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 find_directory(directory_which which, dev_t device, bool createIt, char *returnedPath, int32 pathLength) { status_t err = B_OK; dev_t bootDevice = -1; struct fs_info fsInfo; struct stat st; char *buffer = NULL; const char *home = NULL; const char *templatePath = NULL; /* as with the R5 version, no on-stack buffer */ buffer = (char *)malloc(pathLength); 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) { free(buffer); 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 } 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; } if (err < B_OK) { free(buffer); return err; } switch (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; /* Common directories, shared among users */ 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_COMMON_ETC_DIRECTORY: case B_COMMON_DOCUMENTATION_DIRECTORY: case B_COMMON_SETTINGS_DIRECTORY: case B_COMMON_DEVELOP_DIRECTORY: case B_COMMON_LOG_DIRECTORY: case B_COMMON_SPOOL_DIRECTORY: case B_COMMON_TEMP_DIRECTORY: case B_COMMON_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_COMMON_CACHE_DIRECTORY: case B_COMMON_PACKAGES_DIRECTORY: case B_COMMON_HEADERS_DIRECTORY: case B_COMMON_NONPACKAGED_DIRECTORY: case B_COMMON_NONPACKAGED_ADDONS_DIRECTORY: case B_COMMON_NONPACKAGED_TRANSLATORS_DIRECTORY: case B_COMMON_NONPACKAGED_MEDIA_NODES_DIRECTORY: case B_COMMON_NONPACKAGED_BIN_DIRECTORY: case B_COMMON_NONPACKAGED_DATA_DIRECTORY: case B_COMMON_NONPACKAGED_FONTS_DIRECTORY: case B_COMMON_NONPACKAGED_SOUNDS_DIRECTORY: case B_COMMON_NONPACKAGED_DOCUMENTATION_DIRECTORY: case B_COMMON_NONPACKAGED_LIB_DIRECTORY: case B_COMMON_NONPACKAGED_HEADERS_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_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: templatePath = kUserDirectories[which - B_USER_DIRECTORY]; break; /* Global directories */ case B_APPS_DIRECTORY: templatePath = "apps"; break; case B_PREFERENCES_DIRECTORY: templatePath = "preferences"; break; case B_UTILITIES_DIRECTORY: templatePath = "utilities"; break; case B_PACKAGE_LINKS_DIRECTORY: templatePath = "packages"; break; default: free(buffer); return EINVAL; } err = B_OK; if (templatePath) { if (!strncmp(templatePath, "$h", 2)) { if (bootDevice > -1 && device != bootDevice) { int l = pathLength - strlen(buffer); if (l > 5) strncat(buffer, "/home", 5); } else { #ifndef _KERNEL_MODE #ifdef USE_PWENTS struct passwd pwBuffer; char pwStringBuffer[MAX_PASSWD_BUFFER_SIZE]; struct passwd *pw; if (getpwuid_r(geteuid(), &pwBuffer, pwStringBuffer, sizeof(pwStringBuffer), &pw) == 0) { home = pw->pw_dir; } #endif // USE_PWENTS if (!home) { /* use env var */ home = getenv("HOME"); } #endif // !_KERNEL_MODE if (!home) home = kUserDirectory; strncpy(buffer, home, pathLength); } templatePath += 2; } else strlcat(buffer, "/", pathLength); if (!err && strlen(buffer) + 2 + strlen(templatePath) < (uint32)pathLength) { strcat(buffer, templatePath); } else err = err ? err : E2BIG; } else err = err ? err : ENOENT; if (!err && createIt && stat(buffer, &st) < 0) err = create_path(buffer, 0755); if (!err) strlcpy(returnedPath, buffer, pathLength); free(buffer); return err; }