Example #1
0
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;
}