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 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
6 *
7 * Distributed under the terms of the MIT license.
8 */
9
10 // TODO: this call is currently compiled for the kernel and libroot separately;
11 // they may not always return the same directory right now!
12
13 #ifdef _KERNEL_MODE
14 # include <vfs.h>
15 #else
16 # include <syscalls.h>
17 #endif
18
19 #include <directories.h>
20 #include <FindDirectory.h>
21 #include <fs_info.h>
22 #include <StackOrHeapArray.h>
23
24 #include <errno.h>
25 #include <pwd.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30
31 #include <architecture_private.h>
32 #include <errno_private.h>
33 #include <find_directory_private.h>
34 #include <stdlib_private.h>
35 #include <symbol_versioning.h>
36 #include <user_group.h>
37
38 #include <AutoDeleter.h>
39
40 #include "PathBuffer.h"
41
42
43 /* use pwents to find home */
44 #define USE_PWENTS
45
46
47 /*
48 * If you change any of the directories below, please have a look at
49 * headers/private/libroot/directories.h and adjust that accordingly!
50 */
51
52 #define SYSTEM "system"
53 #define COMMON "system/data/empty"
54 #define NON_PACKAGED "/non-packaged"
55
56 enum {
57 // obsolete common directories
58 B_COMMON_DIRECTORY = 2000,
59 B_COMMON_SYSTEM_DIRECTORY,
60 B_COMMON_ADDONS_DIRECTORY,
61 B_COMMON_BOOT_DIRECTORY,
62 B_COMMON_FONTS_DIRECTORY,
63 B_COMMON_LIB_DIRECTORY,
64 B_COMMON_SERVERS_DIRECTORY,
65 B_COMMON_BIN_DIRECTORY,
66 _B_COMMON_ETC_DIRECTORY,
67 B_COMMON_DOCUMENTATION_DIRECTORY,
68 _B_COMMON_SETTINGS_DIRECTORY,
69 B_COMMON_DEVELOP_DIRECTORY,
70 _B_COMMON_LOG_DIRECTORY,
71 _B_COMMON_SPOOL_DIRECTORY,
72 _B_COMMON_TEMP_DIRECTORY,
73 _B_COMMON_VAR_DIRECTORY,
74 B_COMMON_TRANSLATORS_DIRECTORY,
75 B_COMMON_MEDIA_NODES_DIRECTORY,
76 B_COMMON_SOUNDS_DIRECTORY,
77 B_COMMON_DATA_DIRECTORY,
78 _B_COMMON_CACHE_DIRECTORY,
79 B_COMMON_PACKAGES_DIRECTORY,
80 B_COMMON_HEADERS_DIRECTORY,
81 };
82
83
84 /* Haiku system directories */
85
86 static const char *kSystemDirectories[] = {
87 SYSTEM, // B_SYSTEM_DIRECTORY
88 SYSTEM, // B_BEOS_SYSTEM_DIRECTORY
89 SYSTEM "/add-ons$a",
90 SYSTEM "/boot",
91 SYSTEM "/data/fonts",
92 SYSTEM "/lib$a",
93 SYSTEM "/servers",
94 SYSTEM "/apps",
95 SYSTEM "/bin$a",
96 SYSTEM "/settings/etc",
97 SYSTEM "/documentation",
98 SYSTEM "/preferences",
99 SYSTEM "/add-ons$a/Translators",
100 SYSTEM "/add-ons$a/media",
101 SYSTEM "/data/sounds",
102 SYSTEM "/data",
103 SYSTEM "/develop",
104 SYSTEM "/packages",
105 SYSTEM "/develop/headers$a",
106 SYSTEM "/data/deskbar/menu",
107 };
108
109 /* Common directories, shared among users */
110
111 static const char *kCommonDirectories[] = {
112 COMMON, // B_COMMON_DIRECTORY
113 COMMON, // B_COMMON_SYSTEM_DIRECTORY
114 COMMON "/add-ons$a",
115 COMMON "/boot",
116 COMMON "/data/fonts",
117 COMMON "/lib$a",
118 COMMON "/servers",
119 COMMON "/bin$a",
120 SYSTEM "/settings/etc", // B_SYSTEM_ETC_DIRECTORY
121 COMMON "/documentation",
122 SYSTEM "/settings", // B_SYSTEM_SETTINGS_DIRECTORY
123 COMMON "/develop",
124 SYSTEM "/var/log", // B_SYSTEM_LOG_DIRECTORY
125 SYSTEM "/var/spool", // B_SYSTEM_SPOOL_DIRECTORY
126 SYSTEM "/cache/tmp", // B_SYSTEM_TEMP_DIRECTORY
127 SYSTEM "/var", // B_SYSTEM_VAR_DIRECTORY
128 COMMON "/add-ons$a/Translators",
129 COMMON "/add-ons$a/media",
130 COMMON "/data/sounds",
131 COMMON "/data",
132 SYSTEM "/cache", // B_SYSTEM_CACHE_DIRECTORY
133 COMMON "/packages",
134 COMMON "/develop/headers$a",
135 SYSTEM NON_PACKAGED,
136 SYSTEM NON_PACKAGED "/add-ons$a",
137 SYSTEM NON_PACKAGED "/add-ons$a/Translators",
138 SYSTEM NON_PACKAGED "/add-ons$a/media",
139 SYSTEM NON_PACKAGED "/bin$a",
140 SYSTEM NON_PACKAGED "/data",
141 SYSTEM NON_PACKAGED "/data/fonts",
142 SYSTEM NON_PACKAGED "/data/sounds",
143 SYSTEM NON_PACKAGED "/documentation",
144 SYSTEM NON_PACKAGED "/lib$a",
145 SYSTEM NON_PACKAGED "/develop/headers$a",
146 SYSTEM NON_PACKAGED "/develop",
147 };
148
149 /* User directories */
150
151 #define HOME "$h"
152 #define CONFIG "/config"
153
154 static const char *kUserDirectories[] = {
155 HOME, // B_USER_DIRECTORY
156 HOME CONFIG, // B_USER_CONFIG_DIRECTORY
157 HOME CONFIG "/add-ons$a",
158 HOME CONFIG "/settings/boot",
159 HOME CONFIG "/data/fonts",
160 HOME CONFIG "/lib$a",
161 HOME CONFIG "/settings",
162 HOME CONFIG "/settings/deskbar/menu",
163 HOME CONFIG "/settings/printers",
164 HOME CONFIG "/add-ons$a/Translators",
165 HOME CONFIG "/add-ons$a/media",
166 HOME CONFIG "/data/sounds",
167 HOME CONFIG "/data",
168 HOME CONFIG "/cache",
169 HOME CONFIG "/packages",
170 HOME CONFIG "/develop/headers$a",
171 HOME CONFIG NON_PACKAGED,
172 HOME CONFIG NON_PACKAGED "/add-ons$a",
173 HOME CONFIG NON_PACKAGED "/add-ons$a/Translators",
174 HOME CONFIG NON_PACKAGED "/add-ons$a/media",
175 HOME CONFIG NON_PACKAGED "/bin$a",
176 HOME CONFIG NON_PACKAGED "/data",
177 HOME CONFIG NON_PACKAGED "/data/fonts",
178 HOME CONFIG NON_PACKAGED "/data/sounds",
179 HOME CONFIG NON_PACKAGED "/documentation",
180 HOME CONFIG NON_PACKAGED "/lib$a",
181 HOME CONFIG NON_PACKAGED "/develop/headers$a",
182 HOME CONFIG NON_PACKAGED "/develop",
183 HOME CONFIG "/develop",
184 HOME CONFIG "/documentation",
185 HOME CONFIG "/servers",
186 HOME CONFIG "/apps",
187 HOME CONFIG "/bin$a",
188 HOME CONFIG "/preferences",
189 HOME CONFIG "/settings/etc",
190 HOME CONFIG "/var/log",
191 HOME CONFIG "/var/spool",
192 HOME CONFIG "/var",
193 };
194
195 #ifndef _LOADER_MODE
196 /*! make dir and its parents if needed */
197 static int
create_path(const char * path,mode_t mode)198 create_path(const char *path, mode_t mode)
199 {
200 int pathLength;
201 int i = 0;
202
203 if (path == NULL || ((pathLength = strlen(path)) > B_PATH_NAME_LENGTH))
204 return EINVAL;
205
206 BStackOrHeapArray<char, 128> buffer(pathLength + 1);
207 if (!buffer.IsValid())
208 return B_NO_MEMORY;
209
210 while (++i < pathLength) {
211 char *slash = strchr(&path[i], '/');
212 struct stat st;
213
214 if (slash == NULL)
215 i = pathLength;
216 else if (i != slash - path)
217 i = slash - path;
218 else
219 continue;
220
221 strlcpy(buffer, path, i + 1);
222 if (stat(buffer, &st) < 0) {
223 __set_errno(0);
224 if (mkdir(buffer, mode) < 0)
225 return errno;
226 }
227 }
228
229 return 0;
230 }
231
232
233 static size_t
get_user_home_path(char * buffer,size_t bufferSize)234 get_user_home_path(char* buffer, size_t bufferSize)
235 {
236 const char* home = NULL;
237 #ifndef _KERNEL_MODE
238 #ifdef USE_PWENTS
239 uid_t user = geteuid();
240 if (user == 0) {
241 // TODO: this is a work-around as the launch_daemon, and the registrar
242 // must not call getpwuid_r().
243 return strlcpy(buffer, kUserDirectory, bufferSize);
244 }
245
246 struct passwd pwBuffer;
247 char pwStringBuffer[MAX_PASSWD_BUFFER_SIZE];
248 struct passwd* pw;
249
250 if (getpwuid_r(user, &pwBuffer, pwStringBuffer,
251 sizeof(pwStringBuffer), &pw) == 0
252 && pw != NULL) {
253 home = pw->pw_dir;
254 }
255 #endif // USE_PWENTS
256 if (home == NULL) {
257 /* use env var */
258 ssize_t result = __getenv_reentrant("HOME", buffer, bufferSize);
259 if (result >= 0)
260 return result;
261 }
262 #endif // !_KERNEL_MODE
263 if (home == NULL)
264 home = kUserDirectory;
265
266 return strlcpy(buffer, home, bufferSize);
267 }
268
269
270 // #pragma mark -
271
272
273 status_t
__find_directory(directory_which which,dev_t device,bool createIt,char * returnedPath,int32 _pathLength)274 __find_directory(directory_which which, dev_t device, bool createIt,
275 char *returnedPath, int32 _pathLength)
276 {
277 if (_pathLength <= 0)
278 return E2BIG;
279 size_t pathLength = _pathLength;
280
281 status_t err = B_OK;
282 dev_t bootDevice = -1;
283 struct fs_info fsInfo;
284 struct stat st;
285 const char *templatePath = NULL;
286
287 /* as with the R5 version, no on-stack buffer */
288 char *buffer = (char*)malloc(pathLength);
289 if (buffer == NULL)
290 return B_NO_MEMORY;
291 MemoryDeleter bufferDeleter(buffer);
292
293 memset(buffer, 0, pathLength);
294
295 /* fiddle with non-boot volume for items that need it */
296 switch (which) {
297 case B_DESKTOP_DIRECTORY:
298 case B_TRASH_DIRECTORY:
299 bootDevice = dev_for_path("/boot");
300 if (device <= 0)
301 device = bootDevice;
302 if (fs_stat_dev(device, &fsInfo) != B_OK)
303 return ENODEV;
304 if (device != bootDevice) {
305 #ifdef _KERNEL_MODE
306 err = _user_entry_ref_to_path(device, fsInfo.root, /*"."*/
307 NULL, buffer, pathLength);
308 #else
309 err = _kern_entry_ref_to_path(device, fsInfo.root, /*"."*/
310 NULL, buffer, pathLength);
311 #endif
312 if (err != B_OK)
313 return err;
314 } else {
315 /* use the user id to find the home folder */
316 /* done later */
317 strlcat(buffer, "/boot", pathLength);
318 }
319 break;
320 case B_PACKAGE_LINKS_DIRECTORY:
321 // this is a directory living in rootfs
322 break;
323 default:
324 strlcat(buffer, "/boot", pathLength);
325 break;
326 }
327
328 switch ((int)which) {
329 /* Per volume directories */
330 case B_DESKTOP_DIRECTORY:
331 if (device == bootDevice || !strcmp(fsInfo.fsh_name, "bfs"))
332 templatePath = "$h/Desktop";
333 break;
334 case B_TRASH_DIRECTORY:
335 // TODO: eventually put that into the file system API?
336 if (device == bootDevice || !strcmp(fsInfo.fsh_name, "bfs"))
337 templatePath = "trash"; // TODO: add suffix for current user
338 else if (!strcmp(fsInfo.fsh_name, "fat"))
339 templatePath = "RECYCLED/_BEOS_";
340 break;
341
342 /* Haiku system directories */
343 case B_SYSTEM_DIRECTORY:
344 case B_BEOS_SYSTEM_DIRECTORY:
345 case B_SYSTEM_ADDONS_DIRECTORY:
346 case B_SYSTEM_BOOT_DIRECTORY:
347 case B_SYSTEM_FONTS_DIRECTORY:
348 case B_SYSTEM_LIB_DIRECTORY:
349 case B_SYSTEM_SERVERS_DIRECTORY:
350 case B_SYSTEM_APPS_DIRECTORY:
351 case B_SYSTEM_BIN_DIRECTORY:
352 case B_BEOS_ETC_DIRECTORY:
353 case B_SYSTEM_DOCUMENTATION_DIRECTORY:
354 case B_SYSTEM_PREFERENCES_DIRECTORY:
355 case B_SYSTEM_TRANSLATORS_DIRECTORY:
356 case B_SYSTEM_MEDIA_NODES_DIRECTORY:
357 case B_SYSTEM_SOUNDS_DIRECTORY:
358 case B_SYSTEM_DATA_DIRECTORY:
359 case B_SYSTEM_DEVELOP_DIRECTORY:
360 case B_SYSTEM_PACKAGES_DIRECTORY:
361 case B_SYSTEM_HEADERS_DIRECTORY:
362 case B_SYSTEM_DESKBAR_DIRECTORY:
363 templatePath = kSystemDirectories[which - B_SYSTEM_DIRECTORY];
364 break;
365
366 /* Obsolete common directories and writable system directories */
367 case B_COMMON_DIRECTORY:
368 case B_COMMON_SYSTEM_DIRECTORY:
369 case B_COMMON_ADDONS_DIRECTORY:
370 case B_COMMON_BOOT_DIRECTORY:
371 case B_COMMON_FONTS_DIRECTORY:
372 case B_COMMON_LIB_DIRECTORY:
373 case B_COMMON_SERVERS_DIRECTORY:
374 case B_COMMON_BIN_DIRECTORY:
375 case B_SYSTEM_ETC_DIRECTORY:
376 case B_COMMON_DOCUMENTATION_DIRECTORY:
377 case B_SYSTEM_SETTINGS_DIRECTORY:
378 case B_COMMON_DEVELOP_DIRECTORY:
379 case B_SYSTEM_LOG_DIRECTORY:
380 case B_SYSTEM_SPOOL_DIRECTORY:
381 case B_SYSTEM_TEMP_DIRECTORY:
382 case B_SYSTEM_VAR_DIRECTORY:
383 case B_COMMON_TRANSLATORS_DIRECTORY:
384 case B_COMMON_MEDIA_NODES_DIRECTORY:
385 case B_COMMON_SOUNDS_DIRECTORY:
386 case B_COMMON_DATA_DIRECTORY:
387 case B_SYSTEM_CACHE_DIRECTORY:
388 case B_COMMON_PACKAGES_DIRECTORY:
389 case B_COMMON_HEADERS_DIRECTORY:
390 case B_SYSTEM_NONPACKAGED_DIRECTORY:
391 case B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY:
392 case B_SYSTEM_NONPACKAGED_TRANSLATORS_DIRECTORY:
393 case B_SYSTEM_NONPACKAGED_MEDIA_NODES_DIRECTORY:
394 case B_SYSTEM_NONPACKAGED_BIN_DIRECTORY:
395 case B_SYSTEM_NONPACKAGED_DATA_DIRECTORY:
396 case B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY:
397 case B_SYSTEM_NONPACKAGED_SOUNDS_DIRECTORY:
398 case B_SYSTEM_NONPACKAGED_DOCUMENTATION_DIRECTORY:
399 case B_SYSTEM_NONPACKAGED_LIB_DIRECTORY:
400 case B_SYSTEM_NONPACKAGED_HEADERS_DIRECTORY:
401 case B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY:
402 templatePath = kCommonDirectories[which - B_COMMON_DIRECTORY];
403 break;
404
405 /* User directories */
406 case B_USER_DIRECTORY:
407 case B_USER_CONFIG_DIRECTORY:
408 case B_USER_ADDONS_DIRECTORY:
409 case B_USER_BOOT_DIRECTORY:
410 case B_USER_FONTS_DIRECTORY:
411 case B_USER_LIB_DIRECTORY:
412 case B_USER_SETTINGS_DIRECTORY:
413 case B_USER_DESKBAR_DIRECTORY:
414 case B_USER_PRINTERS_DIRECTORY:
415 case B_USER_TRANSLATORS_DIRECTORY:
416 case B_USER_MEDIA_NODES_DIRECTORY:
417 case B_USER_SOUNDS_DIRECTORY:
418 case B_USER_DATA_DIRECTORY:
419 case B_USER_CACHE_DIRECTORY:
420 case B_USER_PACKAGES_DIRECTORY:
421 case B_USER_HEADERS_DIRECTORY:
422 case B_USER_DEVELOP_DIRECTORY:
423 case B_USER_DOCUMENTATION_DIRECTORY:
424 case B_USER_NONPACKAGED_DIRECTORY:
425 case B_USER_NONPACKAGED_ADDONS_DIRECTORY:
426 case B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY:
427 case B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY:
428 case B_USER_NONPACKAGED_BIN_DIRECTORY:
429 case B_USER_NONPACKAGED_DATA_DIRECTORY:
430 case B_USER_NONPACKAGED_FONTS_DIRECTORY:
431 case B_USER_NONPACKAGED_SOUNDS_DIRECTORY:
432 case B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY:
433 case B_USER_NONPACKAGED_LIB_DIRECTORY:
434 case B_USER_NONPACKAGED_HEADERS_DIRECTORY:
435 case B_USER_NONPACKAGED_DEVELOP_DIRECTORY:
436 case B_USER_SERVERS_DIRECTORY:
437 case B_USER_APPS_DIRECTORY:
438 case B_USER_BIN_DIRECTORY:
439 case B_USER_PREFERENCES_DIRECTORY:
440 case B_USER_ETC_DIRECTORY:
441 case B_USER_LOG_DIRECTORY:
442 case B_USER_SPOOL_DIRECTORY:
443 case B_USER_VAR_DIRECTORY:
444 templatePath = kUserDirectories[which - B_USER_DIRECTORY];
445 break;
446
447 /* Global directories */
448 case B_APPS_DIRECTORY:
449 case B_UTILITIES_DIRECTORY:
450 templatePath = SYSTEM "/apps";
451 break;
452 case B_PREFERENCES_DIRECTORY:
453 templatePath = SYSTEM "/preferences";
454 break;
455 case B_PACKAGE_LINKS_DIRECTORY:
456 templatePath = "packages";
457 break;
458
459 default:
460 return EINVAL;
461 }
462
463 if (templatePath == NULL)
464 return ENOENT;
465
466 PathBuffer pathBuffer(buffer, pathLength, strlen(buffer));
467
468 // resolve "$h" placeholder to the user's home directory
469 if (!strncmp(templatePath, "$h", 2)) {
470 if (bootDevice > -1 && device != bootDevice) {
471 pathBuffer.Append("/home");
472 } else {
473 size_t length = get_user_home_path(buffer, pathLength);
474 if (length >= pathLength)
475 return E2BIG;
476 pathBuffer.SetTo(buffer, pathLength, length);
477 }
478 templatePath += 2;
479 } else if (templatePath[0] != '\0')
480 pathBuffer.Append('/');
481
482 // resolve "$a" placeholder to the architecture subdirectory, if not
483 // primary
484 if (char* dollar = strchr(templatePath, '$')) {
485 if (dollar[1] == 'a') {
486 pathBuffer.Append(templatePath, dollar - templatePath);
487 #ifndef _KERNEL_MODE
488 const char* architecture = __get_architecture();
489 if (strcmp(architecture, __get_primary_architecture()) != 0) {
490 pathBuffer.Append('/');
491 pathBuffer.Append(architecture);
492 }
493 #endif
494 templatePath = dollar + 2;
495 }
496 }
497
498 // append (remainder of) template path
499 pathBuffer.Append(templatePath);
500
501 if (pathBuffer.Length() >= pathLength)
502 return E2BIG;
503
504 if (createIt && stat(buffer, &st) < 0) {
505 err = create_path(buffer, 0755);
506 if (err != B_OK)
507 return err;
508 }
509
510 strlcpy(returnedPath, buffer, pathLength);
511 return B_OK;
512 }
513
514
515 extern "C" status_t
__find_directory_alpha4(directory_which which,dev_t device,bool createIt,char * returnedPath,int32 pathLength)516 __find_directory_alpha4(directory_which which, dev_t device, bool createIt,
517 char *returnedPath, int32 pathLength)
518 {
519 return __find_directory(which, device, createIt, returnedPath, pathLength);
520 }
521
522
523 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__find_directory_alpha4",
524 "find_directory@", "BASE");
525
526 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__find_directory", "find_directory@@",
527 "1_ALPHA5");
528 #else // _LOADER_MODE
529 status_t
__find_directory(directory_which which,dev_t device,bool createIt,char * returnedPath,int32 _pathLength)530 __find_directory(directory_which which, dev_t device, bool createIt,
531 char *returnedPath, int32 _pathLength)
532 {
533 if (_pathLength <= 0)
534 return E2BIG;
535 size_t pathLength = _pathLength;
536
537 const char *templatePath = NULL;
538
539 /* as with the R5 version, no on-stack buffer */
540 char *buffer = (char*)malloc(pathLength);
541 if (buffer == NULL)
542 return B_NO_MEMORY;
543 MemoryDeleter bufferDeleter(buffer);
544
545 memset(buffer, 0, pathLength);
546
547 strlcat(buffer, "/boot", pathLength);
548
549 switch ((int)which) {
550 /* Haiku system directories */
551 case B_SYSTEM_DIRECTORY:
552 case B_BEOS_SYSTEM_DIRECTORY:
553 case B_SYSTEM_ADDONS_DIRECTORY:
554 case B_SYSTEM_BOOT_DIRECTORY:
555 case B_SYSTEM_FONTS_DIRECTORY:
556 case B_SYSTEM_LIB_DIRECTORY:
557 case B_SYSTEM_SERVERS_DIRECTORY:
558 case B_SYSTEM_APPS_DIRECTORY:
559 case B_SYSTEM_BIN_DIRECTORY:
560 case B_BEOS_ETC_DIRECTORY:
561 case B_SYSTEM_DOCUMENTATION_DIRECTORY:
562 case B_SYSTEM_PREFERENCES_DIRECTORY:
563 case B_SYSTEM_TRANSLATORS_DIRECTORY:
564 case B_SYSTEM_MEDIA_NODES_DIRECTORY:
565 case B_SYSTEM_SOUNDS_DIRECTORY:
566 case B_SYSTEM_DATA_DIRECTORY:
567 case B_SYSTEM_DEVELOP_DIRECTORY:
568 case B_SYSTEM_PACKAGES_DIRECTORY:
569 case B_SYSTEM_HEADERS_DIRECTORY:
570 case B_SYSTEM_DESKBAR_DIRECTORY:
571 templatePath = kSystemDirectories[which - B_SYSTEM_DIRECTORY];
572 break;
573
574 /* Obsolete common directories and writable system directories */
575 case B_COMMON_DIRECTORY:
576 case B_COMMON_SYSTEM_DIRECTORY:
577 case B_COMMON_ADDONS_DIRECTORY:
578 case B_COMMON_BOOT_DIRECTORY:
579 case B_COMMON_FONTS_DIRECTORY:
580 case B_COMMON_LIB_DIRECTORY:
581 case B_COMMON_SERVERS_DIRECTORY:
582 case B_COMMON_BIN_DIRECTORY:
583 case B_SYSTEM_ETC_DIRECTORY:
584 case B_COMMON_DOCUMENTATION_DIRECTORY:
585 case B_SYSTEM_SETTINGS_DIRECTORY:
586 case B_COMMON_DEVELOP_DIRECTORY:
587 case B_SYSTEM_LOG_DIRECTORY:
588 case B_SYSTEM_SPOOL_DIRECTORY:
589 case B_SYSTEM_TEMP_DIRECTORY:
590 case B_SYSTEM_VAR_DIRECTORY:
591 case B_COMMON_TRANSLATORS_DIRECTORY:
592 case B_COMMON_MEDIA_NODES_DIRECTORY:
593 case B_COMMON_SOUNDS_DIRECTORY:
594 case B_COMMON_DATA_DIRECTORY:
595 case B_SYSTEM_CACHE_DIRECTORY:
596 case B_COMMON_PACKAGES_DIRECTORY:
597 case B_COMMON_HEADERS_DIRECTORY:
598 case B_SYSTEM_NONPACKAGED_DIRECTORY:
599 case B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY:
600 case B_SYSTEM_NONPACKAGED_TRANSLATORS_DIRECTORY:
601 case B_SYSTEM_NONPACKAGED_MEDIA_NODES_DIRECTORY:
602 case B_SYSTEM_NONPACKAGED_BIN_DIRECTORY:
603 case B_SYSTEM_NONPACKAGED_DATA_DIRECTORY:
604 case B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY:
605 case B_SYSTEM_NONPACKAGED_SOUNDS_DIRECTORY:
606 case B_SYSTEM_NONPACKAGED_DOCUMENTATION_DIRECTORY:
607 case B_SYSTEM_NONPACKAGED_LIB_DIRECTORY:
608 case B_SYSTEM_NONPACKAGED_HEADERS_DIRECTORY:
609 case B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY:
610 templatePath = kCommonDirectories[which - B_COMMON_DIRECTORY];
611 break;
612
613 /* User directories */
614 case B_USER_DIRECTORY:
615 case B_USER_CONFIG_DIRECTORY:
616 case B_USER_ADDONS_DIRECTORY:
617 case B_USER_BOOT_DIRECTORY:
618 case B_USER_FONTS_DIRECTORY:
619 case B_USER_LIB_DIRECTORY:
620 case B_USER_SETTINGS_DIRECTORY:
621 case B_USER_DESKBAR_DIRECTORY:
622 case B_USER_PRINTERS_DIRECTORY:
623 case B_USER_TRANSLATORS_DIRECTORY:
624 case B_USER_MEDIA_NODES_DIRECTORY:
625 case B_USER_SOUNDS_DIRECTORY:
626 case B_USER_DATA_DIRECTORY:
627 case B_USER_CACHE_DIRECTORY:
628 case B_USER_PACKAGES_DIRECTORY:
629 case B_USER_HEADERS_DIRECTORY:
630 case B_USER_DEVELOP_DIRECTORY:
631 case B_USER_DOCUMENTATION_DIRECTORY:
632 case B_USER_NONPACKAGED_DIRECTORY:
633 case B_USER_NONPACKAGED_ADDONS_DIRECTORY:
634 case B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY:
635 case B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY:
636 case B_USER_NONPACKAGED_BIN_DIRECTORY:
637 case B_USER_NONPACKAGED_DATA_DIRECTORY:
638 case B_USER_NONPACKAGED_FONTS_DIRECTORY:
639 case B_USER_NONPACKAGED_SOUNDS_DIRECTORY:
640 case B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY:
641 case B_USER_NONPACKAGED_LIB_DIRECTORY:
642 case B_USER_NONPACKAGED_HEADERS_DIRECTORY:
643 case B_USER_NONPACKAGED_DEVELOP_DIRECTORY:
644 case B_USER_SERVERS_DIRECTORY:
645 case B_USER_APPS_DIRECTORY:
646 case B_USER_BIN_DIRECTORY:
647 case B_USER_PREFERENCES_DIRECTORY:
648 case B_USER_ETC_DIRECTORY:
649 case B_USER_LOG_DIRECTORY:
650 case B_USER_SPOOL_DIRECTORY:
651 case B_USER_VAR_DIRECTORY:
652 templatePath = kUserDirectories[which - B_USER_DIRECTORY];
653 break;
654
655 default:
656 return EINVAL;
657 }
658
659 if (templatePath == NULL)
660 return ENOENT;
661
662 PathBuffer pathBuffer(buffer, pathLength, strlen(buffer));
663
664 // resolve "$h" placeholder to the user's home directory
665 if (!strncmp(templatePath, "$h", 2)) {
666 pathBuffer.Append("/home");
667 templatePath += 2;
668 } else if (templatePath[0] != '\0')
669 pathBuffer.Append('/');
670
671 // resolve "$a" placeholder to the architecture subdirectory, if not
672 // primary
673 if (char* dollar = strchr(templatePath, '$')) {
674 if (dollar[1] == 'a') {
675 pathBuffer.Append(templatePath, dollar - templatePath);
676 templatePath = dollar + 2;
677 }
678 }
679
680 // append (remainder of) template path
681 pathBuffer.Append(templatePath);
682
683 if (pathBuffer.Length() >= pathLength)
684 return E2BIG;
685
686 strlcpy(returnedPath, buffer, pathLength);
687 return B_OK;
688 }
689 #endif // _LOADER_MODE
690