haiku/src/system/libroot/os/find_directory.c
Axel Dörfler 317bd7dda3 * Changed directory structure as suggested on the mailing list.
* Made the TimeZoneView less error prone, and also actually use Haiku code (the
  previous check didn't work since it used #if, not #ifdef).
* Also took the liberty to rename our boot loader to haiku_loader, since I had
  to update the nasm binary anyway. Updated the assembly sources to nasm 2.0.
* I haven't found where the synth location in the MIDI code is specified,
  though.
* Also, NetBootArchive, and FloppyBootImage haven't been updated yet. Will do
  so next.
* Some optional packages still put their license to beos/etc/licenses. I didn't
  update them yet, as we'll probably do so anyway at some point. Also, I think
  we might want to introduce a common/data/licenses instead for those.
* If you encounter any problems, please tell!


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29876 a95241bf-73f2-0310-859d-f6bbb57e9c96
2009-04-03 09:02:44 +00:00

335 lines
7.9 KiB
C

/*
* Copyright 2004, François Revol.
* Copyright 2007-2009, Axel Dörfler, axeld@pinc-software.de.
*
* Distributed under the terms of the MIT license.
*/
// TODO: this call is currently compiled for the kernel and libroot separately;
// they may not always return the same directory right now!
#ifdef _KERNEL_MODE
# include <vfs.h>
#else
# include <syscalls.h>
#endif
#include <FindDirectory.h>
#include <fs_info.h>
#include <errno.h>
#include <pwd.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <user_group.h>
/* use pwents to find home */
#define USE_PWENTS
/* Haiku system directories */
#define SYSTEM "system"
static const char *kSystemDirectories[] = {
SYSTEM, // B_SYSTEM_DIRECTORY
SYSTEM, // B_BEOS_SYSTEM_DIRECTORY
SYSTEM "/add-ons",
SYSTEM "/boot",
SYSTEM "/fonts",
SYSTEM "/lib",
SYSTEM "/servers",
SYSTEM "/apps",
SYSTEM "/bin",
SYSTEM "/etc",
SYSTEM "/documentation",
SYSTEM "/preferences",
SYSTEM "/add-ons/Translators",
SYSTEM "/add-ons/media",
SYSTEM "/data/sounds",
SYSTEM "/data",
};
/* Common directories, shared among users */
#define COMMON "common"
// ToDo: this is for now and might be changed back to "home"
// (or even something else) later
static const char *kCommonDirectories[] = {
COMMON "", // B_COMMON_DIRECTORY
COMMON "", // B_COMMON_SYSTEM_DIRECTORY
COMMON "/add-ons",
COMMON "/boot",
COMMON "/fonts",
COMMON "/lib",
COMMON "/servers",
COMMON "/bin",
COMMON "/etc",
COMMON "/documentation",
COMMON "/settings",
"develop", // B_COMMON_DEVELOP_DIRECTORY
"var/log", // B_COMMON_LOG_DIRECTORY
"var/spool", // B_COMMON_SPOOL_DIRECTORY
"var/tmp", // B_COMMON_TEMP_DIRECTORY
"var", // B_COMMON_VAR_DIRECTORY
COMMON "/add-ons/Translators",
COMMON "/add-ons/media",
COMMON "/data/sounds",
COMMON "/data",
};
/* User directories */
#define HOME "$h"
static const char *kUserDirectories[] = {
HOME "", // B_USER_DIRECTORY
HOME "/config", // B_USER_CONFIG_DIRECTORY
HOME "/config/add-ons",
HOME "/config/boot",
HOME "/config/fonts",
HOME "/config/lib",
HOME "/config/settings",
HOME "/config/be",
HOME "/config/settings/printers",
HOME "/config/add-ons/Translators",
HOME "/config/add-ons/media",
HOME "/config/data/sounds",
HOME "/config/data",
HOME "/config/cache",
};
/*! make dir and its parents if needed */
static int
create_path(const char *path, mode_t mode)
{
char buffer[B_PATH_NAME_LENGTH + 1];
int pathLength;
int i = 0;
if (path == NULL || ((pathLength = strlen(path)) > B_PATH_NAME_LENGTH))
return EINVAL;
while (++i < pathLength) {
char *slash = strchr(&path[i], '/');
struct stat st;
if (slash == NULL)
i = pathLength;
else if (i != slash - path)
i = slash - path;
else
continue;
strlcpy(buffer, path, i + 1);
if (stat(buffer, &st) < 0) {
errno = 0;
if (mkdir(buffer, mode) < 0)
return errno;
}
}
return 0;
}
// #pragma mark -
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;
char *home = NULL;
const char *template = 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;
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"))
template = "$h/Desktop";
break;
case B_TRASH_DIRECTORY:
// TODO: eventually put that into the file system API?
if (device == bootDevice || !strcmp(fsInfo.fsh_name, "bfs"))
template = "$h/Desktop/Trash";
else if (!strcmp(fsInfo.fsh_name, "dos"))
template = "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_SYSTEM_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:
template = 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:
template = 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:
template = kUserDirectories[which - B_USER_DIRECTORY];
break;
/* Global directories */
case B_APPS_DIRECTORY:
template = "apps";
break;
case B_PREFERENCES_DIRECTORY:
template = "preferences";
break;
case B_UTILITIES_DIRECTORY:
template = "utilities";
break;
default:
free(buffer);
return EINVAL;
}
err = B_OK;
if (template) {
if (!strncmp(template, "$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 = "/boot/home";
strncpy(buffer, home, pathLength);
}
template += 2;
} else
strlcat(buffer, "/", pathLength);
if (!err && strlen(buffer) + 2 + strlen(template) < (uint32)pathLength)
strcat(buffer, template);
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;
}