1/* 2 * Copyright 2004, Fran��ois Revol. 3 * Copyright 2007-2010, Axel D��rfler, axeld@pinc-software.de. 4 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de> 5 * 6 * Distributed under the terms of the MIT license. 7 */ 8 9// TODO: this call is currently compiled for the kernel and libroot separately; 10// they may not always return the same directory right now! 11 12#ifdef _KERNEL_MODE 13# include <vfs.h> 14#else 15# include <syscalls.h> 16#endif 17 18#include <directories.h> 19#include <FindDirectory.h> 20#include <fs_info.h> 21 22#include <errno.h> 23#include <pwd.h> 24#include <string.h> 25#include <sys/stat.h> 26#include <stdlib.h> 27#include <unistd.h> 28 29#include <errno_private.h> 30#include <user_group.h> 31 32/* use pwents to find home */ 33#define USE_PWENTS 34 35 36/* 37 * If you change any of the directories below, please have a look at 38 * headers/private/libroot/directories.h and adjust that accordingly! 39 */ 40 41#define SYSTEM "system" 42#define COMMON "common" 43#define NON_PACKAGED "/non-packaged" 44 45 46/* Haiku system directories */ 47 48static const char *kSystemDirectories[] = { 49 SYSTEM, // B_SYSTEM_DIRECTORY 50 SYSTEM, // B_BEOS_SYSTEM_DIRECTORY 51 SYSTEM "/add-ons", 52 SYSTEM "/boot", 53 SYSTEM "/data/fonts", 54 SYSTEM "/lib", 55 SYSTEM "/servers", 56 SYSTEM "/apps", 57 SYSTEM "/bin", 58 COMMON "/etc", 59 SYSTEM "/documentation", 60 SYSTEM "/preferences", 61 SYSTEM "/add-ons/Translators", 62 SYSTEM "/add-ons/media", 63 SYSTEM "/data/sounds", 64 SYSTEM "/data", 65 "develop", 66 SYSTEM "/packages", 67 "develop/headers", 68}; 69 70/* Common directories, shared among users */ 71 72static const char *kCommonDirectories[] = { 73 COMMON, // B_COMMON_DIRECTORY 74 COMMON, // B_COMMON_SYSTEM_DIRECTORY 75 COMMON "/add-ons", 76 COMMON "/boot", 77 COMMON "/data/fonts", 78 COMMON "/lib", 79 COMMON "/servers", 80 COMMON "/bin", 81 COMMON "/etc", 82 COMMON "/documentation", 83 COMMON "/settings", 84 COMMON "/develop", // B_COMMON_DEVELOP_DIRECTORY 85 COMMON "/var/log", // B_COMMON_LOG_DIRECTORY 86 COMMON "/var/spool", // B_COMMON_SPOOL_DIRECTORY 87 COMMON "/cache/tmp", // B_COMMON_TEMP_DIRECTORY 88 COMMON "/var", // B_COMMON_VAR_DIRECTORY 89 COMMON "/add-ons/Translators", 90 COMMON "/add-ons/media", 91 COMMON "/data/sounds", 92 COMMON "/data", 93 COMMON "/cache", // B_COMMON_CACHE_DIRECTORY 94 COMMON "/packages", 95 COMMON "/include", 96 COMMON NON_PACKAGED, 97 COMMON NON_PACKAGED "/add-ons", 98 COMMON NON_PACKAGED "/add-ons/Translators", 99 COMMON NON_PACKAGED "/add-ons/media", 100 COMMON NON_PACKAGED "/bin", 101 COMMON NON_PACKAGED "/data", 102 COMMON NON_PACKAGED "/data/fonts", 103 COMMON NON_PACKAGED "/data/sounds", 104 COMMON NON_PACKAGED "/documentation", 105 COMMON NON_PACKAGED "/lib", 106 COMMON NON_PACKAGED "/develop/headers", 107}; 108 109/* User directories */ 110 111#define HOME "$h" 112#define CONFIG "/config" 113 114static const char *kUserDirectories[] = { 115 HOME, // B_USER_DIRECTORY 116 HOME CONFIG, // B_USER_CONFIG_DIRECTORY 117 HOME CONFIG "/add-ons", 118 HOME CONFIG "/boot", 119 HOME CONFIG "/data/fonts", 120 HOME CONFIG "/lib", 121 HOME CONFIG "/settings", 122 HOME CONFIG "/settings/deskbar", 123 HOME CONFIG "/settings/printers", 124 HOME CONFIG "/add-ons/Translators", 125 HOME CONFIG "/add-ons/media", 126 HOME CONFIG "/data/sounds", 127 HOME CONFIG "/data", 128 HOME CONFIG "/cache", 129 HOME CONFIG "/packages", 130 HOME CONFIG "/include", 131 HOME CONFIG NON_PACKAGED, 132 HOME CONFIG NON_PACKAGED "/add-ons", 133 HOME CONFIG NON_PACKAGED "/add-ons/Translators", 134 HOME CONFIG NON_PACKAGED "/add-ons/media", 135 HOME CONFIG NON_PACKAGED "/bin", 136 HOME CONFIG NON_PACKAGED "/data", 137 HOME CONFIG NON_PACKAGED "/data/fonts", 138 HOME CONFIG NON_PACKAGED "/data/sounds", 139 HOME CONFIG NON_PACKAGED "/documentation", 140 HOME CONFIG NON_PACKAGED "/lib", 141 HOME CONFIG NON_PACKAGED "/develop/headers", 142}; 143 144 145/*! make dir and its parents if needed */ 146static int 147create_path(const char *path, mode_t mode) 148{ 149 char buffer[B_PATH_NAME_LENGTH + 1]; 150 int pathLength; 151 int i = 0; 152 153 if (path == NULL || ((pathLength = strlen(path)) > B_PATH_NAME_LENGTH)) 154 return EINVAL; 155 156 while (++i < pathLength) { 157 char *slash = strchr(&path[i], '/'); 158 struct stat st; 159 160 if (slash == NULL) 161 i = pathLength; 162 else if (i != slash - path) 163 i = slash - path; 164 else 165 continue; 166 167 strlcpy(buffer, path, i + 1); 168 if (stat(buffer, &st) < 0) { 169 __set_errno(0); 170 if (mkdir(buffer, mode) < 0) 171 return errno; 172 } 173 } 174 175 return 0; 176} 177 178 179// #pragma mark - 180 181 182status_t 183find_directory(directory_which which, dev_t device, bool createIt, 184 char *returnedPath, int32 pathLength) 185{ 186 status_t err = B_OK; 187 dev_t bootDevice = -1; 188 struct fs_info fsInfo; 189 struct stat st; 190 char *buffer = NULL; 191 const char *home = NULL; 192 const char *templatePath = NULL; 193 194 /* as with the R5 version, no on-stack buffer */ 195 buffer = (char *)malloc(pathLength); 196 memset(buffer, 0, pathLength); 197 198 /* fiddle with non-boot volume for items that need it */ 199 switch (which) { 200 case B_DESKTOP_DIRECTORY: 201 case B_TRASH_DIRECTORY: 202 bootDevice = dev_for_path("/boot"); 203 if (device <= 0) 204 device = bootDevice; 205 if (fs_stat_dev(device, &fsInfo) < B_OK) { 206 free(buffer); 207 return ENODEV; 208 } 209 if (device != bootDevice) { 210#ifdef _KERNEL_MODE 211 err = _user_entry_ref_to_path(device, fsInfo.root, /*"."*/ 212 NULL, buffer, pathLength); 213#else 214 err = _kern_entry_ref_to_path(device, fsInfo.root, /*"."*/ 215 NULL, buffer, pathLength); 216#endif 217 } else { 218 /* use the user id to find the home folder */ 219 /* done later */ 220 strlcat(buffer, "/boot", pathLength); 221 } 222 break; 223 case B_PACKAGE_LINKS_DIRECTORY: 224 // this is a directory living in rootfs 225 break; 226 default: 227 strlcat(buffer, "/boot", pathLength); 228 break; 229 } 230 231 if (err < B_OK) { 232 free(buffer); 233 return err; 234 } 235 236 switch (which) { 237 /* Per volume directories */ 238 case B_DESKTOP_DIRECTORY: 239 if (device == bootDevice || !strcmp(fsInfo.fsh_name, "bfs")) 240 templatePath = "$h/Desktop"; 241 break; 242 case B_TRASH_DIRECTORY: 243 // TODO: eventually put that into the file system API? 244 if (device == bootDevice || !strcmp(fsInfo.fsh_name, "bfs")) 245 templatePath = "trash"; // TODO: add suffix for current user 246 else if (!strcmp(fsInfo.fsh_name, "fat")) 247 templatePath = "RECYCLED/_BEOS_"; 248 break; 249 250 /* Haiku system directories */ 251 case B_SYSTEM_DIRECTORY: 252 case B_BEOS_SYSTEM_DIRECTORY: 253 case B_SYSTEM_ADDONS_DIRECTORY: 254 case B_SYSTEM_BOOT_DIRECTORY: 255 case B_SYSTEM_FONTS_DIRECTORY: 256 case B_SYSTEM_LIB_DIRECTORY: 257 case B_SYSTEM_SERVERS_DIRECTORY: 258 case B_SYSTEM_APPS_DIRECTORY: 259 case B_SYSTEM_BIN_DIRECTORY: 260 case B_BEOS_ETC_DIRECTORY: 261 case B_SYSTEM_DOCUMENTATION_DIRECTORY: 262 case B_SYSTEM_PREFERENCES_DIRECTORY: 263 case B_SYSTEM_TRANSLATORS_DIRECTORY: 264 case B_SYSTEM_MEDIA_NODES_DIRECTORY: 265 case B_SYSTEM_SOUNDS_DIRECTORY: 266 case B_SYSTEM_DATA_DIRECTORY: 267 case B_SYSTEM_DEVELOP_DIRECTORY: 268 case B_SYSTEM_PACKAGES_DIRECTORY: 269 case B_SYSTEM_HEADERS_DIRECTORY: 270 templatePath = kSystemDirectories[which - B_SYSTEM_DIRECTORY]; 271 break; 272 273 /* Common directories, shared among users */ 274 case B_COMMON_DIRECTORY: 275 case B_COMMON_SYSTEM_DIRECTORY: 276 case B_COMMON_ADDONS_DIRECTORY: 277 case B_COMMON_BOOT_DIRECTORY: 278 case B_COMMON_FONTS_DIRECTORY: 279 case B_COMMON_LIB_DIRECTORY: 280 case B_COMMON_SERVERS_DIRECTORY: 281 case B_COMMON_BIN_DIRECTORY: 282 case B_COMMON_ETC_DIRECTORY: 283 case B_COMMON_DOCUMENTATION_DIRECTORY: 284 case B_COMMON_SETTINGS_DIRECTORY: 285 case B_COMMON_DEVELOP_DIRECTORY: 286 case B_COMMON_LOG_DIRECTORY: 287 case B_COMMON_SPOOL_DIRECTORY: 288 case B_COMMON_TEMP_DIRECTORY: 289 case B_COMMON_VAR_DIRECTORY: 290 case B_COMMON_TRANSLATORS_DIRECTORY: 291 case B_COMMON_MEDIA_NODES_DIRECTORY: 292 case B_COMMON_SOUNDS_DIRECTORY: 293 case B_COMMON_DATA_DIRECTORY: 294 case B_COMMON_CACHE_DIRECTORY: 295 case B_COMMON_PACKAGES_DIRECTORY: 296 case B_COMMON_HEADERS_DIRECTORY: 297 case B_COMMON_NONPACKAGED_DIRECTORY: 298 case B_COMMON_NONPACKAGED_ADDONS_DIRECTORY: 299 case B_COMMON_NONPACKAGED_TRANSLATORS_DIRECTORY: 300 case B_COMMON_NONPACKAGED_MEDIA_NODES_DIRECTORY: 301 case B_COMMON_NONPACKAGED_BIN_DIRECTORY: 302 case B_COMMON_NONPACKAGED_DATA_DIRECTORY: 303 case B_COMMON_NONPACKAGED_FONTS_DIRECTORY: 304 case B_COMMON_NONPACKAGED_SOUNDS_DIRECTORY: 305 case B_COMMON_NONPACKAGED_DOCUMENTATION_DIRECTORY: 306 case B_COMMON_NONPACKAGED_LIB_DIRECTORY: 307 case B_COMMON_NONPACKAGED_HEADERS_DIRECTORY: 308 templatePath = kCommonDirectories[which - B_COMMON_DIRECTORY]; 309 break; 310 311 /* User directories */ 312 case B_USER_DIRECTORY: 313 case B_USER_CONFIG_DIRECTORY: 314 case B_USER_ADDONS_DIRECTORY: 315 case B_USER_BOOT_DIRECTORY: 316 case B_USER_FONTS_DIRECTORY: 317 case B_USER_LIB_DIRECTORY: 318 case B_USER_SETTINGS_DIRECTORY: 319 case B_USER_DESKBAR_DIRECTORY: 320 case B_USER_PRINTERS_DIRECTORY: 321 case B_USER_TRANSLATORS_DIRECTORY: 322 case B_USER_MEDIA_NODES_DIRECTORY: 323 case B_USER_SOUNDS_DIRECTORY: 324 case B_USER_DATA_DIRECTORY: 325 case B_USER_CACHE_DIRECTORY: 326 case B_USER_PACKAGES_DIRECTORY: 327 case B_USER_HEADERS_DIRECTORY: 328 case B_USER_NONPACKAGED_DIRECTORY: 329 case B_USER_NONPACKAGED_ADDONS_DIRECTORY: 330 case B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY: 331 case B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY: 332 case B_USER_NONPACKAGED_BIN_DIRECTORY: 333 case B_USER_NONPACKAGED_DATA_DIRECTORY: 334 case B_USER_NONPACKAGED_FONTS_DIRECTORY: 335 case B_USER_NONPACKAGED_SOUNDS_DIRECTORY: 336 case B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY: 337 case B_USER_NONPACKAGED_LIB_DIRECTORY: 338 case B_USER_NONPACKAGED_HEADERS_DIRECTORY: 339 templatePath = kUserDirectories[which - B_USER_DIRECTORY]; 340 break; 341 342 /* Global directories */ 343 case B_APPS_DIRECTORY: 344 templatePath = "apps"; 345 break; 346 case B_PREFERENCES_DIRECTORY: 347 templatePath = "preferences"; 348 break; 349 case B_UTILITIES_DIRECTORY: 350 templatePath = "utilities"; 351 break; 352 case B_PACKAGE_LINKS_DIRECTORY: 353 templatePath = "packages"; 354 break; 355 356 default: 357 free(buffer); 358 return EINVAL; 359 } 360 361 err = B_OK; 362 if (templatePath) { 363 if (!strncmp(templatePath, "$h", 2)) { 364 if (bootDevice > -1 && device != bootDevice) { 365 int l = pathLength - strlen(buffer); 366 if (l > 5) 367 strncat(buffer, "/home", 5); 368 } else { 369#ifndef _KERNEL_MODE 370#ifdef USE_PWENTS 371 struct passwd pwBuffer; 372 char pwStringBuffer[MAX_PASSWD_BUFFER_SIZE]; 373 struct passwd *pw; 374 375 if (getpwuid_r(geteuid(), &pwBuffer, pwStringBuffer, 376 sizeof(pwStringBuffer), &pw) == 0) { 377 home = pw->pw_dir; 378 } 379#endif // USE_PWENTS 380 if (!home) { 381 /* use env var */ 382 home = getenv("HOME"); 383 } 384#endif // !_KERNEL_MODE 385 if (!home) 386 home = kUserDirectory; 387 strncpy(buffer, home, pathLength); 388 } 389 templatePath += 2; 390 } else 391 strlcat(buffer, "/", pathLength); 392 393 if (!err && strlen(buffer) + 2 + strlen(templatePath) 394 < (uint32)pathLength) { 395 strcat(buffer, templatePath); 396 } else 397 err = err ? err : E2BIG; 398 } else 399 err = err ? err : ENOENT; 400 401 if (!err && createIt && stat(buffer, &st) < 0) 402 err = create_path(buffer, 0755); 403 if (!err) 404 strlcpy(returnedPath, buffer, pathLength); 405 406 free(buffer); 407 return err; 408} 409 410