1%% options 2 3copyright owner = Dirk Krause 4copyright year = 2015-xxxx 5SPDX-License-Identifier: BSD-3-Clause 6 7 8 9%% header 10 11/** @file 12 Make directory hierarchy (create all parent directories for a 13 file or directory and the directory itself if required), 14 the file or directory name is specified as char string. 15*/ 16 17#ifndef DK4CONF_H_INCLUDED 18#if DK4_BUILDING_DKTOOLS4 19#include "dk4conf.h" 20#else 21#include <dktools-4/dk4conf.h> 22#endif 23#endif 24 25#ifndef DK4TYPES_H_INCLUDED 26#if DK4_BUILDING_DKTOOLS4 27#include <libdk4base/dk4types.h> 28#else 29#include <dktools-4/dk4types.h> 30#endif 31#endif 32 33#ifndef DK4ERROR_H_INCLUDED 34#if DK4_BUILDING_DKTOOLS4 35#include <libdk4base/dk4error.h> 36#else 37#include <dktools-4/dk4error.h> 38#endif 39#endif 40 41#ifdef __cplusplus 42extern "C" { 43#endif 44 45/** Find position of first separator for real directory. 46 47 This function is not intended for use in application programs, 48 it is exported only for use from the dk4appmkdh module. 49 50 The function either returns a value or sets the back variable 51 to 1 or reports an error. 52 @param fn File name. 53 @param bptr Pointer to the back variable. 54 @param lc Flag: Last component in fn is directory too. 55 @param erp Error report, may be NULL. 56 @return First separator after a real directory on success if 57 found, NULL otherwise. 58*/ 59char * 60dk4mkdir_hierarchy_c8_first_sep(char *fn, int *bptr, int lc, dk4_er_t *erp); 61 62/** Check whether directory exists or attempt to create directory. 63 @param fn File name. 64 @param ro Flag: Read only (test directory presence), 65 do not attempt to create the directory. 66 @param erp Error report, may be NULL. 67 @return 1 if directory is available now, 0 otherwise. 68 69 Error codes: 70 - DK4_E_INVALID_ARGUMENTS<br> 71 if fn is NULL, 72 - DK4_E_NOT_FOUND<br> 73 if a server/share combination is not present on Windows, 74 - DK4_E_NON_DIR<br> 75 if any component in the path is not a directory, 76 - DK4_E_MKDIR_FAILED<br> 77 with errno value in iDetails1 if the mkdir() function failed on a 78 non-Windows system. 79 - DK4_E_CREATE_DIR_FAILED<br> 80 with GetLastError() result in lDetails1 if the CreateDirectory() 81 function failed on a Windows system. 82*/ 83int 84dk4mkdir_hierarchy_c8_one(const char *fn, int ro, dk4_er_t *erp); 85 86/** Create directory structure. 87 @param fn File name. 88 @param lc Flag: Last component in fn is directory too. 89 @param erp Error report, may be NULL. 90 @return 1 on success, 0 on error. 91 92 Error codes: 93 - DK4_E_INVALID_ARGUMENTS<br> 94 if fn is NULL, 95 - DK4_E_BUFFER_TOO_SMALL<br> 96 if fn is too long, 97 - DK4_E_MATH_OVERFLOW<br> 98 if a mathematical overflow occured in size allocation, 99 - DK4_E_NOT_FOUND<br> 100 if a server/share combination is not present on Windows, 101 - DK4_E_NON_DIR<br> 102 if one of the components in fn is not a directory, 103 - DK4_E_MKDIR_FAILED<br> 104 with errno in idetails if the function fails to create the directory 105 or a parent directory, 106 - DK4_E_CREATE_DIR_FAILED<br> 107 with GetLastError() result in lDetails1 if the CreateDirectory() 108 function failed on a Windows system. 109*/ 110int 111dk4mkdir_hierarchy_c8(const char *fn, int lc, dk4_er_t *erp); 112 113 114#if DK4_HAVE_UID_T && DK4_HAVE_GID_T && DK4_HAVE_MODE_T && (!DK4_ON_WINDOWS) 115 116/** Create directory structure for a given POSIX user and group. 117 @param fn File name. 118 @param lc Flag: Last component in fn is directory too. 119 @param uid User ID for new directories. 120 @param gid Group ID for new directories. 121 @param mode Permissions to new directories. 122 @param erp Error report, may be NULL. 123 @return 1 on success, 0 on error. 124 125 Error codes: 126 - DK4_E_INVALID_ARGUMENTS<br> 127 if fn is NULL, 128 - DK4_E_BUFFER_TOO_SMALL<br> 129 if fn is too long, 130 - DK4_E_MATH_OVERFLOW<br> 131 if a mathematical overflow occured in size allocation, 132 - DK4_E_NOT_FOUND<br> 133 if a server/share combination is not present on Windows, 134 - DK4_E_NON_DIR<br> 135 if one of the components in fn is not a directory, 136 - DK4_E_MKDIR_FAILED<br> 137 with errno in idetails if the function fails to create the directory 138 or a parent directory, 139 - DK4_E_CHOWN_FAILED<br> 140 with errno value in iDetails1 if the chown() function failed on a 141 non-Windows system, 142 - DK4_E_CHMOD_FAILED<br> 143 with errno value in iDetails1 if the chmod() function failed on a 144 non-Windows system, 145 - DK4_E_CREATE_DIR_FAILED<br> 146 with GetLastError() result in lDetails1 if the CreateDirectory() 147 function failed on a Windows system. 148*/ 149int 150dk4mkdir_hierarchy_ugm_c8( 151 const char *fn, 152 int lc, 153 uid_t uid, 154 gid_t gid, 155 mode_t mode, 156 dk4_er_t *erp 157); 158 159#endif 160 161#ifdef __cplusplus 162} 163#endif 164 165 166 167%% module 168 169#include "dk4conf.h" 170#include <libdk4base/dk4types.h> 171 172#if DK4_ON_WINDOWS 173#ifndef WINDOWS_H_INCLUDED 174#include <windows.h> 175#define WINDOWS_H_INCLUDED 1 176#endif 177#endif 178 179#include <libdk4c/dk4mkdh8.h> 180 181#if DK4_HAVE_SYS_STAT_H 182#ifndef SYS_STAT_H_INCLUDED 183#include <sys/stat.h> 184#define SYS_STAT_H_INCLUDED 1 185#endif 186#endif 187 188#if DK4_HAVE_SYS_TYPES_H 189#ifndef SYS_TYPES_H_INCLUDED 190#include <sys/types.h> 191#define SYS_TYPES_H_INCLUDED 1 192#endif 193#endif 194 195#if DK4_HAVE_DIRECT_H 196#ifndef DIRECT_H_INCLUDED 197#include <direct.h> 198#define DIRECT_H_INCLUDED 1 199#endif 200#endif 201 202#if DK4_HAVE_STDLIB_H 203#ifndef STDLIB_H_INCLUDED 204#include <stdlib.h> 205#define STDLIB_H_INCLUDED 1 206#endif 207#endif 208 209#if DK4_HAVE_UNISTD_H 210#ifndef UNISTD_H_INCLUDED 211#include <unistd.h> 212#define UNISTD_H_INCLUDED 1 213#endif 214#endif 215 216#if DK4_HAVE_ERRNO_H 217#ifndef ERRNO_H_INCLUDED 218#include <errno.h> 219#define ERRNO_H_INCLUDED 1 220#endif 221#endif 222 223#ifndef DK4MEM_H_INCLUDED 224#include <libdk4base/dk4mem.h> 225#endif 226 227#ifndef DK4MPL_H_INCLUDED 228#include <libdk4base/dk4mpl.h> 229#endif 230 231#ifndef DK4STR8_H_INCLUDED 232#include <libdk4base/dk4str8.h> 233#endif 234 235#ifndef DK4PATH8_H_INCLUDED 236#include <libdk4c/dk4path8.h> 237#endif 238 239#ifndef DK4STAT8_H_INCLUDED 240#include <libdk4c/dk4stat8.h> 241#endif 242 243#ifndef DK4STAT_H_INCLUDED 244#include <libdk4c/dk4stat.h> 245#endif 246 247#if DK4_HAVE_ASSERT_H 248#ifndef ASSERT_H_INCLUDED 249#include <assert.h> 250#define ASSERT_H_INCLUDED 1 251#endif 252#endif 253 254 255$!trace-include 256 257 258 259#if DK4_ON_WINDOWS 260/* +++ Windows */ 261 262 263 264/** Check whether c is a character. 265 @param c Byte to check. 266 @return 1 for characters, 0 for other bytes. 267*/ 268static 269int 270dk4mkdir_hierarchy_c8_is_char(char c) 271{ 272 int back = 0; 273 if (('a' <= c) && ('z' >= c)) { 274 back = 1; 275 } else { 276 if (('A' <= c) && ('Z' >= c)) { 277 back = 1; 278 } 279 } 280 return back; 281} 282 283 284 285int 286dk4mkdir_hierarchy_c8_one(const char *fn, int ro, dk4_er_t *erp) 287{ 288 BY_HANDLE_FILE_INFORMATION bhfi; 289 WIN32_FIND_DATAA ffdata; 290 HANDLE ha; 291 DWORD dwattr; 292 int found; 293 int i; 294 int back = 0; 295 $? "+ dk4mkdir_hierarchy_c8_one \"%!8s\"", fn 296#if DK4_USE_ASSERT 297 assert(NULL != fn); 298#endif 299 if (NULL == fn) { 300 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 301 goto finished; 302 } 303#if 1 304 dwattr = GetFileAttributesA(fn); 305 if (INVALID_FILE_ATTRIBUTES == dwattr) { 306 ha = FindFirstFileA(fn, &ffdata); 307 if (INVALID_HANDLE_VALUE != ha) { 308 dwattr = ffdata.dwFileAttributes; 309 FindClose(ha); 310 } 311 } 312 if (INVALID_FILE_ATTRIBUTES != dwattr) { 313 if (0 != (FILE_ATTRIBUTE_DIRECTORY & dwattr)) { 314 back = 1; 315 } else { 316 if (0 != (FILE_ATTRIBUTE_REPARSE_POINT & dwattr)) { 317 found = 0; 318 for (i = 0; ((3 > i) && (0 == back) && (0 == found)); i++) { 319 ha = CreateFileA( 320 fn, 321 ( 322 (0 == i) 323 ? (0) 324 : ((1 == i) ? (FILE_READ_ATTRIBUTES) : (GENERIC_READ)) 325 ), 326 (FILE_SHARE_READ | FILE_SHARE_WRITE), 327 NULL, 328 OPEN_EXISTING, 329 (dwattr | FILE_FLAG_BACKUP_SEMANTICS), 330 NULL 331 ); 332 if (INVALID_HANDLE_VALUE != ha) { 333 if (GetFileInformationByHandle(ha, &bhfi)) { 334 found = 1; 335 if (0 != (FILE_ATTRIBUTE_DIRECTORY & (bhfi.dwFileAttributes))) { 336 back = 1; 337 } 338 } 339 CloseHandle(ha); 340 } 341 } 342 } 343 if (0 == back) { 344 dk4error_set_simple_error_code(erp, DK4_E_NON_DIR); 345 } 346 } 347 } else { 348 if (0 != ro) { 349 dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND); 350 } else { 351#if DK4_WIN_AVOID_CRT || DK4_WIN_DENY_CRT 352 if (CreateDirectoryA(fn, NULL)) { 353 back = 1; 354 } else { 355 dk4error_set_ldetails( 356 erp, DK4_E_CREATE_DIR_FAILED , 357 (long)((unsigned long)GetLastError()) 358 ); 359 } 360#else 361 if (CreateDirectoryA(fn, NULL)) { 362 back = 1; 363 } else { 364 errno = 0; 365 if (0 == _mkdir(fn)) { 366 back = 1; 367 } else { 368 dk4error_set_idetails(erp, DK4_E_MKDIR_FAILED, errno); 369 } 370 } 371#endif 372 } 373 } 374#else 375 back = 1; 376#endif 377 $? "- dk4mkdir_hierarchy_c8_one %d", back 378 finished: 379 return back; 380} 381 382 383 384char * 385dk4mkdir_hierarchy_c8_first_sep(char *fn, int *bptr, int lc, dk4_er_t *erp) 386{ 387 char *pc = NULL; 388 int back = 0; 389 char sc; 390 391#if DK4_USE_ASSERT 392 assert(NULL != fn); 393#endif 394 if (NULL == fn) { 395 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 396 goto finished; 397 } 398 399 if ('\\' == *fn) { /* leading bs */ 400 if ('\\' == fn[1]) { /* server and share */ 401 pc = dk4str8_chr(&(fn[2]), '\\'); 402 if (NULL != pc) { /* Share name */ 403 pc = dk4str8_chr(&(pc[1]), '\\'); 404 if (NULL != pc) { /* First dir */ 405 *pc = '\0'; 406 back = dk4mkdir_hierarchy_c8_one(fn, 1, erp); 407 *pc = '\\'; 408 if (0 != back) { 409 back = 0; 410 pc = dk4str8_chr(&(pc[1]), '\\'); 411 if (NULL == pc) { 412 if (0 != lc) { 413 back = dk4mkdir_hierarchy_c8_one(fn, 0, erp); 414 } else { 415 back = 1; 416 } 417 } 418 } else { 419 pc = dk4str8_chr(&(pc[1]), '\\'); 420 if (NULL == pc) { 421 if (0 != lc) { 422 back = dk4mkdir_hierarchy_c8_one(fn, 0, erp); 423 } 424 } 425 } 426 } else { /* Share name but no dir */ 427 if (0 != lc) { 428 back = dk4mkdir_hierarchy_c8_one(fn, 1, erp); 429 } else { 430 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 431 } 432 } 433 } else { 434 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 435 } 436 } else { /* abs path, no drive */ 437 pc = dk4str8_chr(&(fn[1]), '\\'); 438 if (NULL == pc) { 439 if (0 != lc) { 440 back = dk4mkdir_hierarchy_c8_one(fn, 0, erp); 441 } else { 442 back = 1; 443 } 444 } 445 } 446 } else { /* no leading bs */ 447 if (0 != dk4mkdir_hierarchy_c8_is_char(*fn)) { /* leading char */ 448 if (':' == fn[1]) { /* drive */ 449 if ('\\' == fn[2]) { /* drive, abs path */ 450 sc = fn[3]; 451 fn[3] = '\0'; 452 back = dk4mkdir_hierarchy_c8_one(fn, 1, erp); 453 fn[3] = sc; 454 if (0 != back) { 455 back = 0; 456 pc = dk4str8_chr(&(fn[3]), '\\'); 457 if (NULL == pc) { 458 if (0 != lc) { 459 back = dk4mkdir_hierarchy_c8_one(fn, 0, erp); 460 } else { 461 back = 1; 462 } 463 } 464 } 465 } else { /* drive, rel path */ 466 sc = fn[2]; 467 fn[2] = '\0'; 468 back = dk4mkdir_hierarchy_c8_one(fn, 1, erp); 469 fn[2] = sc; 470 if (0 != back) { 471 back = 0; 472 pc = dk4str8_chr(&(fn[3]), '\\'); 473 if (NULL == pc) { 474 if (0 != lc) { 475 back = dk4mkdir_hierarchy_c8_one(fn, 0, erp); 476 } else { 477 back = 1; 478 } 479 } 480 } 481 } 482 } else { /* no drive */ 483 pc = dk4str8_chr(fn, '\\'); 484 if (NULL == pc) { 485 if (0 != lc) { 486 back = dk4mkdir_hierarchy_c8_one(fn, 0, erp); 487 } else { 488 back = 1; 489 } 490 } 491 } 492 } else { /* no leading char */ 493 pc = dk4str8_chr(fn, '\\'); 494 if (NULL == pc) { 495 if (0 != lc) { 496 back = dk4mkdir_hierarchy_c8_one(fn, 0, erp); 497 } else { 498 back = 1; 499 } 500 } 501 } 502 } 503 504 finished: 505 if (NULL != bptr) { *bptr = back; } 506 return pc; 507} 508 509 510 511/* --- Windows */ 512#else 513/* +++ non-Windows */ 514 515 516 517int 518dk4mkdir_hierarchy_c8_one(const char *fn, int ro, dk4_er_t *erp) 519{ 520 dk4_stat_t stb; 521 int back = 0; 522 $? "+ dk4mkdir_hierarchy_c8_one \"%!8s\"", fn 523#if DK4_USE_ASSERT 524 assert(NULL != fn); 525#endif 526 if (NULL == fn) { 527 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 528 goto finished; 529 } 530#if 1 531 if (0 != dk4stat_c8(&stb, fn, NULL)) { 532 back = dk4stat_is_directory(&stb, erp); 533 if (0 == back) { 534 dk4error_set_simple_error_code(erp, DK4_E_NON_DIR); 535 } 536 } else { 537 if (0 != ro) { 538 dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND); 539 } else { 540 errno = 0; 541 if (0 == mkdir(fn, 0700)) { 542 back = 1; 543 } else { 544 dk4error_set_idetails(erp, DK4_E_MKDIR_FAILED, errno); 545 } 546 } 547 } 548#else 549 back = 1; 550#endif 551 $? "- dk4mkdir_hierarchy_c8_one %d", back 552 finished: 553 return back; 554} 555 556 557 558char * 559dk4mkdir_hierarchy_c8_first_sep(char *fn, int *bptr, int lc, dk4_er_t *erp) 560{ 561 char *pc = NULL; 562 int back = 0; 563 564#if DK4_USE_ASSERT 565 assert(NULL != fn); 566#endif 567 if (NULL == fn) { 568 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 569 goto finished; 570 } 571 572 if ('/' == *fn) { 573 pc = dk4str8_chr(&(fn[1]), '/'); 574 } else { 575 pc = dk4str8_chr(fn, '/'); 576 } 577 if (NULL == pc) { 578 if (0 != lc) { 579 back = dk4mkdir_hierarchy_c8_one(fn, 0, erp); 580 } else { 581 back = 1; 582 } 583 } 584 585 finished: 586 if (NULL != bptr) { *bptr = back; } 587 return pc; 588} 589 590 591 592/* --- non-Windows */ 593#endif 594 595 596 597/** Create directory structure using an editable copy of the path. 598 @param fn File name. 599 @param lc Flag: Last component in fn is directory too. 600 @param erp Error report, may be NULL. 601 @return 1 on success, 0 on error. 602 603 Error codes: 604 - DK4_E_INVALID_ARGUMENTS<br> 605 if fn is NULL, 606 - DK4_E_BUFFER_TOO_SMALL<br> 607 if fn is too long, 608 - DK4_E_MATH_OVERFLOW<br> 609 if a mathematical overflow occured in size allocation, 610 - DK4_E_NOT_FOUND<br> 611 if a server/share combination is not present on Windows, 612 - DK4_E_NON_DIR<br> 613 if one of the components in fn is not a directory, 614 - DK4_E_MKDIR_FAILED<br> 615 with errno in idetails if the function fails to create the directory 616 or a parent directory, 617 - DK4_E_CREATE_DIR_FAILED<br> 618 with GetLastError() result in lDetails1 if the CreateDirectory() 619 function failed on a Windows system. 620*/ 621static 622int 623dk4mkdir_hierarchy_c8_on_copy(char *fn, int lc, dk4_er_t *erp) 624{ 625 char *pc; 626 int back = 0; 627 628 $? "+ dk4mkdir_hierarchy_c8_on_copy \"%!8s\"", fn 629#if DK4_USE_ASSERT 630 assert(NULL != fn); 631#endif 632 633 /* Correct file name */ 634 dk4path8_correct_sep(fn); 635 636 /* Find first real separator */ 637 pc = dk4mkdir_hierarchy_c8_first_sep(fn, &back, lc, erp); 638 639 /* Process directories */ 640 if (NULL != pc) { 641 back = 1; 642 while (NULL != pc) { 643 *pc = '\0'; 644 if (0 < dk4str8_len(fn)) { 645 if (0 == dk4mkdir_hierarchy_c8_one(fn, 0, erp)) { 646 back = 0; 647 } 648 } 649#if DK4_HAVE_BACKSLASH_AS_SEP 650 *pc = '\\'; 651 pc = dk4str8_chr(&(pc[1]), '\\'); 652#else 653 *pc = '/'; 654 pc = dk4str8_chr(&(pc[1]), '/'); 655#endif 656 } 657 if (0 != lc) { 658 if (0 == dk4mkdir_hierarchy_c8_one(fn, 0, erp)) { 659 back = 0; 660 } 661 } 662 } 663 $? "- dk4mkdir_hierarchy_c8_on_copy %d", back 664 return back; 665} 666 667 668 669/** Create directory structure using a local copy of the path. 670 @param fn File name. 671 @param lc Flag: Last component in fn is directory too. 672 @param erp Error report, may be NULL. 673 @return 1 on success, 0 on error. 674 675 Error codes: 676 - DK4_E_INVALID_ARGUMENTS<br> 677 if fn is NULL, 678 - DK4_E_BUFFER_TOO_SMALL<br> 679 if fn is too long, 680 - DK4_E_MATH_OVERFLOW<br> 681 if a mathematical overflow occured in size allocation, 682 - DK4_E_NOT_FOUND<br> 683 if a server/share combination is not present on Windows, 684 - DK4_E_NON_DIR<br> 685 if one of the components in fn is not a directory, 686 - DK4_E_MKDIR_FAILED<br> 687 with errno in idetails if the function fails to create the directory 688 or a parent directory, 689 - DK4_E_CREATE_DIR_FAILED<br> 690 with GetLastError() result in lDetails1 if the CreateDirectory() 691 function failed on a Windows system. 692*/ 693static 694int 695dk4mkdir_hierarchy_c8_local(const char *fn, int lc, dk4_er_t *erp) 696{ 697 char mycp[DK4_MAX_PATH]; 698 int back = 0; 699 $? "+ dk4mkdir_hierarchy_c8_local \"%!8s\"", fn 700#if DK4_USE_ASSERT 701 assert(NULL != fn); 702#endif 703 if (0 != dk4str8_cpy_s(mycp, sizeof(mycp), fn, erp)) { 704 back = dk4mkdir_hierarchy_c8_on_copy(mycp, lc, erp); 705 } $? "- dk4mkdir_hierarchy_c8_local %d", back 706 return back; 707} 708 709 710 711int 712dk4mkdir_hierarchy_c8(const char *fn, int lc, dk4_er_t *erp) 713{ 714 char *mycp; 715 size_t sz; 716 int back = 0; 717 $? "+ dk4mkdir_hierarchy_c8 \"%!8s\"", TR_8STR(fn) 718#if DK4_USE_ASSERT 719 assert(NULL != fn); 720#endif 721 if (NULL != fn) { 722 sz = dk4str8_len(fn); 723 if (DK4_MAX_PATH > sz) { 724 back = dk4mkdir_hierarchy_c8_local(fn, lc, erp); 725 } else { 726 mycp = dk4str8_dup(fn, erp); 727 if (NULL != mycp) { 728 back = dk4mkdir_hierarchy_c8_on_copy(mycp, lc, erp); 729 dk4mem_free(mycp); 730 } 731 } 732 } else { 733 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 734 } $? "- dk4mkdir_hierarchy_c8 %d", back 735 return back; 736} 737 738 739 740#if DK4_HAVE_UID_T && DK4_HAVE_GID_T && DK4_HAVE_MODE_T && (!DK4_ON_WINDOWS) 741 742 743 744/** Check whether directory exists or attempt to create directory. 745 @param fn File name. 746 @param ro Flag: Read only (test directory presence), 747 do not attempt to create the directory. 748 @param uid User ID for new directories. 749 @param gid Group ID for new directories. 750 @param mode Mode for new directories. 751 @param erp Error report, may be NULL. 752 @return 1 if directory is available now, 0 otherwise. 753 754 Error codes: 755 - DK4_E_INVALID_ARGUMENTS<br> 756 if fn is NULL, 757 - DK4_E_NOT_FOUND<br> 758 if a server/share combination is not present on Windows, 759 - DK4_E_NON_DIR<br> 760 if any component in the path is not a directory, 761 - DK4_E_MKDIR_FAILED<br> 762 with errno value in iDetails1 if the mkdir() function failed on a 763 non-Windows system, 764 - DK4_E_CHOWN_FAILED<br> 765 with errno value in iDetails1 if the chown() function failed on a 766 non-Windows system, 767 - DK4_E_CHMOD_FAILED<br> 768 with errno value in iDetails1 if the chmod() function failed on a 769 non-Windows system, 770 - DK4_E_CREATE_DIR_FAILED<br> 771 with GetLastError() result in lDetails1 if the CreateDirectory() 772 function failed on a Windows system. 773*/ 774static 775int 776dk4mkdir_hierarchy_ugm_c8_one( 777 const char *fn, 778 int ro, 779 uid_t uid, 780 gid_t gid, 781 mode_t mode, 782 dk4_er_t *erp 783) 784{ 785 dk4_stat_t stb; 786 int back = 0; 787 $? "+ dk4mkdir_hierarchy_c8_one \"%!8s\"", fn 788#if DK4_USE_ASSERT 789 assert(NULL != fn); 790#endif 791 if (NULL == fn) { 792 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 793 goto finished; 794 } 795#if 1 796 if (0 != dk4stat_c8(&stb, fn, NULL)) { 797 back = dk4stat_is_directory(&stb, erp); 798 if (0 == back) { 799 dk4error_set_simple_error_code(erp, DK4_E_NON_DIR); 800 } 801 } else { 802 if (0 != ro) { 803 dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND); 804 } else { 805 errno = 0; 806 if (0 == mkdir(fn, mode)) { 807 errno = 0; 808 if (0 == chown(fn, uid, gid)) { 809 errno = 0; 810 if (0 == chmod(fn, mode)) { 811 back = 1; 812 } else { 813 dk4error_set_idetails(erp, DK4_E_CHMOD_FAILED, errno); 814 } 815 } else { 816 dk4error_set_idetails(erp, DK4_E_CHOWN_FAILED, errno); 817 } 818 } else { 819 dk4error_set_idetails(erp, DK4_E_MKDIR_FAILED, errno); 820 } 821 } 822 } 823#else 824 back = 1; 825#endif 826 $? "- dk4mkdir_hierarchy_c8_one %d", back 827 finished: 828 return back; 829} 830 831 832 833/** Create directory structure using an editable copy of the path. 834 @param fn File name. 835 @param lc Flag: Last component in fn is directory too. 836 @param uid User ID for new directories. 837 @param gid Group ID for new directories. 838 @param mode Mode for new directories. 839 @param erp Error report, may be NULL. 840 @return 1 on success, 0 on error. 841 842 Error codes: 843 - DK4_E_INVALID_ARGUMENTS<br> 844 if fn is NULL, 845 - DK4_E_BUFFER_TOO_SMALL<br> 846 if fn is too long, 847 - DK4_E_MATH_OVERFLOW<br> 848 if a mathematical overflow occured in size allocation, 849 - DK4_E_NOT_FOUND<br> 850 if a server/share combination is not present on Windows, 851 - DK4_E_NON_DIR<br> 852 if one of the components in fn is not a directory, 853 - DK4_E_MKDIR_FAILED<br> 854 with errno in idetails if the function fails to create the directory 855 or a parent directory, 856 - DK4_E_CHOWN_FAILED<br> 857 with errno value in iDetails1 if the chown() function failed on a 858 non-Windows system, 859 - DK4_E_CHMOD_FAILED<br> 860 with errno value in iDetails1 if the chmod() function failed on a 861 non-Windows system, 862 - DK4_E_CREATE_DIR_FAILED<br> 863 with GetLastError() result in lDetails1 if the CreateDirectory() 864 function failed on a Windows system. 865*/ 866static 867int 868dk4mkdir_hierarchy_ugm_c8_on_copy( 869 char *fn, 870 int lc, 871 uid_t uid, 872 gid_t gid, 873 mode_t mode, 874 dk4_er_t *erp 875) 876{ 877 char *pc; 878 int back = 0; 879 880 $? "+ dk4mkdir_hierarchy_c8_on_copy \"%!8s\"", fn 881 882#if DK4_USE_ASSERT 883 assert(NULL != fn); 884#endif 885 886 /* Correct file name */ 887 dk4path8_correct_sep(fn); 888 889 /* Find first real separator */ 890 pc = dk4mkdir_hierarchy_c8_first_sep(fn, &back, lc, erp); 891 892 /* Process directories */ 893 if (NULL != pc) { 894 back = 1; 895 while (NULL != pc) { 896 *pc = '\0'; 897 if (0 < dk4str8_len(fn)) { 898 if (0 == dk4mkdir_hierarchy_ugm_c8_one(fn, 0, uid, gid, mode, erp)) { 899 back = 0; 900 } 901 } 902#if DK4_HAVE_BACKSLASH_AS_SEP 903 *pc = '\\'; 904 pc = dk4str8_chr(&(pc[1]), '\\'); 905#else 906 *pc = '/'; 907 pc = dk4str8_chr(&(pc[1]), '/'); 908#endif 909 } 910 if (0 != lc) { 911 if (0 == dk4mkdir_hierarchy_ugm_c8_one(fn, 0, uid, gid, mode, erp)) { 912 back = 0; 913 } 914 } 915 } 916 $? "- dk4mkdir_hierarchy_c8_on_copy %d", back 917 return back; 918} 919 920 921 922/** Create directory structure using a local copy of the path. 923 @param fn File name. 924 @param lc Flag: Last component in fn is directory too. 925 @param uid User ID for new directories. 926 @param gid Group ID for new directories. 927 @param mode Mode for new directories. 928 @param erp Error report, may be NULL. 929 @return 1 on success, 0 on error. 930 931 Error codes: 932 - DK4_E_INVALID_ARGUMENTS<br> 933 if fn is NULL, 934 - DK4_E_BUFFER_TOO_SMALL<br> 935 if fn is too long, 936 - DK4_E_MATH_OVERFLOW<br> 937 if a mathematical overflow occured in size allocation, 938 - DK4_E_NOT_FOUND<br> 939 if a server/share combination is not present on Windows, 940 - DK4_E_NON_DIR<br> 941 if one of the components in fn is not a directory, 942 - DK4_E_MKDIR_FAILED<br> 943 with errno in idetails if the function fails to create the directory 944 or a parent directory, 945 - DK4_E_CHOWN_FAILED<br> 946 with errno value in iDetails1 if the chown() function failed on a 947 non-Windows system, 948 - DK4_E_CHMOD_FAILED<br> 949 with errno value in iDetails1 if the chmod() function failed on a 950 non-Windows system, 951 - DK4_E_CREATE_DIR_FAILED<br> 952 with GetLastError() result in lDetails1 if the CreateDirectory() 953 function failed on a Windows system. 954*/ 955static 956int 957dk4mkdir_hierarchy_ugm_c8_local( 958 const char *fn, 959 int lc, 960 uid_t uid, 961 gid_t gid, 962 mode_t mode, 963 dk4_er_t *erp 964) 965{ 966 char mycp[DK4_MAX_PATH]; 967 int back = 0; 968 $? "+ dk4mkdir_hierarchy_c8_local \"%!8s\"", fn 969#if DK4_USE_ASSERT 970 assert(NULL != fn); 971#endif 972 if (0 != dk4str8_cpy_s(mycp, sizeof(mycp), fn, erp)) { 973 back = dk4mkdir_hierarchy_ugm_c8_on_copy(mycp, lc, uid, gid, mode, erp); 974 } $? "- dk4mkdir_hierarchy_c8_local %d", back 975 return back; 976} 977 978 979 980int 981dk4mkdir_hierarchy_ugm_c8( 982 const char *fn, 983 int lc, 984 uid_t uid, 985 gid_t gid, 986 mode_t mode, 987 dk4_er_t *erp 988) 989{ 990 char *mycp; 991 size_t sz; 992 int back = 0; 993 $? "+ dk4mkdir_hierarchy_c8 \"%!8s\"", TR_8STR(fn) 994#if DK4_USE_ASSERT 995 assert(NULL != fn); 996#endif 997 if (NULL != fn) { 998 sz = dk4str8_len(fn); 999 if (DK4_MAX_PATH > sz) { 1000 back = dk4mkdir_hierarchy_ugm_c8_local(fn, lc, uid, gid, mode, erp); 1001 } else { 1002 mycp = dk4str8_dup(fn, erp); 1003 if (NULL != mycp) { 1004 back = dk4mkdir_hierarchy_ugm_c8_on_copy(mycp, lc, uid, gid, mode, erp); 1005 dk4mem_free(mycp); 1006 } 1007 } 1008 } else { 1009 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); 1010 } $? "- dk4mkdir_hierarchy_c8 %d", back 1011 return back; 1012} 1013 1014 1015 1016#endif 1017