xref: /haiku/src/system/libroot/os/find_directory.cpp (revision 529cd177b573aaba391c8adc9c9f5ad76a14bf81)
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 
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>
29 
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>
36 
37 #include <AutoDeleter.h>
38 
39 #include "PathBuffer.h"
40 
41 
42 /* use pwents to find home */
43 #define USE_PWENTS
44 
45 
46 /*
47  * If you change any of the directories below, please have a look at
48  * headers/private/libroot/directories.h and adjust that accordingly!
49  */
50 
51 #define SYSTEM "system"
52 #define COMMON "system/data/empty"
53 #define NON_PACKAGED "/non-packaged"
54 
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,
80 };
81 
82 
83 /* Haiku system directories */
84 
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",
105 };
106 
107 /* Common directories, shared among users */
108 
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",
145 };
146 
147 /* User directories */
148 
149 #define HOME "$h"
150 #define CONFIG "/config"
151 
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",
191 };
192 
193 #ifndef _LOADER_MODE
194 /*! make dir and its parents if needed */
195 static int
196 create_path(const char *path, mode_t mode)
197 {
198 	char buffer[B_PATH_NAME_LENGTH + 1];
199 	int pathLength;
200 	int i = 0;
201 
202 	if (path == NULL || ((pathLength = strlen(path)) > B_PATH_NAME_LENGTH))
203 		return EINVAL;
204 
205 	while (++i < pathLength) {
206 		char *slash = strchr(&path[i], '/');
207 		struct stat st;
208 
209 		if (slash == NULL)
210 			i = pathLength;
211 		else if (i != slash - path)
212 			i = slash - path;
213 		else
214 			continue;
215 
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;
221 		}
222 	}
223 
224 	return 0;
225 }
226 
227 
228 static size_t
229 get_user_home_path(char* buffer, size_t bufferSize)
230 {
231 	const char* home = NULL;
232 #ifndef _KERNEL_MODE
233 #ifdef USE_PWENTS
234 	struct passwd pwBuffer;
235 	char pwStringBuffer[MAX_PASSWD_BUFFER_SIZE];
236 	struct passwd* pw;
237 
238 	if (getpwuid_r(geteuid(), &pwBuffer, pwStringBuffer,
239 			sizeof(pwStringBuffer), &pw) == 0
240 		&& pw != NULL) {
241 		home = pw->pw_dir;
242 	}
243 #endif	// USE_PWENTS
244 	if (home == NULL) {
245 		/* use env var */
246 		ssize_t result = __getenv_reentrant("HOME", buffer, bufferSize);
247 		if (result >= 0)
248 			return result;
249 	}
250 #endif	// !_KERNEL_MODE
251 	if (home == NULL)
252 		home = kUserDirectory;
253 
254 	return strlcpy(buffer, home, bufferSize);
255 }
256 
257 
258 //	#pragma mark -
259 
260 
261 status_t
262 __find_directory(directory_which which, dev_t device, bool createIt,
263 	char *returnedPath, int32 _pathLength)
264 {
265 	if (_pathLength <= 0)
266 		return E2BIG;
267 	size_t pathLength = _pathLength;
268 
269 	status_t err = B_OK;
270 	dev_t bootDevice = -1;
271 	struct fs_info fsInfo;
272 	struct stat st;
273 	const char *templatePath = NULL;
274 
275 	/* as with the R5 version, no on-stack buffer */
276 	char *buffer = (char*)malloc(pathLength);
277 	if (buffer == NULL)
278 		return B_NO_MEMORY;
279 	MemoryDeleter bufferDeleter(buffer);
280 
281 	memset(buffer, 0, pathLength);
282 
283 	/* fiddle with non-boot volume for items that need it */
284 	switch (which) {
285 		case B_DESKTOP_DIRECTORY:
286 		case B_TRASH_DIRECTORY:
287 			bootDevice = dev_for_path("/boot");
288 			if (device <= 0)
289 				device = bootDevice;
290 			if (fs_stat_dev(device, &fsInfo) != B_OK)
291 				return ENODEV;
292 			if (device != bootDevice) {
293 #ifdef _KERNEL_MODE
294 				err = _user_entry_ref_to_path(device, fsInfo.root, /*"."*/
295 					NULL, buffer, pathLength);
296 #else
297 				err = _kern_entry_ref_to_path(device, fsInfo.root, /*"."*/
298 					NULL, buffer, pathLength);
299 #endif
300 				if (err != B_OK)
301 					return err;
302 			} else {
303 				/* use the user id to find the home folder */
304 				/* done later */
305 				strlcat(buffer, "/boot", pathLength);
306 			}
307 			break;
308 		case B_PACKAGE_LINKS_DIRECTORY:
309 			// this is a directory living in rootfs
310 			break;
311 		default:
312 			strlcat(buffer, "/boot", pathLength);
313 			break;
314 	}
315 
316 	switch ((int)which) {
317 		/* Per volume directories */
318 		case B_DESKTOP_DIRECTORY:
319 			if (device == bootDevice || !strcmp(fsInfo.fsh_name, "bfs"))
320 				templatePath = "$h/Desktop";
321 			break;
322 		case B_TRASH_DIRECTORY:
323 			// TODO: eventually put that into the file system API?
324 			if (device == bootDevice || !strcmp(fsInfo.fsh_name, "bfs"))
325 				templatePath = "trash"; // TODO: add suffix for current user
326 			else if (!strcmp(fsInfo.fsh_name, "fat"))
327 				templatePath = "RECYCLED/_BEOS_";
328 			break;
329 
330 		/* Haiku system directories */
331 		case B_SYSTEM_DIRECTORY:
332 		case B_BEOS_SYSTEM_DIRECTORY:
333 		case B_SYSTEM_ADDONS_DIRECTORY:
334 		case B_SYSTEM_BOOT_DIRECTORY:
335 		case B_SYSTEM_FONTS_DIRECTORY:
336 		case B_SYSTEM_LIB_DIRECTORY:
337 		case B_SYSTEM_SERVERS_DIRECTORY:
338 		case B_SYSTEM_APPS_DIRECTORY:
339 		case B_SYSTEM_BIN_DIRECTORY:
340 		case B_BEOS_ETC_DIRECTORY:
341 		case B_SYSTEM_DOCUMENTATION_DIRECTORY:
342 		case B_SYSTEM_PREFERENCES_DIRECTORY:
343 		case B_SYSTEM_TRANSLATORS_DIRECTORY:
344 		case B_SYSTEM_MEDIA_NODES_DIRECTORY:
345 		case B_SYSTEM_SOUNDS_DIRECTORY:
346 		case B_SYSTEM_DATA_DIRECTORY:
347 		case B_SYSTEM_DEVELOP_DIRECTORY:
348 		case B_SYSTEM_PACKAGES_DIRECTORY:
349 		case B_SYSTEM_HEADERS_DIRECTORY:
350 			templatePath = kSystemDirectories[which - B_SYSTEM_DIRECTORY];
351 			break;
352 
353 		/* Obsolete common directories and writable system directories */
354 		case B_COMMON_DIRECTORY:
355 		case B_COMMON_SYSTEM_DIRECTORY:
356 		case B_COMMON_ADDONS_DIRECTORY:
357 		case B_COMMON_BOOT_DIRECTORY:
358 		case B_COMMON_FONTS_DIRECTORY:
359 		case B_COMMON_LIB_DIRECTORY:
360 		case B_COMMON_SERVERS_DIRECTORY:
361 		case B_COMMON_BIN_DIRECTORY:
362 		case B_SYSTEM_ETC_DIRECTORY:
363 		case B_COMMON_DOCUMENTATION_DIRECTORY:
364 		case B_SYSTEM_SETTINGS_DIRECTORY:
365 		case B_COMMON_DEVELOP_DIRECTORY:
366 		case B_SYSTEM_LOG_DIRECTORY:
367 		case B_SYSTEM_SPOOL_DIRECTORY:
368 		case B_SYSTEM_TEMP_DIRECTORY:
369 		case B_SYSTEM_VAR_DIRECTORY:
370 		case B_COMMON_TRANSLATORS_DIRECTORY:
371 		case B_COMMON_MEDIA_NODES_DIRECTORY:
372 		case B_COMMON_SOUNDS_DIRECTORY:
373 		case B_COMMON_DATA_DIRECTORY:
374 		case B_SYSTEM_CACHE_DIRECTORY:
375 		case B_COMMON_PACKAGES_DIRECTORY:
376 		case B_COMMON_HEADERS_DIRECTORY:
377 		case B_SYSTEM_NONPACKAGED_DIRECTORY:
378 		case B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY:
379 		case B_SYSTEM_NONPACKAGED_TRANSLATORS_DIRECTORY:
380 		case B_SYSTEM_NONPACKAGED_MEDIA_NODES_DIRECTORY:
381 		case B_SYSTEM_NONPACKAGED_BIN_DIRECTORY:
382 		case B_SYSTEM_NONPACKAGED_DATA_DIRECTORY:
383 		case B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY:
384 		case B_SYSTEM_NONPACKAGED_SOUNDS_DIRECTORY:
385 		case B_SYSTEM_NONPACKAGED_DOCUMENTATION_DIRECTORY:
386 		case B_SYSTEM_NONPACKAGED_LIB_DIRECTORY:
387 		case B_SYSTEM_NONPACKAGED_HEADERS_DIRECTORY:
388 		case B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY:
389 			templatePath = kCommonDirectories[which - B_COMMON_DIRECTORY];
390 			break;
391 
392 		/* User directories */
393 		case B_USER_DIRECTORY:
394 		case B_USER_CONFIG_DIRECTORY:
395 		case B_USER_ADDONS_DIRECTORY:
396 		case B_USER_BOOT_DIRECTORY:
397 		case B_USER_FONTS_DIRECTORY:
398 		case B_USER_LIB_DIRECTORY:
399 		case B_USER_SETTINGS_DIRECTORY:
400 		case B_USER_DESKBAR_DIRECTORY:
401 		case B_USER_PRINTERS_DIRECTORY:
402 		case B_USER_TRANSLATORS_DIRECTORY:
403 		case B_USER_MEDIA_NODES_DIRECTORY:
404 		case B_USER_SOUNDS_DIRECTORY:
405 		case B_USER_DATA_DIRECTORY:
406 		case B_USER_CACHE_DIRECTORY:
407 		case B_USER_PACKAGES_DIRECTORY:
408 		case B_USER_HEADERS_DIRECTORY:
409 		case B_USER_DEVELOP_DIRECTORY:
410 		case B_USER_DOCUMENTATION_DIRECTORY:
411 		case B_USER_NONPACKAGED_DIRECTORY:
412 		case B_USER_NONPACKAGED_ADDONS_DIRECTORY:
413 		case B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY:
414 		case B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY:
415 		case B_USER_NONPACKAGED_BIN_DIRECTORY:
416 		case B_USER_NONPACKAGED_DATA_DIRECTORY:
417 		case B_USER_NONPACKAGED_FONTS_DIRECTORY:
418 		case B_USER_NONPACKAGED_SOUNDS_DIRECTORY:
419 		case B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY:
420 		case B_USER_NONPACKAGED_LIB_DIRECTORY:
421 		case B_USER_NONPACKAGED_HEADERS_DIRECTORY:
422 		case B_USER_NONPACKAGED_DEVELOP_DIRECTORY:
423 		case B_USER_SERVERS_DIRECTORY:
424 		case B_USER_APPS_DIRECTORY:
425 		case B_USER_BIN_DIRECTORY:
426 		case B_USER_PREFERENCES_DIRECTORY:
427 		case B_USER_ETC_DIRECTORY:
428 		case B_USER_LOG_DIRECTORY:
429 		case B_USER_SPOOL_DIRECTORY:
430 		case B_USER_VAR_DIRECTORY:
431 			templatePath = kUserDirectories[which - B_USER_DIRECTORY];
432 			break;
433 
434 		/* Global directories */
435 		case B_APPS_DIRECTORY:
436 		case B_UTILITIES_DIRECTORY:
437 			templatePath = SYSTEM "/apps";
438 			break;
439 		case B_PREFERENCES_DIRECTORY:
440 			templatePath = SYSTEM "/preferences";
441 			break;
442 		case B_PACKAGE_LINKS_DIRECTORY:
443 			templatePath = "packages";
444 			break;
445 
446 		default:
447 			return EINVAL;
448 	}
449 
450 	if (templatePath == NULL)
451 		return ENOENT;
452 
453 	PathBuffer pathBuffer(buffer, pathLength, strlen(buffer));
454 
455 	// resolve "$h" placeholder to the user's home directory
456 	if (!strncmp(templatePath, "$h", 2)) {
457 		if (bootDevice > -1 && device != bootDevice) {
458 			pathBuffer.Append("/home");
459 		} else {
460 			size_t length = get_user_home_path(buffer, pathLength);
461 			if (length >= pathLength)
462 				return E2BIG;
463 			pathBuffer.SetTo(buffer, pathLength, length);
464 		}
465 		templatePath += 2;
466 	} else if (templatePath[0] != '\0')
467 		pathBuffer.Append('/');
468 
469 	// resolve "$a" placeholder to the architecture subdirectory, if not
470 	// primary
471 	if (char* dollar = strchr(templatePath, '$')) {
472 		if (dollar[1] == 'a') {
473 			pathBuffer.Append(templatePath, dollar - templatePath);
474 #ifndef _KERNEL_MODE
475 			const char* architecture = __get_architecture();
476 			if (strcmp(architecture, __get_primary_architecture()) != 0) {
477 				pathBuffer.Append('/');
478 				pathBuffer.Append(architecture);
479 			}
480 #endif
481 			templatePath = dollar + 2;
482 		}
483 	}
484 
485 	// append (remainder of) template path
486 	pathBuffer.Append(templatePath);
487 
488 	if (pathBuffer.Length() >= pathLength)
489 		return E2BIG;
490 
491 	if (createIt && stat(buffer, &st) < 0) {
492 		err = create_path(buffer, 0755);
493 		if (err != B_OK)
494 			return err;
495 	}
496 
497 	strlcpy(returnedPath, buffer, pathLength);
498 	return B_OK;
499 }
500 
501 
502 extern "C" status_t
503 __find_directory_alpha4(directory_which which, dev_t device, bool createIt,
504 	char *returnedPath, int32 pathLength)
505 {
506 	return __find_directory(which, device, createIt, returnedPath, pathLength);
507 }
508 
509 
510 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__find_directory_alpha4",
511 	"find_directory@", "BASE");
512 
513 DEFINE_LIBROOT_KERNEL_SYMBOL_VERSION("__find_directory", "find_directory@@",
514     "1_ALPHA5");
515 #else // _LOADER_MODE
516 status_t
517 __find_directory(directory_which which, dev_t device, bool createIt,
518 	char *returnedPath, int32 _pathLength)
519 {
520 	if (_pathLength <= 0)
521 		return E2BIG;
522 	size_t pathLength = _pathLength;
523 
524 	const char *templatePath = NULL;
525 
526 	/* as with the R5 version, no on-stack buffer */
527 	char *buffer = (char*)malloc(pathLength);
528 	if (buffer == NULL)
529 		return B_NO_MEMORY;
530 	MemoryDeleter bufferDeleter(buffer);
531 
532 	memset(buffer, 0, pathLength);
533 
534 	strlcat(buffer, "/boot", pathLength);
535 
536 	switch ((int)which) {
537 		/* Haiku system directories */
538 		case B_SYSTEM_DIRECTORY:
539 		case B_BEOS_SYSTEM_DIRECTORY:
540 		case B_SYSTEM_ADDONS_DIRECTORY:
541 		case B_SYSTEM_BOOT_DIRECTORY:
542 		case B_SYSTEM_FONTS_DIRECTORY:
543 		case B_SYSTEM_LIB_DIRECTORY:
544 		case B_SYSTEM_SERVERS_DIRECTORY:
545 		case B_SYSTEM_APPS_DIRECTORY:
546 		case B_SYSTEM_BIN_DIRECTORY:
547 		case B_BEOS_ETC_DIRECTORY:
548 		case B_SYSTEM_DOCUMENTATION_DIRECTORY:
549 		case B_SYSTEM_PREFERENCES_DIRECTORY:
550 		case B_SYSTEM_TRANSLATORS_DIRECTORY:
551 		case B_SYSTEM_MEDIA_NODES_DIRECTORY:
552 		case B_SYSTEM_SOUNDS_DIRECTORY:
553 		case B_SYSTEM_DATA_DIRECTORY:
554 		case B_SYSTEM_DEVELOP_DIRECTORY:
555 		case B_SYSTEM_PACKAGES_DIRECTORY:
556 		case B_SYSTEM_HEADERS_DIRECTORY:
557 			templatePath = kSystemDirectories[which - B_SYSTEM_DIRECTORY];
558 			break;
559 
560 		/* Obsolete common directories and writable system directories */
561 		case B_COMMON_DIRECTORY:
562 		case B_COMMON_SYSTEM_DIRECTORY:
563 		case B_COMMON_ADDONS_DIRECTORY:
564 		case B_COMMON_BOOT_DIRECTORY:
565 		case B_COMMON_FONTS_DIRECTORY:
566 		case B_COMMON_LIB_DIRECTORY:
567 		case B_COMMON_SERVERS_DIRECTORY:
568 		case B_COMMON_BIN_DIRECTORY:
569 		case B_SYSTEM_ETC_DIRECTORY:
570 		case B_COMMON_DOCUMENTATION_DIRECTORY:
571 		case B_SYSTEM_SETTINGS_DIRECTORY:
572 		case B_COMMON_DEVELOP_DIRECTORY:
573 		case B_SYSTEM_LOG_DIRECTORY:
574 		case B_SYSTEM_SPOOL_DIRECTORY:
575 		case B_SYSTEM_TEMP_DIRECTORY:
576 		case B_SYSTEM_VAR_DIRECTORY:
577 		case B_COMMON_TRANSLATORS_DIRECTORY:
578 		case B_COMMON_MEDIA_NODES_DIRECTORY:
579 		case B_COMMON_SOUNDS_DIRECTORY:
580 		case B_COMMON_DATA_DIRECTORY:
581 		case B_SYSTEM_CACHE_DIRECTORY:
582 		case B_COMMON_PACKAGES_DIRECTORY:
583 		case B_COMMON_HEADERS_DIRECTORY:
584 		case B_SYSTEM_NONPACKAGED_DIRECTORY:
585 		case B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY:
586 		case B_SYSTEM_NONPACKAGED_TRANSLATORS_DIRECTORY:
587 		case B_SYSTEM_NONPACKAGED_MEDIA_NODES_DIRECTORY:
588 		case B_SYSTEM_NONPACKAGED_BIN_DIRECTORY:
589 		case B_SYSTEM_NONPACKAGED_DATA_DIRECTORY:
590 		case B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY:
591 		case B_SYSTEM_NONPACKAGED_SOUNDS_DIRECTORY:
592 		case B_SYSTEM_NONPACKAGED_DOCUMENTATION_DIRECTORY:
593 		case B_SYSTEM_NONPACKAGED_LIB_DIRECTORY:
594 		case B_SYSTEM_NONPACKAGED_HEADERS_DIRECTORY:
595 		case B_SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY:
596 			templatePath = kCommonDirectories[which - B_COMMON_DIRECTORY];
597 			break;
598 
599 		/* User directories */
600 		case B_USER_DIRECTORY:
601 		case B_USER_CONFIG_DIRECTORY:
602 		case B_USER_ADDONS_DIRECTORY:
603 		case B_USER_BOOT_DIRECTORY:
604 		case B_USER_FONTS_DIRECTORY:
605 		case B_USER_LIB_DIRECTORY:
606 		case B_USER_SETTINGS_DIRECTORY:
607 		case B_USER_DESKBAR_DIRECTORY:
608 		case B_USER_PRINTERS_DIRECTORY:
609 		case B_USER_TRANSLATORS_DIRECTORY:
610 		case B_USER_MEDIA_NODES_DIRECTORY:
611 		case B_USER_SOUNDS_DIRECTORY:
612 		case B_USER_DATA_DIRECTORY:
613 		case B_USER_CACHE_DIRECTORY:
614 		case B_USER_PACKAGES_DIRECTORY:
615 		case B_USER_HEADERS_DIRECTORY:
616 		case B_USER_DEVELOP_DIRECTORY:
617 		case B_USER_DOCUMENTATION_DIRECTORY:
618 		case B_USER_NONPACKAGED_DIRECTORY:
619 		case B_USER_NONPACKAGED_ADDONS_DIRECTORY:
620 		case B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY:
621 		case B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY:
622 		case B_USER_NONPACKAGED_BIN_DIRECTORY:
623 		case B_USER_NONPACKAGED_DATA_DIRECTORY:
624 		case B_USER_NONPACKAGED_FONTS_DIRECTORY:
625 		case B_USER_NONPACKAGED_SOUNDS_DIRECTORY:
626 		case B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY:
627 		case B_USER_NONPACKAGED_LIB_DIRECTORY:
628 		case B_USER_NONPACKAGED_HEADERS_DIRECTORY:
629 		case B_USER_NONPACKAGED_DEVELOP_DIRECTORY:
630 		case B_USER_SERVERS_DIRECTORY:
631 		case B_USER_APPS_DIRECTORY:
632 		case B_USER_BIN_DIRECTORY:
633 		case B_USER_PREFERENCES_DIRECTORY:
634 		case B_USER_ETC_DIRECTORY:
635 		case B_USER_LOG_DIRECTORY:
636 		case B_USER_SPOOL_DIRECTORY:
637 		case B_USER_VAR_DIRECTORY:
638 			templatePath = kUserDirectories[which - B_USER_DIRECTORY];
639 			break;
640 
641 		default:
642 			return EINVAL;
643 	}
644 
645 	if (templatePath == NULL)
646 		return ENOENT;
647 
648 	PathBuffer pathBuffer(buffer, pathLength, strlen(buffer));
649 
650 	// resolve "$h" placeholder to the user's home directory
651 	if (!strncmp(templatePath, "$h", 2)) {
652 		pathBuffer.Append("/home");
653 		templatePath += 2;
654 	} else if (templatePath[0] != '\0')
655 		pathBuffer.Append('/');
656 
657 	// resolve "$a" placeholder to the architecture subdirectory, if not
658 	// primary
659 	if (char* dollar = strchr(templatePath, '$')) {
660 		if (dollar[1] == 'a') {
661 			pathBuffer.Append(templatePath, dollar - templatePath);
662 			templatePath = dollar + 2;
663 		}
664 	}
665 
666 	// append (remainder of) template path
667 	pathBuffer.Append(templatePath);
668 
669 	if (pathBuffer.Length() >= pathLength)
670 		return E2BIG;
671 
672 	strlcpy(returnedPath, buffer, pathLength);
673 	return B_OK;
674 }
675 #endif // _LOADER_MODE
676