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