1 /* 2 * Copyright 2015, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <find_directory_private.h> 9 10 #include <errno.h> 11 #include <stdio.h> 12 #include <string.h> 13 #include <sys/stat.h> 14 15 #include <algorithm> 16 17 #include <fs_attr.h> 18 19 #include <architecture_private.h> 20 #include <AutoDeleter.h> 21 #include <directories.h> 22 #include <syscalls.h> 23 24 #include "PathBuffer.h" 25 26 27 static size_t kHomeInstallationLocationIndex = 1; 28 29 static const path_base_directory kArchitectureSpecificBaseDirectories[] = { 30 B_FIND_PATH_ADD_ONS_DIRECTORY, 31 B_FIND_PATH_BIN_DIRECTORY, 32 B_FIND_PATH_DEVELOP_LIB_DIRECTORY, 33 B_FIND_PATH_HEADERS_DIRECTORY, 34 }; 35 36 static size_t kArchitectureSpecificBaseDirectoryCount = 37 sizeof(kArchitectureSpecificBaseDirectories) 38 / sizeof(kArchitectureSpecificBaseDirectories[0]); 39 40 41 namespace { 42 43 44 struct InstallationLocations { 45 public: 46 static const size_t kCount = 4; 47 48 public: 49 InstallationLocations() 50 : 51 fReferenceCount(1) 52 { 53 fLocations[0] = kUserNonpackagedDirectory; 54 fLocations[1] = kUserConfigDirectory; 55 fLocations[2] = kSystemNonpackagedDirectory; 56 fLocations[3] = kSystemDirectory; 57 } 58 59 InstallationLocations(const char* home) 60 : 61 fReferenceCount(1) 62 { 63 static const char* const kNonPackagedSuffix = "/non-packaged"; 64 char* homeNonPackaged 65 = (char*)malloc(strlen(home) + strlen(kNonPackagedSuffix) + 1); 66 fLocations[0] = homeNonPackaged; 67 if (homeNonPackaged != NULL) { 68 strcpy(homeNonPackaged, home); 69 strcat(homeNonPackaged, kNonPackagedSuffix); 70 } 71 72 fLocations[1] = strdup(home); 73 74 fLocations[2] = kSystemNonpackagedDirectory; 75 fLocations[3] = kSystemDirectory; 76 } 77 78 ~InstallationLocations() 79 { 80 free(const_cast<char*>(fLocations[0])); 81 free(const_cast<char*>(fLocations[1])); 82 } 83 84 bool IsValid() const 85 { 86 return fLocations[0] != NULL && fLocations[1] != NULL; 87 } 88 89 bool IsUserIndex(size_t index) const 90 { 91 return index==0 || index==1; 92 } 93 94 bool IsSystemIndex(size_t index) const 95 { 96 return index==2 || index==3; 97 } 98 99 static InstallationLocations* Default() 100 { 101 static char sBuffer[sizeof(InstallationLocations)]; 102 static InstallationLocations* sDefaultLocations 103 = new(&sBuffer) InstallationLocations; 104 return sDefaultLocations; 105 } 106 107 static InstallationLocations* Get() 108 { 109 InstallationLocations* defaultLocations = Default(); 110 111 // Get the home config installation location and create a new object, 112 // if it differs from the default. 113 char homeInstallationLocation[B_PATH_NAME_LENGTH]; 114 if (__find_directory(B_USER_CONFIG_DIRECTORY, -1, false, 115 homeInstallationLocation, sizeof(homeInstallationLocation)) 116 == B_OK) { 117 _kern_normalize_path(homeInstallationLocation, true, 118 homeInstallationLocation); 119 // failure is OK 120 if (strcmp(homeInstallationLocation, 121 defaultLocations->At(kHomeInstallationLocationIndex)) 122 != 0) { 123 InstallationLocations* locations 124 = new(std::nothrow) InstallationLocations( 125 homeInstallationLocation); 126 if (locations != NULL && locations->IsValid()) 127 return locations; 128 delete locations; 129 } 130 } 131 132 atomic_add(&defaultLocations->fReferenceCount, 1); 133 return defaultLocations; 134 } 135 136 void Put() 137 { 138 if (atomic_add(&fReferenceCount, -1) == 1) 139 delete this; 140 } 141 142 const char* At(size_t index) const 143 { 144 return fLocations[index]; 145 } 146 147 const char* LocationFor(const char* path, size_t& _index) 148 { 149 for (size_t i = 0; i < kCount; i++) { 150 size_t length = strlen(fLocations[i]); 151 if (strncmp(path, fLocations[i], length) == 0 152 && (path[length] == '/' || path[length] == '\0')) { 153 _index = i; 154 return fLocations[i]; 155 } 156 } 157 158 return NULL; 159 } 160 161 private: 162 int32 fReferenceCount; 163 const char* fLocations[kCount]; 164 }; 165 166 167 } // unnamed namespace 168 169 170 /*! Returns the installation location relative path for the given base directory 171 constant and installation location index. A '%' in the returned path must be 172 replaced by "" for the primary architecture and by "/<arch>" for a secondary 173 architecture. 174 */ 175 static const char* 176 get_relative_directory_path(size_t installationLocationIndex, 177 path_base_directory baseDirectory) 178 { 179 switch (baseDirectory) { 180 case B_FIND_PATH_INSTALLATION_LOCATION_DIRECTORY: 181 return ""; 182 case B_FIND_PATH_ADD_ONS_DIRECTORY: 183 return "/add-ons%"; 184 case B_FIND_PATH_APPS_DIRECTORY: 185 return "/apps"; 186 case B_FIND_PATH_BIN_DIRECTORY: 187 return "/bin%"; 188 case B_FIND_PATH_BOOT_DIRECTORY: 189 return "/boot"; 190 case B_FIND_PATH_CACHE_DIRECTORY: 191 return "/cache"; 192 case B_FIND_PATH_DATA_DIRECTORY: 193 return "/data"; 194 case B_FIND_PATH_DEVELOP_DIRECTORY: 195 return "/develop"; 196 case B_FIND_PATH_DEVELOP_LIB_DIRECTORY: 197 return "/develop/lib%"; 198 case B_FIND_PATH_DOCUMENTATION_DIRECTORY: 199 return "/documentation"; 200 case B_FIND_PATH_ETC_DIRECTORY: 201 return "/settings/etc"; 202 case B_FIND_PATH_FONTS_DIRECTORY: 203 return "/data/fonts"; 204 case B_FIND_PATH_HEADERS_DIRECTORY: 205 return "/develop/headers%"; 206 case B_FIND_PATH_LIB_DIRECTORY: 207 return "/lib%"; 208 case B_FIND_PATH_LOG_DIRECTORY: 209 return "/log"; 210 case B_FIND_PATH_MEDIA_NODES_DIRECTORY: 211 return "/add-ons%/media"; 212 case B_FIND_PATH_PACKAGES_DIRECTORY: 213 return "/packages"; 214 case B_FIND_PATH_PREFERENCES_DIRECTORY: 215 return "/preferences"; 216 case B_FIND_PATH_SERVERS_DIRECTORY: 217 return "/servers"; 218 case B_FIND_PATH_SETTINGS_DIRECTORY: 219 return installationLocationIndex == kHomeInstallationLocationIndex 220 ? "/settings/global" : "/settings"; 221 case B_FIND_PATH_SOUNDS_DIRECTORY: 222 return "/data/sounds"; 223 case B_FIND_PATH_SPOOL_DIRECTORY: 224 return "/var/spool"; 225 case B_FIND_PATH_TRANSLATORS_DIRECTORY: 226 return "/add-ons%/Translators"; 227 case B_FIND_PATH_VAR_DIRECTORY: 228 return "/var"; 229 230 case B_FIND_PATH_IMAGE_PATH: 231 case B_FIND_PATH_PACKAGE_PATH: 232 default: 233 return NULL; 234 } 235 } 236 237 238 static status_t 239 create_directory(char* path) 240 { 241 // find the first directory that doesn't exist 242 char* slash = path; 243 bool found = false; 244 while (!found && (slash = strchr(slash + 1, '/')) != NULL) { 245 *slash = '\0'; 246 struct stat st; 247 if (lstat(path, &st) != 0) 248 break; 249 *slash = '/'; 250 } 251 252 if (found) 253 return B_OK; 254 255 // create directories 256 while (slash != NULL) { 257 *slash = '\0'; 258 bool created = mkdir(path, 0755); 259 *slash = '/'; 260 261 if (!created) 262 return errno; 263 264 slash = strchr(slash + 1, '/'); 265 } 266 267 return B_OK; 268 } 269 270 271 static bool 272 is_in_range(const void* pointer, const void* base, size_t size) 273 { 274 return pointer >= base && (addr_t)pointer < (addr_t)base + size; 275 } 276 277 278 static status_t 279 find_image(const void* codePointer, image_info& _info) 280 { 281 int32 cookie = 0; 282 283 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &_info) == B_OK) { 284 if (codePointer == NULL ? _info.type == B_APP_IMAGE 285 : (is_in_range(codePointer, _info.text, _info.text_size) 286 || is_in_range(codePointer, _info.data, _info.data_size))) { 287 return B_OK; 288 } 289 } 290 291 return B_ENTRY_NOT_FOUND; 292 } 293 294 295 static status_t 296 copy_path(const char* path, char* buffer, size_t bufferSize) 297 { 298 if (strlcpy(buffer, path, bufferSize) >= bufferSize) 299 return B_BUFFER_OVERFLOW; 300 return B_OK; 301 } 302 303 304 static status_t 305 normalize_path(const char* path, char* buffer, size_t bufferSize) 306 { 307 status_t error; 308 if (bufferSize >= B_PATH_NAME_LENGTH) { 309 error = _kern_normalize_path(path, true, buffer); 310 } else { 311 char normalizedPath[B_PATH_NAME_LENGTH]; 312 error = _kern_normalize_path(path, true, normalizedPath); 313 if (error == B_OK) 314 error = copy_path(path, buffer, bufferSize); 315 } 316 317 if (error != B_OK) 318 return error; 319 320 // make sure the path exists 321 struct stat st; 322 if (lstat(buffer, &st) != 0) 323 return errno; 324 325 return B_OK; 326 } 327 328 329 static status_t 330 normalize_longest_existing_path_prefix(const char* path, char* buffer, 331 size_t bufferSize) 332 { 333 if (strlcpy(buffer, path, bufferSize) >= bufferSize) 334 return B_NAME_TOO_LONG; 335 336 // Until we have an existing path, chop off leaf components. 337 for (;;) { 338 struct stat st; 339 if (lstat(buffer, &st) == 0) 340 break; 341 342 // Chop off the leaf, but fail, it it's "..", since then we'd actually 343 // construct a subpath. 344 char* lastSlash = strrchr(buffer, '/'); 345 if (lastSlash == NULL || strcmp(lastSlash + 1, "..") == 0) 346 return B_ENTRY_NOT_FOUND; 347 348 *lastSlash = '\0'; 349 } 350 351 // normalize the existing prefix path 352 size_t prefixLength = strlen(buffer); 353 status_t error = normalize_path(buffer, buffer, bufferSize); 354 if (error != B_OK) 355 return error; 356 357 // Re-append the non-existent suffix. Remove duplicate slashes and "." 358 // components. 359 const char* bufferEnd = buffer + bufferSize; 360 char* end = buffer + strlen(buffer); 361 const char* remainder = path + prefixLength + 1; 362 while (*remainder != '\0') { 363 // find component start 364 if (*remainder == '/') { 365 remainder++; 366 continue; 367 } 368 369 // find component end 370 const char* componentEnd = strchr(remainder, '/'); 371 if (componentEnd == NULL) 372 componentEnd = remainder + strlen(remainder); 373 374 // skip "." components 375 size_t componentLength = componentEnd - remainder; 376 if (componentLength == 1 && *remainder == '.') { 377 remainder++; 378 continue; 379 } 380 381 // append the component 382 if (end + 1 + componentLength >= bufferEnd) 383 return B_BUFFER_OVERFLOW; 384 385 *end++ = '/'; 386 memcpy(end, remainder, componentLength); 387 end += componentLength; 388 remainder += componentLength; 389 } 390 391 *end = '\0'; 392 return B_OK; 393 } 394 395 396 static status_t 397 get_file_attribute(const char* path, const char* attribute, char* nameBuffer, 398 size_t bufferSize) 399 { 400 int fd = fs_open_attr(path, attribute, B_STRING_TYPE, 401 O_RDONLY | O_NOTRAVERSE); 402 if (fd < 0) 403 return errno; 404 405 status_t error = B_OK; 406 ssize_t bytesRead = read(fd, nameBuffer, bufferSize - 1); 407 if (bytesRead < 0) 408 error = bytesRead; 409 else if (bytesRead == 0) 410 error = B_ENTRY_NOT_FOUND; 411 else 412 nameBuffer[bytesRead] = '\0'; 413 414 fs_close_attr(fd); 415 416 return error; 417 } 418 419 420 static status_t 421 normalize_dependency(const char* dependency, char* buffer, size_t bufferSize) 422 { 423 if (strlcpy(buffer, dependency, bufferSize) >= bufferSize) 424 return B_NAME_TOO_LONG; 425 426 // replace all ':' with '~' 427 char* colon = buffer - 1; 428 while ((colon = strchr(colon + 1, ':')) != NULL) 429 *colon = '~'; 430 431 return B_OK; 432 } 433 434 435 static ssize_t 436 process_path(const char* installationLocation, const char* architecture, 437 const char* relativePath, const char* subPath, uint32 flags, 438 char* pathBuffer, size_t bufferSize) 439 { 440 // copy the installation location 441 PathBuffer buffer(pathBuffer, bufferSize); 442 buffer.Append(installationLocation); 443 444 // append the relative path, expanding the architecture placeholder 445 if (const char* placeholder = strchr(relativePath, '%')) { 446 buffer.Append(relativePath, placeholder - relativePath); 447 448 if (architecture != NULL) { 449 buffer.Append("/", 1); 450 buffer.Append(architecture); 451 } 452 453 buffer.Append(placeholder + 1); 454 } else 455 buffer.Append(relativePath); 456 457 // append subpath, if given 458 if (subPath != NULL) { 459 buffer.Append("/", 1); 460 buffer.Append(subPath); 461 } 462 463 size_t totalLength = buffer.Length(); 464 if (totalLength >= bufferSize) 465 return B_BUFFER_OVERFLOW; 466 467 // handle the flags 468 char* path = pathBuffer; 469 470 status_t error = B_OK; 471 if ((flags & B_FIND_PATH_CREATE_DIRECTORY) != 0) { 472 // create the directory 473 error = create_directory(path); 474 } else if ((flags & B_FIND_PATH_CREATE_PARENT_DIRECTORY) != 0) { 475 // create the parent directory 476 char* lastSlash = strrchr(path, '/'); 477 *lastSlash = '\0'; 478 error = create_directory(path); 479 *lastSlash = '/'; 480 } 481 482 if (error != B_OK) 483 return error; 484 485 if ((flags & B_FIND_PATH_EXISTING_ONLY) != 0) { 486 // check if the entry exists 487 struct stat st; 488 if (lstat(path, &st) != 0) 489 return 0; 490 } 491 492 return totalLength + 1; 493 } 494 495 496 status_t 497 internal_path_for_path(char* referencePath, size_t referencePathSize, 498 const char* dependency, const char* architecture, 499 path_base_directory baseDirectory, const char* subPath, uint32 flags, 500 char* pathBuffer, size_t bufferSize) 501 { 502 if (strcmp(architecture, __get_primary_architecture()) == 0) 503 architecture = NULL; 504 505 // resolve dependency 506 char packageName[B_FILE_NAME_LENGTH]; 507 // Temporarily used here, permanently used below where 508 // B_FIND_PATH_PACKAGE_PATH is handled. 509 if (dependency != NULL) { 510 // get the versioned package name 511 status_t error = get_file_attribute(referencePath, "SYS:PACKAGE", 512 packageName, sizeof(packageName)); 513 if (error != B_OK) 514 return error; 515 516 // normalize the dependency name 517 char normalizedDependency[B_FILE_NAME_LENGTH]; 518 error = normalize_dependency(dependency, normalizedDependency, 519 sizeof(normalizedDependency)); 520 if (error != B_OK) 521 return error; 522 523 // Compute the path of the dependency symlink. This will yield the 524 // installation location path when normalized. 525 if (snprintf(referencePath, referencePathSize, 526 kSystemPackageLinksDirectory "/%s/%s", packageName, 527 normalizedDependency) 528 >= (ssize_t)referencePathSize) { 529 return B_BUFFER_OVERFLOW; 530 } 531 } 532 533 // handle B_FIND_PATH_IMAGE_PATH 534 if (baseDirectory == B_FIND_PATH_IMAGE_PATH) 535 return copy_path(referencePath, pathBuffer, bufferSize); 536 537 // Handle B_FIND_PATH_PACKAGE_PATH: get the package file name and 538 // simply adjust our arguments to look the package file up in the packages 539 // directory. 540 if (baseDirectory == B_FIND_PATH_PACKAGE_PATH) { 541 status_t error = get_file_attribute(referencePath, "SYS:PACKAGE_FILE", 542 packageName, sizeof(packageName)); 543 if (error != B_OK) 544 return error; 545 546 dependency = NULL; 547 subPath = packageName; 548 baseDirectory = B_FIND_PATH_PACKAGES_DIRECTORY; 549 flags = B_FIND_PATH_EXISTING_ONLY; 550 } 551 552 // normalize 553 status_t error = normalize_path(referencePath, referencePath, 554 referencePathSize); 555 if (error != B_OK) 556 return error; 557 558 // get the installation location 559 InstallationLocations* installationLocations = InstallationLocations::Get(); 560 MethodDeleter<InstallationLocations> installationLocationsDeleter( 561 installationLocations, &InstallationLocations::Put); 562 563 size_t installationLocationIndex; 564 const char* installationLocation = installationLocations->LocationFor( 565 referencePath, installationLocationIndex); 566 if (installationLocation == NULL) 567 return B_ENTRY_NOT_FOUND; 568 569 // get base dir and process the path 570 const char* relativePath = get_relative_directory_path( 571 installationLocationIndex, baseDirectory); 572 if (relativePath == NULL) 573 return B_BAD_VALUE; 574 575 ssize_t pathSize = process_path(installationLocation, architecture, 576 relativePath, subPath, flags, pathBuffer, bufferSize); 577 if (pathSize <= 0) 578 return pathSize == 0 ? B_ENTRY_NOT_FOUND : pathSize; 579 return B_OK; 580 } 581 582 583 // #pragma mark - 584 585 586 status_t 587 __find_path(const void* codePointer, path_base_directory baseDirectory, 588 const char* subPath, char* pathBuffer, size_t bufferSize) 589 { 590 return __find_path_etc(codePointer, NULL, NULL, baseDirectory, subPath, 0, 591 pathBuffer, bufferSize); 592 } 593 594 595 status_t 596 __find_path_etc(const void* codePointer, const char* dependency, 597 const char* architecture, path_base_directory baseDirectory, 598 const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize) 599 { 600 if (pathBuffer == NULL) 601 return B_BAD_VALUE; 602 603 // resolve codePointer to image info 604 image_info imageInfo; 605 status_t error = find_image(codePointer, imageInfo); 606 if (error != B_OK) 607 return error; 608 609 if (architecture == NULL) 610 architecture = __get_architecture(); 611 612 return internal_path_for_path(imageInfo.name, sizeof(imageInfo.name), 613 dependency, architecture, baseDirectory, subPath, flags, pathBuffer, 614 bufferSize); 615 } 616 617 618 status_t 619 __find_path_for_path(const char* path, path_base_directory baseDirectory, 620 const char* subPath, char* pathBuffer, size_t bufferSize) 621 { 622 return __find_path_for_path_etc(path, NULL, NULL, baseDirectory, subPath, 0, 623 pathBuffer, bufferSize); 624 } 625 626 627 status_t 628 __find_path_for_path_etc(const char* path, const char* dependency, 629 const char* architecture, path_base_directory baseDirectory, 630 const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize) 631 { 632 if (baseDirectory == B_FIND_PATH_IMAGE_PATH) 633 return B_BAD_VALUE; 634 635 char referencePath[B_PATH_NAME_LENGTH]; 636 if (strlcpy(referencePath, path, sizeof(referencePath)) 637 >= sizeof(referencePath)) { 638 return B_NAME_TOO_LONG; 639 } 640 641 if (architecture == NULL) 642 architecture = __guess_architecture_for_path(path); 643 644 return internal_path_for_path(referencePath, sizeof(referencePath), 645 dependency, architecture, baseDirectory, subPath, flags, pathBuffer, 646 bufferSize); 647 } 648 649 650 status_t 651 __find_paths(path_base_directory baseDirectory, const char* subPath, 652 char*** _paths, size_t* _pathCount) 653 { 654 return __find_paths_etc(NULL, baseDirectory, subPath, 0, _paths, 655 _pathCount); 656 } 657 658 659 status_t 660 __find_paths_etc(const char* architecture, path_base_directory baseDirectory, 661 const char* subPath, uint32 flags, char*** _paths, size_t* _pathCount) 662 { 663 if (_paths == NULL || _pathCount == NULL) 664 return B_BAD_VALUE; 665 666 // Analyze architecture. If NULL, use the caller's architecture. If the 667 // effective architecture is the primary one, set architecture to NULL to 668 // indicate that we don't need to insert an architecture subdirectory 669 // component. 670 if (architecture == NULL) 671 architecture = __get_architecture(); 672 if (strcmp(architecture, __get_primary_architecture()) == 0) 673 architecture = NULL; 674 size_t architectureSize = architecture != NULL 675 ? strlen(architecture) + 1 : 0; 676 677 size_t subPathLength = subPath != NULL ? strlen(subPath) + 1 : 0; 678 679 // get the installation locations 680 InstallationLocations* installationLocations = InstallationLocations::Get(); 681 MethodDeleter<InstallationLocations> installationLocationsDeleter( 682 installationLocations, &InstallationLocations::Put); 683 684 // Get the relative paths and compute the total size to allocate. 685 const char* relativePaths[InstallationLocations::kCount]; 686 size_t totalSize = 0; 687 688 for (size_t i = 0; i < InstallationLocations::kCount; i++) { 689 if (((flags & B_FIND_PATHS_USER_ONLY) != 0 690 && !installationLocations->IsUserIndex(i)) 691 || ((flags & B_FIND_PATHS_SYSTEM_ONLY) != 0 692 && !installationLocations->IsSystemIndex(i))) 693 continue; 694 695 relativePaths[i] = get_relative_directory_path(i, baseDirectory); 696 if (relativePaths[i] == NULL) 697 return B_BAD_VALUE; 698 699 totalSize += strlen(installationLocations->At(i)) 700 + strlen(relativePaths[i]) + subPathLength + 1; 701 if (strchr(relativePaths[i], '%') != NULL) 702 totalSize += architectureSize - 1; 703 } 704 705 // allocate storage 706 char** paths = (char**)malloc(sizeof(char*) * InstallationLocations::kCount 707 + totalSize); 708 if (paths == NULL) 709 return B_NO_MEMORY; 710 MemoryDeleter pathsDeleter(paths); 711 712 // construct and process the paths 713 size_t count = 0; 714 char* pathBuffer = (char*)(paths + InstallationLocations::kCount); 715 const char* pathBufferEnd = pathBuffer + totalSize; 716 for (size_t i = 0; i < InstallationLocations::kCount; i++) { 717 if (((flags & B_FIND_PATHS_USER_ONLY) != 0 718 && !installationLocations->IsUserIndex(i)) 719 || ((flags & B_FIND_PATHS_SYSTEM_ONLY) != 0 720 && !installationLocations->IsSystemIndex(i))) 721 continue; 722 723 ssize_t pathSize = process_path(installationLocations->At(i), 724 architecture, relativePaths[i], subPath, flags, pathBuffer, 725 pathBufferEnd - pathBuffer); 726 if (pathSize < 0) 727 return pathSize; 728 if (pathSize > 0) { 729 paths[count++] = pathBuffer; 730 pathBuffer += pathSize; 731 } 732 } 733 734 if (count == 0) 735 return B_ENTRY_NOT_FOUND; 736 737 *_paths = paths; 738 *_pathCount = count; 739 pathsDeleter.Detach(); 740 741 return B_OK; 742 } 743 744 745 const char* 746 __guess_secondary_architecture_from_path(const char* path, 747 const char* const* secondaryArchitectures, 748 size_t secondaryArchitectureCount) 749 { 750 // Get the longest existing prefix path and normalize it. 751 char prefix[B_PATH_NAME_LENGTH]; 752 if (normalize_longest_existing_path_prefix(path, prefix, sizeof(prefix)) 753 != B_OK) { 754 return NULL; 755 } 756 757 // get an installation location relative path 758 InstallationLocations* installationLocations = InstallationLocations::Get(); 759 MethodDeleter<InstallationLocations> installationLocationsDeleter( 760 installationLocations, &InstallationLocations::Put); 761 762 size_t installationLocationIndex; 763 const char* installationLocation = installationLocations->LocationFor( 764 prefix, installationLocationIndex); 765 if (installationLocation == NULL) 766 return NULL; 767 768 const char* relativePath = prefix + strlen(installationLocation); 769 if (relativePath[0] != '/') 770 return NULL; 771 772 // Iterate through the known paths that would indicate a secondary 773 // architecture and try to match them with our given path. 774 for (size_t i = 0; i < kArchitectureSpecificBaseDirectoryCount; i++) { 775 const char* basePath = get_relative_directory_path( 776 installationLocationIndex, kArchitectureSpecificBaseDirectories[i]); 777 const char* placeholder = strchr(basePath, '%'); 778 if (placeholder == NULL) 779 continue; 780 781 // match the part up to the architecture placeholder 782 size_t prefixLength = placeholder - basePath; 783 if (strncmp(relativePath, basePath, prefixLength) != 0 784 || relativePath[prefixLength] != '/') { 785 continue; 786 } 787 788 // match the architecture 789 const char* architecturePart = relativePath + prefixLength + 1; 790 for (size_t k = 0; k < secondaryArchitectureCount; k++) { 791 const char* architecture = secondaryArchitectures[k]; 792 size_t architectureLength = strlen(architecture); 793 if (strncmp(architecturePart, architecture, architectureLength) == 0 794 && (architecturePart[architectureLength] == '/' 795 || architecturePart[architectureLength] == '\0')) { 796 return architecture; 797 } 798 } 799 } 800 801 return NULL; 802 } 803 804 805 B_DEFINE_WEAK_ALIAS(__find_path, find_path); 806 B_DEFINE_WEAK_ALIAS(__find_path_etc, find_path_etc); 807 B_DEFINE_WEAK_ALIAS(__find_path_for_path, find_path_for_path); 808 B_DEFINE_WEAK_ALIAS(__find_path_for_path_etc, find_path_for_path_etc); 809 B_DEFINE_WEAK_ALIAS(__find_paths, find_paths); 810 B_DEFINE_WEAK_ALIAS(__find_paths_etc, find_paths_etc); 811