From 60b39cd7416028e61e3d30bb3ba28bd3526e6001 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 16 Nov 2013 22:27:47 +0100 Subject: [PATCH] Add get_*architecture() API, extend find_path*() API * Add get_architecture(), get_primary_architecture(), get_secondary_architectures(), guess_architecture_for_path() to get the caller's architecture, the primary architecture, all secondary architectures, or the architecture associated with a specified path respectively. * Rename the find_path*() functions to find_path*_etc() and add an optional architecture parameter. Add simplified find_path*() functions. * BPathFinder: Add FindPath[s]() versions with an architecture parameter. --- headers/os/storage/FindDirectory.h | 24 +- headers/os/storage/PathFinder.h | 8 + headers/os/support/Architecture.h | 27 ++ headers/private/system/architecture_private.h | 25 ++ .../private/system/find_directory_private.h | 29 +- src/kits/storage/PathFinder.cpp | 46 ++- src/system/libroot/os/Architecture.cpp | 117 +++++++ src/system/libroot/os/Jamfile | 1 + src/system/libroot/os/find_paths.cpp | 315 ++++++++++++++++-- 9 files changed, 537 insertions(+), 55 deletions(-) create mode 100644 headers/os/support/Architecture.h create mode 100644 headers/private/system/architecture_private.h create mode 100644 src/system/libroot/os/Architecture.cpp diff --git a/headers/os/storage/FindDirectory.h b/headers/os/storage/FindDirectory.h index 761a1eea69..5b2fba39d5 100644 --- a/headers/os/storage/FindDirectory.h +++ b/headers/os/storage/FindDirectory.h @@ -170,16 +170,26 @@ extern "C" { status_t find_directory(directory_which which, dev_t volume, bool createIt, char* pathString, int32 length); -status_t find_path(const void* codePointer, const char* dependency, - path_base_directory baseDirectory, const char* subPath, uint32 flags, - char* pathBuffer, size_t bufferSize); +status_t find_path(const void* codePointer, path_base_directory baseDirectory, + const char* subPath, char* pathBuffer, size_t bufferSize); -status_t find_path_for_path(const char* path, const char* dependency, - path_base_directory baseDirectory, const char* subPath, uint32 flags, - char* pathBuffer, size_t bufferSize); +status_t find_path_etc(const void* codePointer, const char* dependency, + const char* architecture, path_base_directory baseDirectory, + const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize); + +status_t find_path_for_path(const char* path, path_base_directory baseDirectory, + const char* subPath, char* pathBuffer, size_t bufferSize); + +status_t find_path_for_path_etc(const char* path, const char* dependency, + const char* architecture, path_base_directory baseDirectory, + const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize); status_t find_paths(path_base_directory baseDirectory, const char* subPath, - uint32 flags, char*** _paths, size_t* _pathCount); + char*** _paths, size_t* _pathCount); + +status_t find_paths_etc(const char* architecture, + path_base_directory baseDirectory, const char* subPath, uint32 flags, + char*** _paths, size_t* _pathCount); #ifdef __cplusplus diff --git a/headers/os/storage/PathFinder.h b/headers/os/storage/PathFinder.h index a1819fb145..80f342aafd 100644 --- a/headers/os/storage/PathFinder.h +++ b/headers/os/storage/PathFinder.h @@ -31,6 +31,10 @@ public: status_t SetTo(const entry_ref& ref, const char* dependency = NULL); + status_t FindPath(const char* architecture, + path_base_directory baseDirectory, + const char* subPath, uint32 flags, + BPath& path); status_t FindPath(path_base_directory baseDirectory, const char* subPath, uint32 flags, BPath& path); @@ -39,6 +43,10 @@ public: status_t FindPath(path_base_directory baseDirectory, BPath& path); + static status_t FindPaths(const char* architecture, + path_base_directory baseDirectory, + const char* subPath, uint32 flags, + BStringList& paths); static status_t FindPaths(path_base_directory baseDirectory, const char* subPath, uint32 flags, BStringList& paths); diff --git a/headers/os/support/Architecture.h b/headers/os/support/Architecture.h new file mode 100644 index 0000000000..7781397b0a --- /dev/null +++ b/headers/os/support/Architecture.h @@ -0,0 +1,27 @@ +/* + * Copyright 2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _SUPPORT_ARCHITECTURE_H +#define _SUPPORT_ARCHITECTURE_H + + +#include + +#include + + +__BEGIN_DECLS + + +const char* get_architecture(); +const char* get_primary_architecture(); +size_t get_secondary_architectures(const char** architectures, + size_t count); +const char* guess_architecture_for_path(const char* path); + + +__END_DECLS + + +#endif /* _SUPPORT_ARCHITECTURE_H */ diff --git a/headers/private/system/architecture_private.h b/headers/private/system/architecture_private.h new file mode 100644 index 0000000000..e638375e19 --- /dev/null +++ b/headers/private/system/architecture_private.h @@ -0,0 +1,25 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _SYSTEM_ARCHITECTURE_PRIVATE_H +#define _SYSTEM_ARCHITECTURE_PRIVATE_H + + +#include + + +__BEGIN_DECLS + + +const char* __get_architecture(); +const char* __get_primary_architecture(); +size_t __get_secondary_architectures(const char** architectures, + size_t count); +const char* __guess_architecture_for_path(const char* path); + + +__END_DECLS + + +#endif /* _SYSTEM_ARCHITECTURE_PRIVATE_H */ diff --git a/headers/private/system/find_directory_private.h b/headers/private/system/find_directory_private.h index 3bdd7bf35f..5db48f33ca 100644 --- a/headers/private/system/find_directory_private.h +++ b/headers/private/system/find_directory_private.h @@ -17,16 +17,31 @@ __BEGIN_DECLS status_t __find_directory(directory_which which, dev_t device, bool createIt, char *returnedPath, int32 pathLength); -status_t __find_path(const void* codePointer, const char* dependency, - path_base_directory baseDirectory, const char* subPath, uint32 flags, - char* pathBuffer, size_t bufferSize); +status_t __find_path(const void* codePointer, path_base_directory baseDirectory, + const char* subPath, char* pathBuffer, size_t bufferSize); -status_t __find_path_for_path(const char* path, const char* dependency, - path_base_directory baseDirectory, const char* subPath, uint32 flags, - char* pathBuffer, size_t bufferSize); +status_t __find_path_etc(const void* codePointer, const char* dependency, + const char* architecture, path_base_directory baseDirectory, + const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize); + +status_t __find_path_for_path(const char* path, + path_base_directory baseDirectory, const char* subPath, char* pathBuffer, + size_t bufferSize); + +status_t __find_path_for_path_etc(const char* path, const char* dependency, + const char* architecture, path_base_directory baseDirectory, + const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize); status_t __find_paths(path_base_directory baseDirectory, const char* subPath, - uint32 flags, char*** _paths, size_t* _pathCount); + char*** _paths, size_t* _pathCount); + +status_t __find_paths_etc(const char* architecture, + path_base_directory baseDirectory, const char* subPath, uint32 flags, + char*** _paths, size_t* _pathCount); + +const char* __guess_secondary_architecture_from_path(const char* path, + const char* const* secondaryArchitectures, + size_t secondaryArchitectureCount); __END_DECLS diff --git a/src/kits/storage/PathFinder.cpp b/src/kits/storage/PathFinder.cpp index 579418999c..f51eb652bc 100644 --- a/src/kits/storage/PathFinder.cpp +++ b/src/kits/storage/PathFinder.cpp @@ -55,9 +55,11 @@ BPathFinder::SetTo(const entry_ref& ref, const char* dependency) } + status_t -BPathFinder::FindPath(path_base_directory baseDirectory, const char* subPath, - uint32 flags, BPath& path) +BPathFinder::FindPath(const char* architecture, + path_base_directory baseDirectory, const char* subPath, uint32 flags, + BPath& path) { path.Unset(); @@ -71,11 +73,11 @@ BPathFinder::FindPath(path_base_directory baseDirectory, const char* subPath, status_t error; if (!fPath.IsEmpty()) { - error = find_path_for_path(fPath, dependency, baseDirectory, subPath, - flags, pathBuffer, sizeof(pathBuffer)); + error = find_path_for_path_etc(fPath, dependency, architecture, + baseDirectory, subPath, flags, pathBuffer, sizeof(pathBuffer)); } else { - error = find_path(fCodePointer, dependency, baseDirectory, subPath, - flags, pathBuffer, sizeof(pathBuffer)); + error = find_path_etc(fCodePointer, dependency, architecture, + baseDirectory, subPath, flags, pathBuffer, sizeof(pathBuffer)); } if (error != B_OK) @@ -84,33 +86,41 @@ BPathFinder::FindPath(path_base_directory baseDirectory, const char* subPath, return path.SetTo(pathBuffer); } +status_t +BPathFinder::FindPath(path_base_directory baseDirectory, const char* subPath, + uint32 flags, BPath& path) +{ + return FindPath(NULL, baseDirectory, subPath, flags, path); +} + status_t BPathFinder::FindPath(path_base_directory baseDirectory, const char* subPath, BPath& path) { - return FindPath(baseDirectory, subPath, 0, path); + return FindPath(NULL, baseDirectory, subPath, 0, path); } status_t BPathFinder::FindPath(path_base_directory baseDirectory, BPath& path) { - return FindPath(baseDirectory, NULL, 0, path); + return FindPath(NULL, baseDirectory, NULL, 0, path); } /*static*/ status_t -BPathFinder::FindPaths(path_base_directory baseDirectory, const char* subPath, - uint32 flags, BStringList& paths) +BPathFinder::FindPaths(const char* architecture, + path_base_directory baseDirectory, const char* subPath, uint32 flags, + BStringList& paths) { paths.MakeEmpty(); // get the paths char** pathArray; size_t pathCount; - status_t error = find_paths(baseDirectory, subPath, flags, &pathArray, - &pathCount); + status_t error = find_paths_etc(architecture, baseDirectory, subPath, flags, + &pathArray, &pathCount); if (error != B_OK) return error; @@ -127,18 +137,26 @@ BPathFinder::FindPaths(path_base_directory baseDirectory, const char* subPath, } +/*static*/ status_t +BPathFinder::FindPaths(path_base_directory baseDirectory, const char* subPath, + uint32 flags, BStringList& paths) +{ + return FindPaths(NULL, baseDirectory, subPath, 0, paths); +} + + /*static*/ status_t BPathFinder::FindPaths(path_base_directory baseDirectory, const char* subPath, BStringList& paths) { - return FindPaths(baseDirectory, subPath, 0, paths); + return FindPaths(NULL, baseDirectory, subPath, 0, paths); } /*static*/ status_t BPathFinder::FindPaths(path_base_directory baseDirectory, BStringList& paths) { - return FindPaths(baseDirectory, NULL, 0, paths); + return FindPaths(NULL, baseDirectory, NULL, 0, paths); } diff --git a/src/system/libroot/os/Architecture.cpp b/src/system/libroot/os/Architecture.cpp new file mode 100644 index 0000000000..9b96256ad3 --- /dev/null +++ b/src/system/libroot/os/Architecture.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include + +#include + +#include +#include +#include + + +static const char* const kArchitecture = B_HAIKU_ABI_NAME; +static const char* const kPrimaryArchitecture = __HAIKU_PRIMARY_PACKAGING_ARCH; + +#ifdef __HAIKU_ARCH_X86 + static const char* const kSiblingArchitectures[] = {"x86_gcc2", "x86"}; +#else + static const char* const kSiblingArchitectures[] = {}; +#endif + +static const size_t kSiblingArchitectureCount + = sizeof(kSiblingArchitectures) / sizeof(const char*); + + +static bool +has_secondary_architecture(const char* architecture) +{ + if (strcmp(architecture, kPrimaryArchitecture) == 0) + return false; + + char path[B_PATH_NAME_LENGTH]; + snprintf(path, sizeof(path), kSystemLibDirectory "/%s/libroot.so", + architecture); + + struct stat st; + return lstat(path, &st) == 0; +} + + +// #pragma mark - + + +const char* +__get_architecture() +{ + return kArchitecture; +} + + +const char* +__get_primary_architecture() +{ + return kPrimaryArchitecture; +} + + +size_t +__get_secondary_architectures(const char** architectures, size_t count) +{ + size_t index = 0; + + // If this is an architecture that could be a primary or secondary + // architecture, check for which architectures a libroot.so is present. + if (kSiblingArchitectureCount > 0) { + for (size_t i = 0; i < kSiblingArchitectureCount; i++) { + const char* architecture = kSiblingArchitectures[i]; + if (!has_secondary_architecture(architecture)) + continue; + + if (index < count) + architectures[index] = architecture; + index++; + } + } + + return index; +} + + +const char* +__guess_architecture_for_path(const char* path) +{ + if (kSiblingArchitectureCount == 0) + return kPrimaryArchitecture; + + // ask the runtime loader + const char* architecture; + if (__gRuntimeLoader->get_executable_architecture(path, &architecture) + == B_OK) { + // verify that it is one of the sibling architectures + for (size_t i = 0; i < kSiblingArchitectureCount; i++) { + if (strcmp(architecture, kSiblingArchitectures[i]) == 0) + return kSiblingArchitectures[i]; + } + } + + // guess from the given path + architecture = __guess_secondary_architecture_from_path(path, + kSiblingArchitectures, kSiblingArchitectureCount); + + return architecture != NULL && has_secondary_architecture(architecture) + ? architecture : kPrimaryArchitecture; +} + + +B_DEFINE_WEAK_ALIAS(__get_architecture, get_architecture); +B_DEFINE_WEAK_ALIAS(__get_primary_architecture, get_primary_architecture); +B_DEFINE_WEAK_ALIAS(__get_secondary_architectures, get_secondary_architectures); +B_DEFINE_WEAK_ALIAS(__guess_architecture_for_path, guess_architecture_for_path); diff --git a/src/system/libroot/os/Jamfile b/src/system/libroot/os/Jamfile index 9e5809a871..1b2b30ce18 100644 --- a/src/system/libroot/os/Jamfile +++ b/src/system/libroot/os/Jamfile @@ -14,6 +14,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { SEARCH_SOURCE += [ FDirName $(SUBDIR) locks ] ; MergeObject <$(architecture)>os_main.o : + Architecture.cpp area.c atomic.c debug.c diff --git a/src/system/libroot/os/find_paths.cpp b/src/system/libroot/os/find_paths.cpp index 384f4cd2cb..f3360a2917 100644 --- a/src/system/libroot/os/find_paths.cpp +++ b/src/system/libroot/os/find_paths.cpp @@ -11,8 +11,11 @@ #include #include +#include + #include +#include #include #include @@ -28,7 +31,70 @@ static size_t kHomeInstallationLocationIndex = 1; static size_t kInstallationLocationCount = sizeof(kInstallationLocations) / sizeof(kInstallationLocations[0]); +static const path_base_directory kArchitectureSpecificBaseDirectories[] = { + B_FIND_PATH_ADD_ONS_DIRECTORY, + B_FIND_PATH_BIN_DIRECTORY, + B_FIND_PATH_DEVELOP_LIB_DIRECTORY, + B_FIND_PATH_HEADERS_DIRECTORY, +}; +static size_t kArchitectureSpecificBaseDirectoryCount = + sizeof(kArchitectureSpecificBaseDirectories) + / sizeof(kArchitectureSpecificBaseDirectories[0]); + + +namespace { + +struct PathBuffer { + PathBuffer(char* buffer, size_t size) + : + fBuffer(buffer), + fSize(size), + fLength(0) + { + if (fSize > 0) + fBuffer[0] = '\0'; + } + + bool Append(const char* toAppend, size_t length) + { + if (fLength < fSize) { + size_t toCopy = std::min(length, fSize - fLength); + if (toCopy > 0) { + memcpy(fBuffer + fLength, toAppend, toCopy); + fBuffer[fLength + toCopy] = '\0'; + } + } + + fLength += length; + return fLength < fSize; + } + + bool Append(const char* toAppend) + { + return Append(toAppend, strlen(toAppend)); + } + + size_t Length() const + { + return fLength; + } + +private: + char* fBuffer; + size_t fSize; + size_t fLength; +}; + +} + + + +/*! Returns the installation location relative path for the given base directory + constant and installation location index. A '%' in the returned path must be + replaced by "" for the primary architecture and by "/" for a secondary + architecture. + */ static const char* get_relative_directory_path(size_t installationLocationIndex, path_base_directory baseDirectory) @@ -37,11 +103,11 @@ get_relative_directory_path(size_t installationLocationIndex, case B_FIND_PATH_INSTALLATION_LOCATION_DIRECTORY: return ""; case B_FIND_PATH_ADD_ONS_DIRECTORY: - return "/add-ons"; + return "/add-ons%"; case B_FIND_PATH_APPS_DIRECTORY: return "/apps"; case B_FIND_PATH_BIN_DIRECTORY: - return "/bin"; + return "/bin%"; case B_FIND_PATH_BOOT_DIRECTORY: return "/boot"; case B_FIND_PATH_CACHE_DIRECTORY: @@ -51,7 +117,7 @@ get_relative_directory_path(size_t installationLocationIndex, case B_FIND_PATH_DEVELOP_DIRECTORY: return "/develop"; case B_FIND_PATH_DEVELOP_LIB_DIRECTORY: - return "/develop/lib"; + return "/develop/lib%"; case B_FIND_PATH_DOCUMENTATION_DIRECTORY: return "/documentation"; case B_FIND_PATH_ETC_DIRECTORY: @@ -59,7 +125,7 @@ get_relative_directory_path(size_t installationLocationIndex, case B_FIND_PATH_FONTS_DIRECTORY: return "/data/fonts"; case B_FIND_PATH_HEADERS_DIRECTORY: - return "/develop/headers"; + return "/develop/headers%"; case B_FIND_PATH_LIB_DIRECTORY: return "/lib"; case B_FIND_PATH_LOG_DIRECTORY: @@ -80,7 +146,7 @@ get_relative_directory_path(size_t installationLocationIndex, case B_FIND_PATH_SPOOL_DIRECTORY: return "/var/spool"; case B_FIND_PATH_TRANSLATORS_DIRECTORY: - return "/add-ons/Translators"; + return "/add-ons%/Translators"; case B_FIND_PATH_VAR_DIRECTORY: return "/var"; @@ -183,6 +249,73 @@ normalize_path(const char* path, char* buffer, size_t bufferSize) } +static status_t +normalize_longest_existing_path_prefix(const char* path, char* buffer, + size_t bufferSize) +{ + if (strlcpy(buffer, path, bufferSize) >= bufferSize) + return B_NAME_TOO_LONG; + + // Until we have an existing path, chop off leaf components. + for (;;) { + struct stat st; + if (lstat(buffer, &st) == 0) + break; + + // Chop off the leaf, but fail, it it's "..", since then we'd actually + // construct a subpath. + char* lastSlash = strrchr(buffer, '/'); + if (lastSlash == NULL || strcmp(lastSlash + 1, "..") == 0) + return B_ENTRY_NOT_FOUND; + + *lastSlash = '\0'; + } + + // normalize the existing prefix path + size_t prefixLength = strlen(buffer); + status_t error = normalize_path(buffer, buffer, bufferSize); + if (error != B_OK) + return error; + + // Re-append the non-existent suffix. Remove duplicate slashes and "." + // components. + const char* bufferEnd = buffer + bufferSize; + char* end = buffer + strlen(buffer); + const char* remainder = path + prefixLength + 1; + while (*remainder != '\0') { + // find component start + if (*remainder == '/') { + remainder++; + continue; + } + + // find component end + const char* componentEnd = strchr(remainder, '/'); + if (componentEnd == NULL) + componentEnd = remainder + strlen(remainder); + + // skip "." components + size_t componentLength = componentEnd - remainder; + if (componentLength == 1 && *remainder == '.') { + remainder++; + continue; + } + + // append the component + if (end + 1 + componentLength >= bufferEnd) + return B_BUFFER_OVERFLOW; + + *end++ = '/'; + memcpy(end, remainder, componentLength); + end += componentLength; + remainder += componentLength; + } + + *end = '\0'; + return B_OK; +} + + static const char* get_installation_location(const char* path, size_t& _index) { @@ -238,21 +371,38 @@ normalize_dependency(const char* dependency, char* buffer, size_t bufferSize) static ssize_t -process_path(const char* installationLocation, const char* relativePath, - const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize) +process_path(const char* installationLocation, const char* architecture, + const char* relativePath, const char* subPath, uint32 flags, + char* pathBuffer, size_t bufferSize) { - size_t totalLength; + // copy the installation location + PathBuffer buffer(pathBuffer, bufferSize); + buffer.Append(installationLocation); + + // append the relative path, expanding the architecture placeholder + if (const char* placeholder = strchr(relativePath, '%')) { + buffer.Append(relativePath, placeholder - relativePath); + + if (architecture != NULL) { + buffer.Append("/", 1); + buffer.Append(architecture); + } + + buffer.Append(placeholder + 1); + } else + buffer.Append(relativePath); + + // append subpath, if given if (subPath != NULL) { - totalLength = snprintf(pathBuffer, bufferSize, "%s%s/%s", - installationLocation, relativePath, subPath); - } else { - totalLength = snprintf(pathBuffer, bufferSize, "%s%s", - installationLocation, relativePath); + buffer.Append("/", 1); + buffer.Append(subPath); } + size_t totalLength = buffer.Length(); if (totalLength >= bufferSize) return B_BUFFER_OVERFLOW; + // handle the flags char* path = pathBuffer; status_t error = B_OK; @@ -283,9 +433,13 @@ process_path(const char* installationLocation, const char* relativePath, status_t internal_path_for_path(char* referencePath, size_t referencePathSize, - const char* dependency, path_base_directory baseDirectory, - const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize) + const char* dependency, const char* architecture, + path_base_directory baseDirectory, const char* subPath, uint32 flags, + char* pathBuffer, size_t bufferSize) { + if (strcmp(architecture, __get_primary_architecture()) == 0) + architecture = NULL; + // normalize status_t error = normalize_path(referencePath, referencePath, referencePathSize); @@ -359,8 +513,8 @@ internal_path_for_path(char* referencePath, size_t referencePathSize, if (relativePath == NULL) return B_BAD_VALUE; - ssize_t pathSize = process_path(installationLocation, relativePath, subPath, - flags, pathBuffer, bufferSize); + ssize_t pathSize = process_path(installationLocation, architecture, + relativePath, subPath, flags, pathBuffer, bufferSize); if (pathSize <= 0) return pathSize == 0 ? B_ENTRY_NOT_FOUND : pathSize; return B_OK; @@ -371,9 +525,18 @@ internal_path_for_path(char* referencePath, size_t referencePathSize, status_t -__find_path(const void* codePointer, const char* dependency, - path_base_directory baseDirectory, const char* subPath, uint32 flags, - char* pathBuffer, size_t bufferSize) +__find_path(const void* codePointer, path_base_directory baseDirectory, + const char* subPath, char* pathBuffer, size_t bufferSize) +{ + return __find_path_etc(codePointer, NULL, NULL, baseDirectory, subPath, 0, + pathBuffer, bufferSize); +} + + +status_t +__find_path_etc(const void* codePointer, const char* dependency, + const char* architecture, path_base_directory baseDirectory, + const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize) { if (pathBuffer == NULL) return B_BAD_VALUE; @@ -384,15 +547,28 @@ __find_path(const void* codePointer, const char* dependency, if (error != B_OK) return error; + if (architecture == NULL) + architecture = __get_architecture(); + return internal_path_for_path(imageInfo.name, sizeof(imageInfo.name), - dependency, baseDirectory, subPath, flags, pathBuffer, bufferSize); + dependency, architecture, baseDirectory, subPath, flags, pathBuffer, + bufferSize); } status_t -__find_path_for_path(const char* path, const char* dependency, - path_base_directory baseDirectory, const char* subPath, uint32 flags, - char* pathBuffer, size_t bufferSize) +__find_path_for_path(const char* path, path_base_directory baseDirectory, + const char* subPath, char* pathBuffer, size_t bufferSize) +{ + return __find_path_for_path_etc(path, NULL, NULL, baseDirectory, subPath, 0, + pathBuffer, bufferSize); +} + + +status_t +__find_path_for_path_etc(const char* path, const char* dependency, + const char* architecture, path_base_directory baseDirectory, + const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize) { char referencePath[B_PATH_NAME_LENGTH]; if (strlcpy(referencePath, path, sizeof(referencePath)) @@ -400,18 +576,42 @@ __find_path_for_path(const char* path, const char* dependency, return B_NAME_TOO_LONG; } + if (architecture == NULL) + architecture = __guess_architecture_for_path(path); + return internal_path_for_path(referencePath, sizeof(referencePath), - dependency, baseDirectory, subPath, flags, pathBuffer, bufferSize); + dependency, architecture, baseDirectory, subPath, flags, pathBuffer, + bufferSize); } status_t __find_paths(path_base_directory baseDirectory, const char* subPath, - uint32 flags, char*** _paths, size_t* _pathCount) + char*** _paths, size_t* _pathCount) +{ + return __find_paths_etc(NULL, baseDirectory, subPath, 0, _paths, + _pathCount); +} + + +status_t +__find_paths_etc(const char* architecture, path_base_directory baseDirectory, + const char* subPath, uint32 flags, char*** _paths, size_t* _pathCount) { if (_paths == NULL || _pathCount == NULL) return B_BAD_VALUE; + // Analyze architecture. If NULL, use the caller's architecture. If the + // effective architecture is the primary one, set architecture to NULL to + // indicate that we don't need to insert an architecture subdirectory + // component. + if (architecture == NULL) + architecture = __get_architecture(); + if (strcmp(architecture, __get_primary_architecture()) == 0) + architecture = NULL; + size_t architectureSize = architecture != NULL + ? strlen(architecture) + 1 : 0; + size_t subPathLength = subPath != NULL ? strlen(subPath) + 1 : 0; // Get the relative paths and compute the total size to allocate. @@ -425,6 +625,8 @@ __find_paths(path_base_directory baseDirectory, const char* subPath, totalSize += strlen(kInstallationLocations[i]) + strlen(relativePaths[i]) + subPathLength + 1; + if (strchr(relativePaths[i], '%') != NULL) + totalSize += architectureSize - 1; } // allocate storage @@ -440,7 +642,7 @@ __find_paths(path_base_directory baseDirectory, const char* subPath, const char* pathBufferEnd = pathBuffer + totalSize; for (size_t i = 0; i < kInstallationLocationCount; i++) { ssize_t pathSize = process_path(kInstallationLocations[i], - relativePaths[i], subPath, flags, pathBuffer, + architecture, relativePaths[i], subPath, flags, pathBuffer, pathBufferEnd - pathBuffer); if (pathSize < 0) return pathSize; @@ -461,6 +663,65 @@ __find_paths(path_base_directory baseDirectory, const char* subPath, } +const char* +__guess_secondary_architecture_from_path(const char* path, + const char* const* secondaryArchitectures, + size_t secondaryArchitectureCount) +{ + // Get the longest existing prefix path and normalize it. + char prefix[B_PATH_NAME_LENGTH]; + if (normalize_longest_existing_path_prefix(path, prefix, sizeof(prefix)) + != B_OK) { + return NULL; + } + + // get an installation location relative path + size_t installationLocationIndex; + const char* installationLocation = get_installation_location(prefix, + installationLocationIndex); + if (installationLocation == NULL) + return NULL; + + const char* relativePath = prefix + strlen(installationLocation); + if (relativePath[0] != '/') + return NULL; + + // Iterate through the known paths that would indicate a secondary + // architecture and try to match them with our given path. + for (size_t i = 0; i < kArchitectureSpecificBaseDirectoryCount; i++) { + const char* basePath = get_relative_directory_path( + installationLocationIndex, kArchitectureSpecificBaseDirectories[i]); + const char* placeholder = strchr(basePath, '%'); + if (placeholder == NULL) + continue; + + // match the part up to the architecture placeholder + size_t prefixLength = placeholder - basePath; + if (strncmp(relativePath, basePath, prefixLength) != 0 + || relativePath[prefixLength] != '/') { + continue; + } + + // match the architecture + const char* architecturePart = relativePath + prefixLength + 1; + for (size_t k = 0; k < secondaryArchitectureCount; k++) { + const char* architecture = secondaryArchitectures[k]; + size_t architectureLength = strlen(architecture); + if (strncmp(architecturePart, architecture, architectureLength) == 0 + && (architecturePart[architectureLength] == '/' + || architecturePart[architectureLength] == '\0')) { + return architecture; + } + } + } + + return NULL; +} + + B_DEFINE_WEAK_ALIAS(__find_path, find_path); +B_DEFINE_WEAK_ALIAS(__find_path_etc, find_path_etc); B_DEFINE_WEAK_ALIAS(__find_path_for_path, find_path_for_path); +B_DEFINE_WEAK_ALIAS(__find_path_for_path_etc, find_path_for_path_etc); B_DEFINE_WEAK_ALIAS(__find_paths, find_paths); +B_DEFINE_WEAK_ALIAS(__find_paths_etc, find_paths_etc);