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