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 installation locations InstallationLocations* installationLocations = InstallationLocations::Get(); MethodDeleter<InstallationLocations> installationLocationsDeleter( installationLocations, &InstallationLocations::Put); // Get the relative paths and compute the total size to allocate. const char* relativePaths[InstallationLocations::kCount]; size_t totalSize = 0; for (size_t i = 0; i < InstallationLocations::kCount; i++) { if (((flags & B_FIND_PATHS_USER_ONLY) != 0 && !installationLocations->IsUserIndex(i)) || ((flags & B_FIND_PATHS_SYSTEM_ONLY) != 0 && !installationLocations->IsSystemIndex(i))) continue; relativePaths[i] = get_relative_directory_path(i, baseDirectory); if (relativePaths[i] == NULL) return B_BAD_VALUE; totalSize += strlen(installationLocations->At(i)) + strlen(relativePaths[i]) + subPathLength + 1; if (strchr(relativePaths[i], '%') != NULL) totalSize += architectureSize - 1; } // allocate storage char** paths = (char**)malloc(sizeof(char*) * InstallationLocations::kCount + totalSize); if (paths == NULL) return B_NO_MEMORY; MemoryDeleter pathsDeleter(paths); // construct and process the paths size_t count = 0; char* pathBuffer = (char*)(paths + InstallationLocations::kCount); const char* pathBufferEnd = pathBuffer + totalSize; for (size_t i = 0; i < InstallationLocations::kCount; i++) { if (((flags & B_FIND_PATHS_USER_ONLY) != 0 && !installationLocations->IsUserIndex(i)) || ((flags & B_FIND_PATHS_SYSTEM_ONLY) != 0 && !installationLocations->IsSystemIndex(i))) continue; ssize_t pathSize = process_path(installationLocations->At(i), architecture, relativePaths[i], subPath, flags, pathBuffer, pathBufferEnd - pathBuffer); if (pathSize < 0) return pathSize; if (pathSize > 0) { paths[count++] = pathBuffer; pathBuffer += pathSize; } } if (count == 0) return B_ENTRY_NOT_FOUND; *_paths = paths; *_pathCount = count; pathsDeleter.Detach(); return B_OK; }
status_t __find_directory(directory_which which, dev_t device, bool createIt, char *returnedPath, int32 _pathLength) { if (_pathLength <= 0) return E2BIG; size_t pathLength = _pathLength; status_t err = B_OK; dev_t bootDevice = -1; struct fs_info fsInfo; struct stat st; const char *templatePath = NULL; /* as with the R5 version, no on-stack buffer */ char *buffer = (char*)malloc(pathLength); if (buffer == NULL) return B_NO_MEMORY; MemoryDeleter bufferDeleter(buffer); memset(buffer, 0, pathLength); /* fiddle with non-boot volume for items that need it */ switch (which) { case B_DESKTOP_DIRECTORY: case B_TRASH_DIRECTORY: bootDevice = dev_for_path("/boot"); if (device <= 0) device = bootDevice; if (fs_stat_dev(device, &fsInfo) != B_OK) return ENODEV; if (device != bootDevice) { #ifdef _KERNEL_MODE err = _user_entry_ref_to_path(device, fsInfo.root, /*"."*/ NULL, buffer, pathLength); #else err = _kern_entry_ref_to_path(device, fsInfo.root, /*"."*/ NULL, buffer, pathLength); #endif if (err != B_OK) return err; } else { /* use the user id to find the home folder */ /* done later */ strlcat(buffer, "/boot", pathLength); } break; case B_PACKAGE_LINKS_DIRECTORY: // this is a directory living in rootfs break; default: strlcat(buffer, "/boot", pathLength); break; } switch ((int)which) { /* Per volume directories */ case B_DESKTOP_DIRECTORY: if (device == bootDevice || !strcmp(fsInfo.fsh_name, "bfs")) templatePath = "$h/Desktop"; break; case B_TRASH_DIRECTORY: // TODO: eventually put that into the file system API? if (device == bootDevice || !strcmp(fsInfo.fsh_name, "bfs")) templatePath = "trash"; // TODO: add suffix for current user else if (!strcmp(fsInfo.fsh_name, "fat")) templatePath = "RECYCLED/_BEOS_"; break; /* Haiku system directories */ case B_SYSTEM_DIRECTORY: case B_BEOS_SYSTEM_DIRECTORY: case B_SYSTEM_ADDONS_DIRECTORY: case B_SYSTEM_BOOT_DIRECTORY: case B_SYSTEM_FONTS_DIRECTORY: case B_SYSTEM_LIB_DIRECTORY: case B_SYSTEM_SERVERS_DIRECTORY: case B_SYSTEM_APPS_DIRECTORY: case B_SYSTEM_BIN_DIRECTORY: case B_BEOS_ETC_DIRECTORY: case B_SYSTEM_DOCUMENTATION_DIRECTORY: case B_SYSTEM_PREFERENCES_DIRECTORY: case B_SYSTEM_TRANSLATORS_DIRECTORY: case B_SYSTEM_MEDIA_NODES_DIRECTORY: case B_SYSTEM_SOUNDS_DIRECTORY: case B_SYSTEM_DATA_DIRECTORY: case B_SYSTEM_DEVELOP_DIRECTORY: case B_SYSTEM_PACKAGES_DIRECTORY: case B_SYSTEM_HEADERS_DIRECTORY: templatePath = kSystemDirectories[which - B_SYSTEM_DIRECTORY]; break; /* Obsolete common directories and writable system directories */ case B_COMMON_DIRECTORY: case B_COMMON_SYSTEM_DIRECTORY: case B_COMMON_ADDONS_DIRECTORY: case B_COMMON_BOOT_DIRECTORY: case B_COMMON_FONTS_DIRECTORY: case B_COMMON_LIB_DIRECTORY: case B_COMMON_SERVERS_DIRECTORY: case B_COMMON_BIN_DIRECTORY: case B_SYSTEM_ETC_DIRECTORY: case B_COMMON_DOCUMENTATION_DIRECTORY: case B_SYSTEM_SETTINGS_DIRECTORY: case B_COMMON_DEVELOP_DIRECTORY: case B_SYSTEM_LOG_DIRECTORY: case B_SYSTEM_SPOOL_DIRECTORY: case B_SYSTEM_TEMP_DIRECTORY: case B_SYSTEM_VAR_DIRECTORY: case B_COMMON_TRANSLATORS_DIRECTORY: case B_COMMON_MEDIA_NODES_DIRECTORY: case B_COMMON_SOUNDS_DIRECTORY: case B_COMMON_DATA_DIRECTORY: case B_SYSTEM_CACHE_DIRECTORY: case B_COMMON_PACKAGES_DIRECTORY: case B_COMMON_HEADERS_DIRECTORY: case B_SYSTEM_NONPACKAGED_DIRECTORY: case B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY: case B_SYSTEM_NONPACKAGED_TRANSLATORS_DIRECTORY: case B_SYSTEM_NONPACKAGED_MEDIA_NODES_DIRECTORY: case B_SYSTEM_NONPACKAGED_BIN_DIRECTORY: case B_SYSTEM_NONPACKAGED_DATA_DIRECTORY: case B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY: case B_SYSTEM_NONPACKAGED_SOUNDS_DIRECTORY: case B_SYSTEM_NONPACKAGED_DOCUMENTATION_DIRECTORY: case B_SYSTEM_NONPACKAGED_LIB_DIRECTORY: case B_SYSTEM_NONPACKAGED_HEADERS_DIRECTORY: case B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY: templatePath = kCommonDirectories[which - B_COMMON_DIRECTORY]; break; /* User directories */ case B_USER_DIRECTORY: case B_USER_CONFIG_DIRECTORY: case B_USER_ADDONS_DIRECTORY: case B_USER_BOOT_DIRECTORY: case B_USER_FONTS_DIRECTORY: case B_USER_LIB_DIRECTORY: case B_USER_SETTINGS_DIRECTORY: case B_USER_DESKBAR_DIRECTORY: case B_USER_PRINTERS_DIRECTORY: case B_USER_TRANSLATORS_DIRECTORY: case B_USER_MEDIA_NODES_DIRECTORY: case B_USER_SOUNDS_DIRECTORY: case B_USER_DATA_DIRECTORY: case B_USER_CACHE_DIRECTORY: case B_USER_PACKAGES_DIRECTORY: case B_USER_HEADERS_DIRECTORY: case B_USER_DEVELOP_DIRECTORY: case B_USER_DOCUMENTATION_DIRECTORY: case B_USER_NONPACKAGED_DIRECTORY: case B_USER_NONPACKAGED_ADDONS_DIRECTORY: case B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY: case B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY: case B_USER_NONPACKAGED_BIN_DIRECTORY: case B_USER_NONPACKAGED_DATA_DIRECTORY: case B_USER_NONPACKAGED_FONTS_DIRECTORY: case B_USER_NONPACKAGED_SOUNDS_DIRECTORY: case B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY: case B_USER_NONPACKAGED_LIB_DIRECTORY: case B_USER_NONPACKAGED_HEADERS_DIRECTORY: case B_USER_NONPACKAGED_DEVELOP_DIRECTORY: case B_USER_SERVERS_DIRECTORY: case B_USER_APPS_DIRECTORY: case B_USER_BIN_DIRECTORY: case B_USER_PREFERENCES_DIRECTORY: case B_USER_ETC_DIRECTORY: case B_USER_LOG_DIRECTORY: case B_USER_SPOOL_DIRECTORY: case B_USER_VAR_DIRECTORY: templatePath = kUserDirectories[which - B_USER_DIRECTORY]; break; /* Global directories */ case B_APPS_DIRECTORY: case B_UTILITIES_DIRECTORY: templatePath = SYSTEM "/apps"; break; case B_PREFERENCES_DIRECTORY: templatePath = SYSTEM "/preferences"; break; case B_PACKAGE_LINKS_DIRECTORY: templatePath = "packages"; break; default: return EINVAL; } if (templatePath == NULL) return ENOENT; PathBuffer pathBuffer(buffer, pathLength, strlen(buffer)); // resolve "$h" placeholder to the user's home directory if (!strncmp(templatePath, "$h", 2)) { if (bootDevice > -1 && device != bootDevice) { pathBuffer.Append("/home"); } else { size_t length = get_user_home_path(buffer, pathLength); if (length >= pathLength) return E2BIG; pathBuffer.SetTo(buffer, pathLength, length); } templatePath += 2; } else if (templatePath[0] != '\0') pathBuffer.Append('/'); // resolve "$a" placeholder to the architecture subdirectory, if not // primary if (char* dollar = strchr(templatePath, '$')) { if (dollar[1] == 'a') { pathBuffer.Append(templatePath, dollar - templatePath); #ifndef _KERNEL_MODE const char* architecture = __get_architecture(); if (strcmp(architecture, __get_primary_architecture()) != 0) { pathBuffer.Append('/'); pathBuffer.Append(architecture); } #endif templatePath = dollar + 2; } } // append (remainder of) template path pathBuffer.Append(templatePath); if (pathBuffer.Length() >= pathLength) return E2BIG; if (createIt && stat(buffer, &st) < 0) { err = create_path(buffer, 0755); if (err != B_OK) return err; } strlcpy(returnedPath, buffer, pathLength); return B_OK; }
status_t internal_path_for_path(char* referencePath, size_t referencePathSize, 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; // resolve dependency char packageName[B_FILE_NAME_LENGTH]; // Temporarily used here, permanently used below where // B_FIND_PATH_PACKAGE_PATH is handled. if (dependency != NULL) { // get the versioned package name status_t error = get_file_attribute(referencePath, "SYS:PACKAGE", packageName, sizeof(packageName)); if (error != B_OK) return error; // normalize the dependency name char normalizedDependency[B_FILE_NAME_LENGTH]; error = normalize_dependency(dependency, normalizedDependency, sizeof(normalizedDependency)); if (error != B_OK) return error; // Compute the path of the dependency symlink. This will yield the // installation location path when normalized. if (snprintf(referencePath, referencePathSize, kSystemPackageLinksDirectory "/%s/%s", packageName, normalizedDependency) >= (ssize_t)referencePathSize) { return B_BUFFER_OVERFLOW; } } // handle B_FIND_PATH_IMAGE_PATH if (baseDirectory == B_FIND_PATH_IMAGE_PATH) return copy_path(referencePath, pathBuffer, bufferSize); // Handle B_FIND_PATH_PACKAGE_PATH: get the package file name and // simply adjust our arguments to look the package file up in the packages // directory. if (baseDirectory == B_FIND_PATH_PACKAGE_PATH) { status_t error = get_file_attribute(referencePath, "SYS:PACKAGE_FILE", packageName, sizeof(packageName)); if (error != B_OK) return error; dependency = NULL; subPath = packageName; baseDirectory = B_FIND_PATH_PACKAGES_DIRECTORY; flags = B_FIND_PATH_EXISTING_ONLY; } // normalize status_t error = normalize_path(referencePath, referencePath, referencePathSize); if (error != B_OK) return error; // get the installation location InstallationLocations* installationLocations = InstallationLocations::Get(); MethodDeleter<InstallationLocations> installationLocationsDeleter( installationLocations, &InstallationLocations::Put); size_t installationLocationIndex; const char* installationLocation = installationLocations->LocationFor( referencePath, installationLocationIndex); if (installationLocation == NULL) return B_ENTRY_NOT_FOUND; // get base dir and process the path const char* relativePath = get_relative_directory_path( installationLocationIndex, baseDirectory); if (relativePath == NULL) return B_BAD_VALUE; 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; }