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 "/settings"; 220 case B_FIND_PATH_SOUNDS_DIRECTORY: 221 return "/data/sounds"; 222 case B_FIND_PATH_SPOOL_DIRECTORY: 223 return "/var/spool"; 224 case B_FIND_PATH_TRANSLATORS_DIRECTORY: 225 return "/add-ons%/Translators"; 226 case B_FIND_PATH_VAR_DIRECTORY: 227 return "/var"; 228 229 case B_FIND_PATH_IMAGE_PATH: 230 case B_FIND_PATH_PACKAGE_PATH: 231 default: 232 return NULL; 233 } 234 } 235 236 237 static status_t 238 create_directory(char* path) 239 { 240 // find the first directory that doesn't exist 241 char* slash = path; 242 bool found = false; 243 while (!found && (slash = strchr(slash + 1, '/')) != NULL) { 244 *slash = '\0'; 245 struct stat st; 246 if (lstat(path, &st) != 0) 247 break; 248 *slash = '/'; 249 } 250 251 if (found) 252 return B_OK; 253 254 // create directories 255 while (slash != NULL) { 256 *slash = '\0'; 257 bool created = mkdir(path, 0755); 258 *slash = '/'; 259 260 if (!created) 261 return errno; 262 263 slash = strchr(slash + 1, '/'); 264 } 265 266 return B_OK; 267 } 268 269 270 static bool 271 is_in_range(const void* pointer, const void* base, size_t size) 272 { 273 return pointer >= base && (addr_t)pointer < (addr_t)base + size; 274 } 275 276 277 static status_t 278 find_image(const void* codePointer, image_info& _info) 279 { 280 int32 cookie = 0; 281 282 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &_info) == B_OK) { 283 if (codePointer == NULL ? _info.type == B_APP_IMAGE 284 : (is_in_range(codePointer, _info.text, _info.text_size) 285 || is_in_range(codePointer, _info.data, _info.data_size))) { 286 return B_OK; 287 } 288 } 289 290 return B_ENTRY_NOT_FOUND; 291 } 292 293 294 static status_t 295 copy_path(const char* path, char* buffer, size_t bufferSize) 296 { 297 if (strlcpy(buffer, path, bufferSize) >= bufferSize) 298 return B_BUFFER_OVERFLOW; 299 return B_OK; 300 } 301 302 303 static status_t 304 normalize_path(const char* path, char* buffer, size_t bufferSize) 305 { 306 status_t error; 307 if (bufferSize >= B_PATH_NAME_LENGTH) { 308 error = _kern_normalize_path(path, true, buffer); 309 } else { 310 char normalizedPath[B_PATH_NAME_LENGTH]; 311 error = _kern_normalize_path(path, true, normalizedPath); 312 if (error == B_OK) 313 error = copy_path(path, buffer, bufferSize); 314 } 315 316 if (error != B_OK) 317 return error; 318 319 // make sure the path exists 320 struct stat st; 321 if (lstat(buffer, &st) != 0) 322 return errno; 323 324 return B_OK; 325 } 326 327 328 static status_t 329 normalize_longest_existing_path_prefix(const char* path, char* buffer, 330 size_t bufferSize) 331 { 332 if (strlcpy(buffer, path, bufferSize) >= bufferSize) 333 return B_NAME_TOO_LONG; 334 335 // Until we have an existing path, chop off leaf components. 336 for (;;) { 337 struct stat st; 338 if (lstat(buffer, &st) == 0) 339 break; 340 341 // Chop off the leaf, but fail, it it's "..", since then we'd actually 342 // construct a subpath. 343 char* lastSlash = strrchr(buffer, '/'); 344 if (lastSlash == NULL || strcmp(lastSlash + 1, "..") == 0) 345 return B_ENTRY_NOT_FOUND; 346 347 *lastSlash = '\0'; 348 } 349 350 // normalize the existing prefix path 351 size_t prefixLength = strlen(buffer); 352 status_t error = normalize_path(buffer, buffer, bufferSize); 353 if (error != B_OK) 354 return error; 355 356 // Re-append the non-existent suffix. Remove duplicate slashes and "." 357 // components. 358 const char* bufferEnd = buffer + bufferSize; 359 char* end = buffer + strlen(buffer); 360 const char* remainder = path + prefixLength + 1; 361 while (*remainder != '\0') { 362 // find component start 363 if (*remainder == '/') { 364 remainder++; 365 continue; 366 } 367 368 // find component end 369 const char* componentEnd = strchr(remainder, '/'); 370 if (componentEnd == NULL) 371 componentEnd = remainder + strlen(remainder); 372 373 // skip "." components 374 size_t componentLength = componentEnd - remainder; 375 if (componentLength == 1 && *remainder == '.') { 376 remainder++; 377 continue; 378 } 379 380 // append the component 381 if (end + 1 + componentLength >= bufferEnd) 382 return B_BUFFER_OVERFLOW; 383 384 *end++ = '/'; 385 memcpy(end, remainder, componentLength); 386 end += componentLength; 387 remainder += componentLength; 388 } 389 390 *end = '\0'; 391 return B_OK; 392 } 393 394 395 static status_t 396 get_file_attribute(const char* path, const char* attribute, char* nameBuffer, 397 size_t bufferSize) 398 { 399 int fd = fs_open_attr(path, attribute, B_STRING_TYPE, 400 O_RDONLY | O_NOTRAVERSE); 401 if (fd < 0) 402 return errno; 403 404 status_t error = B_OK; 405 ssize_t bytesRead = read(fd, nameBuffer, bufferSize - 1); 406 if (bytesRead < 0) 407 error = bytesRead; 408 else if (bytesRead == 0) 409 error = B_ENTRY_NOT_FOUND; 410 else 411 nameBuffer[bytesRead] = '\0'; 412 413 fs_close_attr(fd); 414 415 return error; 416 } 417 418 419 static status_t 420 normalize_dependency(const char* dependency, char* buffer, size_t bufferSize) 421 { 422 if (strlcpy(buffer, dependency, bufferSize) >= bufferSize) 423 return B_NAME_TOO_LONG; 424 425 // replace all ':' with '~' 426 char* colon = buffer - 1; 427 while ((colon = strchr(colon + 1, ':')) != NULL) 428 *colon = '~'; 429 430 return B_OK; 431 } 432 433 434 static ssize_t 435 process_path(const char* installationLocation, const char* architecture, 436 const char* relativePath, const char* subPath, uint32 flags, 437 char* pathBuffer, size_t bufferSize) 438 { 439 // copy the installation location 440 PathBuffer buffer(pathBuffer, bufferSize); 441 buffer.Append(installationLocation); 442 443 // append the relative path, expanding the architecture placeholder 444 if (const char* placeholder = strchr(relativePath, '%')) { 445 buffer.Append(relativePath, placeholder - relativePath); 446 447 if (architecture != NULL) { 448 buffer.Append("/", 1); 449 buffer.Append(architecture); 450 } 451 452 buffer.Append(placeholder + 1); 453 } else 454 buffer.Append(relativePath); 455 456 // append subpath, if given 457 if (subPath != NULL) { 458 buffer.Append("/", 1); 459 buffer.Append(subPath); 460 } 461 462 size_t totalLength = buffer.Length(); 463 if (totalLength >= bufferSize) 464 return B_BUFFER_OVERFLOW; 465 466 // handle the flags 467 char* path = pathBuffer; 468 469 status_t error = B_OK; 470 if ((flags & B_FIND_PATH_CREATE_DIRECTORY) != 0) { 471 // create the directory 472 error = create_directory(path); 473 } else if ((flags & B_FIND_PATH_CREATE_PARENT_DIRECTORY) != 0) { 474 // create the parent directory 475 char* lastSlash = strrchr(path, '/'); 476 *lastSlash = '\0'; 477 error = create_directory(path); 478 *lastSlash = '/'; 479 } 480 481 if (error != B_OK) 482 return error; 483 484 if ((flags & B_FIND_PATH_EXISTING_ONLY) != 0) { 485 // check if the entry exists 486 struct stat st; 487 if (lstat(path, &st) != 0) 488 return 0; 489 } 490 491 return totalLength + 1; 492 } 493 494 495 status_t 496 internal_path_for_path(char* referencePath, size_t referencePathSize, 497 const char* dependency, const char* architecture, 498 path_base_directory baseDirectory, const char* subPath, uint32 flags, 499 char* pathBuffer, size_t bufferSize) 500 { 501 if (strcmp(architecture, __get_primary_architecture()) == 0) 502 architecture = NULL; 503 504 // resolve dependency 505 char packageName[B_FILE_NAME_LENGTH]; 506 // Temporarily used here, permanently used below where 507 // B_FIND_PATH_PACKAGE_PATH is handled. 508 if (dependency != NULL) { 509 // get the versioned package name 510 status_t error = get_file_attribute(referencePath, "SYS:PACKAGE", 511 packageName, sizeof(packageName)); 512 if (error != B_OK) 513 return error; 514 515 // normalize the dependency name 516 char normalizedDependency[B_FILE_NAME_LENGTH]; 517 error = normalize_dependency(dependency, normalizedDependency, 518 sizeof(normalizedDependency)); 519 if (error != B_OK) 520 return error; 521 522 // Compute the path of the dependency symlink. This will yield the 523 // installation location path when normalized. 524 if (snprintf(referencePath, referencePathSize, 525 kSystemPackageLinksDirectory "/%s/%s", packageName, 526 normalizedDependency) 527 >= (ssize_t)referencePathSize) { 528 return B_BUFFER_OVERFLOW; 529 } 530 } 531 532 // handle B_FIND_PATH_IMAGE_PATH 533 if (baseDirectory == B_FIND_PATH_IMAGE_PATH) 534 return copy_path(referencePath, pathBuffer, bufferSize); 535 536 // Handle B_FIND_PATH_PACKAGE_PATH: get the package file name and 537 // simply adjust our arguments to look the package file up in the packages 538 // directory. 539 if (baseDirectory == B_FIND_PATH_PACKAGE_PATH) { 540 status_t error = get_file_attribute(referencePath, "SYS:PACKAGE_FILE", 541 packageName, sizeof(packageName)); 542 if (error != B_OK) 543 return error; 544 545 dependency = NULL; 546 subPath = packageName; 547 baseDirectory = B_FIND_PATH_PACKAGES_DIRECTORY; 548 flags = B_FIND_PATH_EXISTING_ONLY; 549 } 550 551 // normalize 552 status_t error = normalize_path(referencePath, referencePath, 553 referencePathSize); 554 if (error != B_OK) 555 return error; 556 557 // get the installation location 558 InstallationLocations* installationLocations = InstallationLocations::Get(); 559 MethodDeleter<InstallationLocations, void, &InstallationLocations::Put> 560 installationLocationsDeleter(installationLocations); 561 562 size_t installationLocationIndex; 563 const char* installationLocation = installationLocations->LocationFor( 564 referencePath, installationLocationIndex); 565 if (installationLocation == NULL) 566 return B_ENTRY_NOT_FOUND; 567 568 // get base dir and process the path 569 const char* relativePath = get_relative_directory_path( 570 installationLocationIndex, baseDirectory); 571 if (relativePath == NULL) 572 return B_BAD_VALUE; 573 574 ssize_t pathSize = process_path(installationLocation, architecture, 575 relativePath, subPath, flags, pathBuffer, bufferSize); 576 if (pathSize <= 0) 577 return pathSize == 0 ? B_ENTRY_NOT_FOUND : pathSize; 578 return B_OK; 579 } 580 581 582 // #pragma mark - 583 584 585 status_t 586 __find_path(const void* codePointer, path_base_directory baseDirectory, 587 const char* subPath, char* pathBuffer, size_t bufferSize) 588 { 589 return __find_path_etc(codePointer, NULL, NULL, baseDirectory, subPath, 0, 590 pathBuffer, bufferSize); 591 } 592 593 594 status_t 595 __find_path_etc(const void* codePointer, const char* dependency, 596 const char* architecture, path_base_directory baseDirectory, 597 const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize) 598 { 599 if (pathBuffer == NULL) 600 return B_BAD_VALUE; 601 602 // resolve codePointer to image info 603 image_info imageInfo; 604 status_t error = find_image(codePointer, imageInfo); 605 if (error != B_OK) 606 return error; 607 608 if (architecture == NULL) 609 architecture = __get_architecture(); 610 611 return internal_path_for_path(imageInfo.name, sizeof(imageInfo.name), 612 dependency, architecture, baseDirectory, subPath, flags, pathBuffer, 613 bufferSize); 614 } 615 616 617 status_t 618 __find_path_for_path(const char* path, path_base_directory baseDirectory, 619 const char* subPath, char* pathBuffer, size_t bufferSize) 620 { 621 return __find_path_for_path_etc(path, NULL, NULL, baseDirectory, subPath, 0, 622 pathBuffer, bufferSize); 623 } 624 625 626 status_t 627 __find_path_for_path_etc(const char* path, const char* dependency, 628 const char* architecture, path_base_directory baseDirectory, 629 const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize) 630 { 631 if (baseDirectory == B_FIND_PATH_IMAGE_PATH) 632 return B_BAD_VALUE; 633 634 char referencePath[B_PATH_NAME_LENGTH]; 635 if (strlcpy(referencePath, path, sizeof(referencePath)) 636 >= sizeof(referencePath)) { 637 return B_NAME_TOO_LONG; 638 } 639 640 if (architecture == NULL) 641 architecture = __guess_architecture_for_path(path); 642 643 return internal_path_for_path(referencePath, sizeof(referencePath), 644 dependency, architecture, baseDirectory, subPath, flags, pathBuffer, 645 bufferSize); 646 } 647 648 649 status_t 650 __find_paths(path_base_directory baseDirectory, const char* subPath, 651 char*** _paths, size_t* _pathCount) 652 { 653 return __find_paths_etc(NULL, baseDirectory, subPath, 0, _paths, 654 _pathCount); 655 } 656 657 658 status_t 659 __find_paths_etc(const char* architecture, path_base_directory baseDirectory, 660 const char* subPath, uint32 flags, char*** _paths, size_t* _pathCount) 661 { 662 if (_paths == NULL || _pathCount == NULL) 663 return B_BAD_VALUE; 664 665 // Analyze architecture. If NULL, use the caller's architecture. If the 666 // effective architecture is the primary one, set architecture to NULL to 667 // indicate that we don't need to insert an architecture subdirectory 668 // component. 669 if (architecture == NULL) 670 architecture = __get_architecture(); 671 if (strcmp(architecture, __get_primary_architecture()) == 0) 672 architecture = NULL; 673 size_t architectureSize = architecture != NULL 674 ? strlen(architecture) + 1 : 0; 675 676 size_t subPathLength = subPath != NULL ? strlen(subPath) + 1 : 0; 677 678 // get the installation locations 679 InstallationLocations* installationLocations = InstallationLocations::Get(); 680 MethodDeleter<InstallationLocations, void, &InstallationLocations::Put> 681 installationLocationsDeleter(installationLocations); 682 683 // Get the relative paths and compute the total size to allocate. 684 const char* relativePaths[InstallationLocations::kCount]; 685 size_t totalSize = 0; 686 687 for (size_t i = 0; i < InstallationLocations::kCount; i++) { 688 if (((flags & B_FIND_PATHS_USER_ONLY) != 0 689 && !installationLocations->IsUserIndex(i)) 690 || ((flags & B_FIND_PATHS_SYSTEM_ONLY) != 0 691 && !installationLocations->IsSystemIndex(i))) 692 continue; 693 694 relativePaths[i] = get_relative_directory_path(i, baseDirectory); 695 if (relativePaths[i] == NULL) 696 return B_BAD_VALUE; 697 698 totalSize += strlen(installationLocations->At(i)) 699 + strlen(relativePaths[i]) + subPathLength + 1; 700 if (strchr(relativePaths[i], '%') != NULL) 701 totalSize += architectureSize - 1; 702 } 703 704 // allocate storage 705 char** paths = (char**)malloc(sizeof(char*) * InstallationLocations::kCount 706 + totalSize); 707 if (paths == NULL) 708 return B_NO_MEMORY; 709 MemoryDeleter pathsDeleter(paths); 710 711 // construct and process the paths 712 size_t count = 0; 713 char* pathBuffer = (char*)(paths + InstallationLocations::kCount); 714 const char* pathBufferEnd = pathBuffer + totalSize; 715 for (size_t i = 0; i < InstallationLocations::kCount; i++) { 716 if (((flags & B_FIND_PATHS_USER_ONLY) != 0 717 && !installationLocations->IsUserIndex(i)) 718 || ((flags & B_FIND_PATHS_SYSTEM_ONLY) != 0 719 && !installationLocations->IsSystemIndex(i))) 720 continue; 721 722 ssize_t pathSize = process_path(installationLocations->At(i), 723 architecture, relativePaths[i], subPath, flags, pathBuffer, 724 pathBufferEnd - pathBuffer); 725 if (pathSize < 0) 726 return pathSize; 727 if (pathSize > 0) { 728 paths[count++] = pathBuffer; 729 pathBuffer += pathSize; 730 } 731 } 732 733 if (count == 0) 734 return B_ENTRY_NOT_FOUND; 735 736 *_paths = paths; 737 *_pathCount = count; 738 pathsDeleter.Detach(); 739 740 return B_OK; 741 } 742 743 744 const char* 745 __guess_secondary_architecture_from_path(const char* path, 746 const char* const* secondaryArchitectures, 747 size_t secondaryArchitectureCount) 748 { 749 // Get the longest existing prefix path and normalize it. 750 char prefix[B_PATH_NAME_LENGTH]; 751 if (normalize_longest_existing_path_prefix(path, prefix, sizeof(prefix)) 752 != B_OK) { 753 return NULL; 754 } 755 756 // get an installation location relative path 757 InstallationLocations* installationLocations = InstallationLocations::Get(); 758 MethodDeleter<InstallationLocations, void, &InstallationLocations::Put> 759 installationLocationsDeleter(installationLocations); 760 761 size_t installationLocationIndex; 762 const char* installationLocation = installationLocations->LocationFor( 763 prefix, installationLocationIndex); 764 if (installationLocation == NULL) 765 return NULL; 766 767 const char* relativePath = prefix + strlen(installationLocation); 768 if (relativePath[0] != '/') 769 return NULL; 770 771 // Iterate through the known paths that would indicate a secondary 772 // architecture and try to match them with our given path. 773 for (size_t i = 0; i < kArchitectureSpecificBaseDirectoryCount; i++) { 774 const char* basePath = get_relative_directory_path( 775 installationLocationIndex, kArchitectureSpecificBaseDirectories[i]); 776 const char* placeholder = strchr(basePath, '%'); 777 if (placeholder == NULL) 778 continue; 779 780 // match the part up to the architecture placeholder 781 size_t prefixLength = placeholder - basePath; 782 if (strncmp(relativePath, basePath, prefixLength) != 0 783 || relativePath[prefixLength] != '/') { 784 continue; 785 } 786 787 // match the architecture 788 const char* architecturePart = relativePath + prefixLength + 1; 789 for (size_t k = 0; k < secondaryArchitectureCount; k++) { 790 const char* architecture = secondaryArchitectures[k]; 791 size_t architectureLength = strlen(architecture); 792 if (strncmp(architecturePart, architecture, architectureLength) == 0 793 && (architecturePart[architectureLength] == '/' 794 || architecturePart[architectureLength] == '\0')) { 795 return architecture; 796 } 797 } 798 } 799 800 return NULL; 801 } 802 803 804 B_DEFINE_WEAK_ALIAS(__find_path, find_path); 805 B_DEFINE_WEAK_ALIAS(__find_path_etc, find_path_etc); 806 B_DEFINE_WEAK_ALIAS(__find_path_for_path, find_path_for_path); 807 B_DEFINE_WEAK_ALIAS(__find_path_for_path_etc, find_path_for_path_etc); 808 B_DEFINE_WEAK_ALIAS(__find_paths, find_paths); 809 B_DEFINE_WEAK_ALIAS(__find_paths_etc, find_paths_etc); 810