1 /* 2 * Copyright 2004, François Revol. 3 * Copyright 2007-2010, Axel Dörfler, axeld@pinc-software.de. 4 * Copyright 2011, Oliver Tappe, zooey@hirschkaefer.de. 5 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. 6 * 7 * Distributed under the terms of the MIT license. 8 */ 9 10 // TODO: this call is currently compiled for the kernel and libroot separately; 11 // they may not always return the same directory right now! 12 13 #ifdef _KERNEL_MODE 14 # include <vfs.h> 15 #else 16 # include <syscalls.h> 17 #endif 18 19 #include <directories.h> 20 #include <FindDirectory.h> 21 #include <fs_info.h> 22 #include <StackOrHeapArray.h> 23 24 #include <errno.h> 25 #include <pwd.h> 26 #include <string.h> 27 #include <sys/stat.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 31 #include <architecture_private.h> 32 #include <errno_private.h> 33 #include <find_directory_private.h> 34 #include <stdlib_private.h> 35 #include <symbol_versioning.h> 36 #include <user_group.h> 37 38 #include <AutoDeleter.h> 39 40 #include "PathBuffer.h" 41 42 43 /* use pwents to find home */ 44 #define USE_PWENTS 45 46 47 /* 48 * If you change any of the directories below, please have a look at 49 * headers/private/libroot/directories.h and adjust that accordingly! 50 */ 51 52 #define SYSTEM "system" 53 #define COMMON "system/data/empty" 54 #define NON_PACKAGED "/non-packaged" 55 56 enum { 57 // obsolete common directories 58 B_COMMON_DIRECTORY = 2000, 59 B_COMMON_SYSTEM_DIRECTORY, 60 B_COMMON_ADDONS_DIRECTORY, 61 B_COMMON_BOOT_DIRECTORY, 62 B_COMMON_FONTS_DIRECTORY, 63 B_COMMON_LIB_DIRECTORY, 64 B_COMMON_SERVERS_DIRECTORY, 65 B_COMMON_BIN_DIRECTORY, 66 _B_COMMON_ETC_DIRECTORY, 67 B_COMMON_DOCUMENTATION_DIRECTORY, 68 _B_COMMON_SETTINGS_DIRECTORY, 69 B_COMMON_DEVELOP_DIRECTORY, 70 _B_COMMON_LOG_DIRECTORY, 71 _B_COMMON_SPOOL_DIRECTORY, 72 _B_COMMON_TEMP_DIRECTORY, 73 _B_COMMON_VAR_DIRECTORY, 74 B_COMMON_TRANSLATORS_DIRECTORY, 75 B_COMMON_MEDIA_NODES_DIRECTORY, 76 B_COMMON_SOUNDS_DIRECTORY, 77 B_COMMON_DATA_DIRECTORY, 78 _B_COMMON_CACHE_DIRECTORY, 79 B_COMMON_PACKAGES_DIRECTORY, 80 B_COMMON_HEADERS_DIRECTORY, 81 }; 82 83 84 /* Haiku system directories */ 85 86 static const char *kSystemDirectories[] = { 87 SYSTEM, // B_SYSTEM_DIRECTORY 88 SYSTEM, // B_BEOS_SYSTEM_DIRECTORY 89 SYSTEM "/add-ons$a", 90 SYSTEM "/boot", 91 SYSTEM "/data/fonts", 92 SYSTEM "/lib$a", 93 SYSTEM "/servers", 94 SYSTEM "/apps", 95 SYSTEM "/bin$a", 96 SYSTEM "/settings/etc", 97 SYSTEM "/documentation", 98 SYSTEM "/preferences", 99 SYSTEM "/add-ons$a/Translators", 100 SYSTEM "/add-ons$a/media", 101 SYSTEM "/data/sounds", 102 SYSTEM "/data", 103 SYSTEM "/develop", 104 SYSTEM "/packages", 105 SYSTEM "/develop/headers$a", 106 SYSTEM "/data/deskbar/menu", 107 }; 108 109 /* Common directories, shared among users */ 110 111 static const char *kCommonDirectories[] = { 112 COMMON, // B_COMMON_DIRECTORY 113 COMMON, // B_COMMON_SYSTEM_DIRECTORY 114 COMMON "/add-ons$a", 115 COMMON "/boot", 116 COMMON "/data/fonts", 117 COMMON "/lib$a", 118 COMMON "/servers", 119 COMMON "/bin$a", 120 SYSTEM "/settings/etc", // B_SYSTEM_ETC_DIRECTORY 121 COMMON "/documentation", 122 SYSTEM "/settings", // B_SYSTEM_SETTINGS_DIRECTORY 123 COMMON "/develop", 124 SYSTEM "/var/log", // B_SYSTEM_LOG_DIRECTORY 125 SYSTEM "/var/spool", // B_SYSTEM_SPOOL_DIRECTORY 126 SYSTEM "/cache/tmp", // B_SYSTEM_TEMP_DIRECTORY 127 SYSTEM "/var", // B_SYSTEM_VAR_DIRECTORY 128 COMMON "/add-ons$a/Translators", 129 COMMON "/add-ons$a/media", 130 COMMON "/data/sounds", 131 COMMON "/data", 132 SYSTEM "/cache", // B_SYSTEM_CACHE_DIRECTORY 133 COMMON "/packages", 134 COMMON "/develop/headers$a", 135 SYSTEM NON_PACKAGED, 136 SYSTEM NON_PACKAGED "/add-ons$a", 137 SYSTEM NON_PACKAGED "/add-ons$a/Translators", 138 SYSTEM NON_PACKAGED "/add-ons$a/media", 139 SYSTEM NON_PACKAGED "/bin$a", 140 SYSTEM NON_PACKAGED "/data", 141 SYSTEM NON_PACKAGED "/data/fonts", 142 SYSTEM NON_PACKAGED "/data/sounds", 143 SYSTEM NON_PACKAGED "/documentation", 144 SYSTEM NON_PACKAGED "/lib$a", 145 SYSTEM NON_PACKAGED "/develop/headers$a", 146 SYSTEM NON_PACKAGED "/develop", 147 }; 148 149 /* User directories */ 150 151 #define HOME "$h" 152 #define CONFIG "/config" 153 154 static const char *kUserDirectories[] = { 155 HOME, // B_USER_DIRECTORY 156 HOME CONFIG, // B_USER_CONFIG_DIRECTORY 157 HOME CONFIG "/add-ons$a", 158 HOME CONFIG "/settings/boot", 159 HOME CONFIG "/data/fonts", 160 HOME CONFIG "/lib$a", 161 HOME CONFIG "/settings", 162 HOME CONFIG "/settings/deskbar/menu", 163 HOME CONFIG "/settings/printers", 164 HOME CONFIG "/add-ons$a/Translators", 165 HOME CONFIG "/add-ons$a/media", 166 HOME CONFIG "/data/sounds", 167 HOME CONFIG "/data", 168 HOME CONFIG "/cache", 169 HOME CONFIG "/packages", 170 HOME CONFIG "/develop/headers$a", 171 HOME CONFIG NON_PACKAGED, 172 HOME CONFIG NON_PACKAGED "/add-ons$a", 173 HOME CONFIG NON_PACKAGED "/add-ons$a/Translators", 174 HOME CONFIG NON_PACKAGED "/add-ons$a/media", 175 HOME CONFIG NON_PACKAGED "/bin$a", 176 HOME CONFIG NON_PACKAGED "/data", 177 HOME CONFIG NON_PACKAGED "/data/fonts", 178 HOME CONFIG NON_PACKAGED "/data/sounds", 179 HOME CONFIG NON_PACKAGED "/documentation", 180 HOME CONFIG NON_PACKAGED "/lib$a", 181 HOME CONFIG NON_PACKAGED "/develop/headers$a", 182 HOME CONFIG NON_PACKAGED "/develop", 183 HOME CONFIG "/develop", 184 HOME CONFIG "/documentation", 185 HOME CONFIG "/servers", 186 HOME CONFIG "/apps", 187 HOME CONFIG "/bin$a", 188 HOME CONFIG "/preferences", 189 HOME CONFIG "/settings/etc", 190 HOME CONFIG "/var/log", 191 HOME CONFIG "/var/spool", 192 HOME CONFIG "/var", 193 }; 194 195 #ifndef _LOADER_MODE 196 /*! make dir and its parents if needed */ 197 static int 198 create_path(const char *path, mode_t mode) 199 { 200 int pathLength; 201 int i = 0; 202 203 if (path == NULL || ((pathLength = strlen(path)) > B_PATH_NAME_LENGTH)) 204 return EINVAL; 205 206 BStackOrHeapArray<char, 128> buffer(pathLength + 1); 207 if (!buffer.IsValid()) 208 return B_NO_MEMORY; 209 210 while (++i < pathLength) { 211 char *slash = strchr(&path[i], '/'); 212 struct stat st; 213 214 if (slash == NULL) 215 i = pathLength; 216 else if (i != slash - path) 217 i = slash - path; 218 else 219 continue; 220 221 strlcpy(buffer, path, i + 1); 222 if (stat(buffer, &st) < 0) { 223 __set_errno(0); 224 if (mkdir(buffer, mode) < 0) 225 return errno; 226 } 227 } 228 229 return 0; 230 } 231 232 233 static size_t 234 get_user_home_path(char* buffer, size_t bufferSize) 235 { 236 const char* home = NULL; 237 #ifndef _KERNEL_MODE 238 #ifdef USE_PWENTS 239 uid_t user = geteuid(); 240 if (user == 0) { 241 // TODO: this is a work-around as the launch_daemon, and the registrar 242 // must not call getpwuid_r(). 243 return strlcpy(buffer, kUserDirectory, bufferSize); 244 } 245 246 struct passwd pwBuffer; 247 char pwStringBuffer[MAX_PASSWD_BUFFER_SIZE]; 248 struct passwd* pw; 249 250 if (getpwuid_r(user, &pwBuffer, pwStringBuffer, 251 sizeof(pwStringBuffer), &pw) == 0 252 && pw != NULL) { 253 home = pw->pw_dir; 254 } 255 #endif // USE_PWENTS 256 if (home == NULL) { 257 /* use env var */ 258 ssize_t result = __getenv_reentrant("HOME", buffer, bufferSize); 259 if (result >= 0) 260 return result; 261 } 262 #endif // !_KERNEL_MODE 263 if (home == NULL) 264 home = kUserDirectory; 265 266 return strlcpy(buffer, home, bufferSize); 267 } 268 269 270 // #pragma mark - 271 272 273 status_t 274 __find_directory(directory_which which, dev_t device, bool createIt, 275 char *returnedPath, int32 _pathLength) 276 { 277 if (_pathLength <= 0) 278 return E2BIG; 279 size_t pathLength = _pathLength; 280 281 status_t err = B_OK; 282 dev_t bootDevice = -1; 283 struct fs_info fsInfo; 284 struct stat st; 285 const char *templatePath = NULL; 286 287 /* as with the R5 version, no on-stack buffer */ 288 char *buffer = (char*)malloc(pathLength); 289 if (buffer == NULL) 290 return B_NO_MEMORY; 291 MemoryDeleter bufferDeleter(buffer); 292 293 memset(buffer, 0, pathLength); 294 295 /* fiddle with non-boot volume for items that need it */ 296 switch (which) { 297 case B_DESKTOP_DIRECTORY: 298 case B_TRASH_DIRECTORY: 299 bootDevice = dev_for_path("/boot"); 300 if (device <= 0) 301 device = bootDevice; 302 if (fs_stat_dev(device, &fsInfo) != B_OK) 303 return ENODEV; 304 if (device != bootDevice) { 305 #ifdef _KERNEL_MODE 306 err = _user_entry_ref_to_path(device, fsInfo.root, /*"."*/ 307 NULL, buffer, pathLength); 308 #else 309 err = _kern_entry_ref_to_path(device, fsInfo.root, /*"."*/ 310 NULL, buffer, pathLength); 311 #endif 312 if (err != B_OK) 313 return err; 314 } else { 315 /* use the user id to find the home folder */ 316 /* done later */ 317 strlcat(buffer, "/boot", pathLength); 318 } 319 break; 320 case B_PACKAGE_LINKS_DIRECTORY: 321 // this is a directory living in rootfs 322 break; 323 default: 324 strlcat(buffer, "/boot", pathLength); 325 break; 326 } 327 328 switch ((int)which) { 329 /* Per volume directories */ 330 case B_DESKTOP_DIRECTORY: 331 if (device == bootDevice || !strcmp(fsInfo.fsh_name, "bfs")) 332 templatePath = "$h/Desktop"; 333 break; 334 case B_TRASH_DIRECTORY: 335 // TODO: eventually put that into the file system API? 336 if (device == bootDevice || !strcmp(fsInfo.fsh_name, "bfs")) 337 templatePath = "trash"; // TODO: add suffix for current user 338 else if (!strcmp(fsInfo.fsh_name, "fat")) 339 templatePath = "RECYCLED/_BEOS_"; 340 break; 341 342 /* Haiku system directories */ 343 case B_SYSTEM_DIRECTORY: 344 case B_BEOS_SYSTEM_DIRECTORY: 345 case B_SYSTEM_ADDONS_DIRECTORY: 346 case B_SYSTEM_BOOT_DIRECTORY: 347 case B_SYSTEM_FONTS_DIRECTORY: 348 case B_SYSTEM_LIB_DIRECTORY: 349 case B_SYSTEM_SERVERS_DIRECTORY: 350 case B_SYSTEM_APPS_DIRECTORY: 351 case B_SYSTEM_BIN_DIRECTORY: 352 case B_BEOS_ETC_DIRECTORY: 353 case B_SYSTEM_DOCUMENTATION_DIRECTORY: 354 case B_SYSTEM_PREFERENCES_DIRECTORY: 355 case B_SYSTEM_TRANSLATORS_DIRECTORY: 356 case B_SYSTEM_MEDIA_NODES_DIRECTORY: 357 case B_SYSTEM_SOUNDS_DIRECTORY: 358 case B_SYSTEM_DATA_DIRECTORY: 359 case B_SYSTEM_DEVELOP_DIRECTORY: 360 case B_SYSTEM_PACKAGES_DIRECTORY: 361 case B_SYSTEM_HEADERS_DIRECTORY: 362 case B_SYSTEM_DESKBAR_DIRECTORY: 363 templatePath = kSystemDirectories[which - B_SYSTEM_DIRECTORY]; 364 break; 365 366 /* Obsolete common directories and writable system directories */ 367 case B_COMMON_DIRECTORY: 368 case B_COMMON_SYSTEM_DIRECTORY: 369 case B_COMMON_ADDONS_DIRECTORY: 370 case B_COMMON_BOOT_DIRECTORY: 371 case B_COMMON_FONTS_DIRECTORY: 372 case B_COMMON_LIB_DIRECTORY: 373 case B_COMMON_SERVERS_DIRECTORY: 374 case B_COMMON_BIN_DIRECTORY: 375 case B_SYSTEM_ETC_DIRECTORY: 376 case B_COMMON_DOCUMENTATION_DIRECTORY: 377 case B_SYSTEM_SETTINGS_DIRECTORY: 378 case B_COMMON_DEVELOP_DIRECTORY: 379 case B_SYSTEM_LOG_DIRECTORY: 380 case B_SYSTEM_SPOOL_DIRECTORY: 381 case B_SYSTEM_TEMP_DIRECTORY: 382 case B_SYSTEM_VAR_DIRECTORY: 383 case B_COMMON_TRANSLATORS_DIRECTORY: 384 case B_COMMON_MEDIA_NODES_DIRECTORY: 385 case B_COMMON_SOUNDS_DIRECTORY: 386 case B_COMMON_DATA_DIRECTORY: 387 case B_SYSTEM_CACHE_DIRECTORY: 388 case B_COMMON_PACKAGES_DIRECTORY: 389 case B_COMMON_HEADERS_DIRECTORY: 390 case B_SYSTEM_NONPACKAGED_DIRECTORY: 391 case B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY: 392 case B_SYSTEM_NONPACKAGED_TRANSLATORS_DIRECTORY: 393 case B_SYSTEM_NONPACKAGED_MEDIA_NODES_DIRECTORY: 394 case B_SYSTEM_NONPACKAGED_BIN_DIRECTORY: 395 case B_SYSTEM_NONPACKAGED_DATA_DIRECTORY: 396 case B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY: 397 case B_SYSTEM_NONPACKAGED_SOUNDS_DIRECTORY: 398 case B_SYSTEM_NONPACKAGED_DOCUMENTATION_DIRECTORY: 399 case B_SYSTEM_NONPACKAGED_LIB_DIRECTORY: 400 case B_SYSTEM_NONPACKAGED_HEADERS_DIRECTORY: 401 case B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY: 402 templatePath = kCommonDirectories[which - B_COMMON_DIRECTORY]; 403 break; 404 405 /* User directories */ 406 case B_USER_DIRECTORY: 407 case B_USER_CONFIG_DIRECTORY: 408 case B_USER_ADDONS_DIRECTORY: 409 case B_USER_BOOT_DIRECTORY: 410 case B_USER_FONTS_DIRECTORY: 411 case B_USER_LIB_DIRECTORY: 412 case B_USER_SETTINGS_DIRECTORY: 413 case B_USER_DESKBAR_DIRECTORY: 414 case B_USER_PRINTERS_DIRECTORY: 415 case B_USER_TRANSLATORS_DIRECTORY: 416 case B_USER_MEDIA_NODES_DIRECTORY: 417 case B_USER_SOUNDS_DIRECTORY: 418 case B_USER_DATA_DIRECTORY: 419 case B_USER_CACHE_DIRECTORY: 420 case B_USER_PACKAGES_DIRECTORY: 421 case B_USER_HEADERS_DIRECTORY: 422 case B_USER_DEVELOP_DIRECTORY: 423 case B_USER_DOCUMENTATION_DIRECTORY: 424 case B_USER_NONPACKAGED_DIRECTORY: 425 case B_USER_NONPACKAGED_ADDONS_DIRECTORY: 426 case B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY: 427 case B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY: 428 case B_USER_NONPACKAGED_BIN_DIRECTORY: 429 case B_USER_NONPACKAGED_DATA_DIRECTORY: 430 case B_USER_NONPACKAGED_FONTS_DIRECTORY: 431 case B_USER_NONPACKAGED_SOUNDS_DIRECTORY: 432 case B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY: 433 case B_USER_NONPACKAGED_LIB_DIRECTORY: 434 case B_USER_NONPACKAGED_HEADERS_DIRECTORY: 435 case B_USER_NONPACKAGED_DEVELOP_DIRECTORY: 436 case B_USER_SERVERS_DIRECTORY: 437 case B_USER_APPS_DIRECTORY: 438 case B_USER_BIN_DIRECTORY: 439 case B_USER_PREFERENCES_DIRECTORY: 440 case B_USER_ETC_DIRECTORY: 441 case B_USER_LOG_DIRECTORY: 442 case B_USER_SPOOL_DIRECTORY: 443 case B_USER_VAR_DIRECTORY: 444 templatePath = kUserDirectories[which - B_USER_DIRECTORY]; 445 break; 446 447 /* Global directories */ 448 case B_APPS_DIRECTORY: 449 case B_UTILITIES_DIRECTORY: 450 templatePath = SYSTEM "/apps"; 451 break; 452 case B_PREFERENCES_DIRECTORY: 453 templatePath = SYSTEM "/preferences"; 454 break; 455 case B_PACKAGE_LINKS_DIRECTORY: 456 templatePath = "packages"; 457 break; 458 459 default: 460 return EINVAL; 461 } 462 463 if (templatePath == NULL) 464 return ENOENT; 465 466 PathBuffer pathBuffer(buffer, pathLength, strlen(buffer)); 467 468 // resolve "$h" placeholder to the user's home directory 469 if (!strncmp(templatePath, "$h", 2)) { 470 if (bootDevice > -1 && device != bootDevice) { 471 pathBuffer.Append("/home"); 472 } else { 473 size_t length = get_user_home_path(buffer, pathLength); 474 if (length >= pathLength) 475 return E2BIG; 476 pathBuffer.SetTo(buffer, pathLength, length); 477 } 478 templatePath += 2; 479 } else if (templatePath[0] != '\0') 480 pathBuffer.Append('/'); 481 482 // resolve "$a" placeholder to the architecture subdirectory, if not 483 // primary 484 if (char* dollar = strchr(templatePath, '$')) { 485 if (dollar[1] == 'a') { 486 pathBuffer.Append(templatePath, dollar - templatePath); 487 #ifndef _KERNEL_MODE 488 const char* architecture = __get_architecture(); 489 if (strcmp(architecture, __get_primary_architecture()) != 0) { 490 pathBuffer.Append('/'); 491 pathBuffer.Append(architecture); 492 } 493 #endif 494 templatePath = dollar + 2; 495 } 496 } 497 498 // append (remainder of) template path 499 pathBuffer.Append(templatePath); 500 501 if (pathBuffer.Length() >= pathLength) 502 return E2BIG; 503 504 if (createIt && stat(buffer, &st) < 0) { 505 err = create_path(buffer, 0755); 506 if (err != B_OK) 507 return err; 508 } 509 510 strlcpy(returnedPath, buffer, pathLength); 511 return B_OK; 512 } 513 514 515 extern "C" status_t 516 __find_directory_alpha4(directory_which which, dev_t device, bool createIt, 517 char *returnedPath, int32 pathLength) 518 { 519 return __find_directory(which, device, createIt, returnedPath, pathLength); 520 } 521 522 523 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__find_directory_alpha4", 524 "find_directory@", "BASE"); 525 526 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__find_directory", "find_directory@@", 527 "1_ALPHA5"); 528 #else // _LOADER_MODE 529 status_t 530 __find_directory(directory_which which, dev_t device, bool createIt, 531 char *returnedPath, int32 _pathLength) 532 { 533 if (_pathLength <= 0) 534 return E2BIG; 535 size_t pathLength = _pathLength; 536 537 const char *templatePath = NULL; 538 539 /* as with the R5 version, no on-stack buffer */ 540 char *buffer = (char*)malloc(pathLength); 541 if (buffer == NULL) 542 return B_NO_MEMORY; 543 MemoryDeleter bufferDeleter(buffer); 544 545 memset(buffer, 0, pathLength); 546 547 strlcat(buffer, "/boot", pathLength); 548 549 switch ((int)which) { 550 /* Haiku system directories */ 551 case B_SYSTEM_DIRECTORY: 552 case B_BEOS_SYSTEM_DIRECTORY: 553 case B_SYSTEM_ADDONS_DIRECTORY: 554 case B_SYSTEM_BOOT_DIRECTORY: 555 case B_SYSTEM_FONTS_DIRECTORY: 556 case B_SYSTEM_LIB_DIRECTORY: 557 case B_SYSTEM_SERVERS_DIRECTORY: 558 case B_SYSTEM_APPS_DIRECTORY: 559 case B_SYSTEM_BIN_DIRECTORY: 560 case B_BEOS_ETC_DIRECTORY: 561 case B_SYSTEM_DOCUMENTATION_DIRECTORY: 562 case B_SYSTEM_PREFERENCES_DIRECTORY: 563 case B_SYSTEM_TRANSLATORS_DIRECTORY: 564 case B_SYSTEM_MEDIA_NODES_DIRECTORY: 565 case B_SYSTEM_SOUNDS_DIRECTORY: 566 case B_SYSTEM_DATA_DIRECTORY: 567 case B_SYSTEM_DEVELOP_DIRECTORY: 568 case B_SYSTEM_PACKAGES_DIRECTORY: 569 case B_SYSTEM_HEADERS_DIRECTORY: 570 case B_SYSTEM_DESKBAR_DIRECTORY: 571 templatePath = kSystemDirectories[which - B_SYSTEM_DIRECTORY]; 572 break; 573 574 /* Obsolete common directories and writable system directories */ 575 case B_COMMON_DIRECTORY: 576 case B_COMMON_SYSTEM_DIRECTORY: 577 case B_COMMON_ADDONS_DIRECTORY: 578 case B_COMMON_BOOT_DIRECTORY: 579 case B_COMMON_FONTS_DIRECTORY: 580 case B_COMMON_LIB_DIRECTORY: 581 case B_COMMON_SERVERS_DIRECTORY: 582 case B_COMMON_BIN_DIRECTORY: 583 case B_SYSTEM_ETC_DIRECTORY: 584 case B_COMMON_DOCUMENTATION_DIRECTORY: 585 case B_SYSTEM_SETTINGS_DIRECTORY: 586 case B_COMMON_DEVELOP_DIRECTORY: 587 case B_SYSTEM_LOG_DIRECTORY: 588 case B_SYSTEM_SPOOL_DIRECTORY: 589 case B_SYSTEM_TEMP_DIRECTORY: 590 case B_SYSTEM_VAR_DIRECTORY: 591 case B_COMMON_TRANSLATORS_DIRECTORY: 592 case B_COMMON_MEDIA_NODES_DIRECTORY: 593 case B_COMMON_SOUNDS_DIRECTORY: 594 case B_COMMON_DATA_DIRECTORY: 595 case B_SYSTEM_CACHE_DIRECTORY: 596 case B_COMMON_PACKAGES_DIRECTORY: 597 case B_COMMON_HEADERS_DIRECTORY: 598 case B_SYSTEM_NONPACKAGED_DIRECTORY: 599 case B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY: 600 case B_SYSTEM_NONPACKAGED_TRANSLATORS_DIRECTORY: 601 case B_SYSTEM_NONPACKAGED_MEDIA_NODES_DIRECTORY: 602 case B_SYSTEM_NONPACKAGED_BIN_DIRECTORY: 603 case B_SYSTEM_NONPACKAGED_DATA_DIRECTORY: 604 case B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY: 605 case B_SYSTEM_NONPACKAGED_SOUNDS_DIRECTORY: 606 case B_SYSTEM_NONPACKAGED_DOCUMENTATION_DIRECTORY: 607 case B_SYSTEM_NONPACKAGED_LIB_DIRECTORY: 608 case B_SYSTEM_NONPACKAGED_HEADERS_DIRECTORY: 609 case B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY: 610 templatePath = kCommonDirectories[which - B_COMMON_DIRECTORY]; 611 break; 612 613 /* User directories */ 614 case B_USER_DIRECTORY: 615 case B_USER_CONFIG_DIRECTORY: 616 case B_USER_ADDONS_DIRECTORY: 617 case B_USER_BOOT_DIRECTORY: 618 case B_USER_FONTS_DIRECTORY: 619 case B_USER_LIB_DIRECTORY: 620 case B_USER_SETTINGS_DIRECTORY: 621 case B_USER_DESKBAR_DIRECTORY: 622 case B_USER_PRINTERS_DIRECTORY: 623 case B_USER_TRANSLATORS_DIRECTORY: 624 case B_USER_MEDIA_NODES_DIRECTORY: 625 case B_USER_SOUNDS_DIRECTORY: 626 case B_USER_DATA_DIRECTORY: 627 case B_USER_CACHE_DIRECTORY: 628 case B_USER_PACKAGES_DIRECTORY: 629 case B_USER_HEADERS_DIRECTORY: 630 case B_USER_DEVELOP_DIRECTORY: 631 case B_USER_DOCUMENTATION_DIRECTORY: 632 case B_USER_NONPACKAGED_DIRECTORY: 633 case B_USER_NONPACKAGED_ADDONS_DIRECTORY: 634 case B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY: 635 case B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY: 636 case B_USER_NONPACKAGED_BIN_DIRECTORY: 637 case B_USER_NONPACKAGED_DATA_DIRECTORY: 638 case B_USER_NONPACKAGED_FONTS_DIRECTORY: 639 case B_USER_NONPACKAGED_SOUNDS_DIRECTORY: 640 case B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY: 641 case B_USER_NONPACKAGED_LIB_DIRECTORY: 642 case B_USER_NONPACKAGED_HEADERS_DIRECTORY: 643 case B_USER_NONPACKAGED_DEVELOP_DIRECTORY: 644 case B_USER_SERVERS_DIRECTORY: 645 case B_USER_APPS_DIRECTORY: 646 case B_USER_BIN_DIRECTORY: 647 case B_USER_PREFERENCES_DIRECTORY: 648 case B_USER_ETC_DIRECTORY: 649 case B_USER_LOG_DIRECTORY: 650 case B_USER_SPOOL_DIRECTORY: 651 case B_USER_VAR_DIRECTORY: 652 templatePath = kUserDirectories[which - B_USER_DIRECTORY]; 653 break; 654 655 default: 656 return EINVAL; 657 } 658 659 if (templatePath == NULL) 660 return ENOENT; 661 662 PathBuffer pathBuffer(buffer, pathLength, strlen(buffer)); 663 664 // resolve "$h" placeholder to the user's home directory 665 if (!strncmp(templatePath, "$h", 2)) { 666 pathBuffer.Append("/home"); 667 templatePath += 2; 668 } else if (templatePath[0] != '\0') 669 pathBuffer.Append('/'); 670 671 // resolve "$a" placeholder to the architecture subdirectory, if not 672 // primary 673 if (char* dollar = strchr(templatePath, '$')) { 674 if (dollar[1] == 'a') { 675 pathBuffer.Append(templatePath, dollar - templatePath); 676 templatePath = dollar + 2; 677 } 678 } 679 680 // append (remainder of) template path 681 pathBuffer.Append(templatePath); 682 683 if (pathBuffer.Length() >= pathLength) 684 return E2BIG; 685 686 strlcpy(returnedPath, buffer, pathLength); 687 return B_OK; 688 } 689 #endif // _LOADER_MODE 690