1 /*
2 * Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8 #include <find_directory_private.h>
9
10 #include <errno.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <sys/stat.h>
14
15 #include <algorithm>
16
17 #include <fs_attr.h>
18
19 #include <architecture_private.h>
20 #include <AutoDeleter.h>
21 #include <directories.h>
22 #include <syscalls.h>
23
24 #include "PathBuffer.h"
25
26
27 static size_t kHomeInstallationLocationIndex = 1;
28
29 static const path_base_directory kArchitectureSpecificBaseDirectories[] = {
30 B_FIND_PATH_ADD_ONS_DIRECTORY,
31 B_FIND_PATH_BIN_DIRECTORY,
32 B_FIND_PATH_DEVELOP_LIB_DIRECTORY,
33 B_FIND_PATH_HEADERS_DIRECTORY,
34 };
35
36 static size_t kArchitectureSpecificBaseDirectoryCount =
37 sizeof(kArchitectureSpecificBaseDirectories)
38 / sizeof(kArchitectureSpecificBaseDirectories[0]);
39
40
41 namespace {
42
43
44 struct InstallationLocations {
45 public:
46 static const size_t kCount = 4;
47
48 public:
InstallationLocations__anonacc0a5970111::InstallationLocations49 InstallationLocations()
50 :
51 fReferenceCount(1)
52 {
53 fLocations[0] = kUserNonpackagedDirectory;
54 fLocations[1] = kUserConfigDirectory;
55 fLocations[2] = kSystemNonpackagedDirectory;
56 fLocations[3] = kSystemDirectory;
57 }
58
InstallationLocations__anonacc0a5970111::InstallationLocations59 InstallationLocations(const char* home)
60 :
61 fReferenceCount(1)
62 {
63 static const char* const kNonPackagedSuffix = "/non-packaged";
64 char* homeNonPackaged
65 = (char*)malloc(strlen(home) + strlen(kNonPackagedSuffix) + 1);
66 fLocations[0] = homeNonPackaged;
67 if (homeNonPackaged != NULL) {
68 strcpy(homeNonPackaged, home);
69 strcat(homeNonPackaged, kNonPackagedSuffix);
70 }
71
72 fLocations[1] = strdup(home);
73
74 fLocations[2] = kSystemNonpackagedDirectory;
75 fLocations[3] = kSystemDirectory;
76 }
77
~InstallationLocations__anonacc0a5970111::InstallationLocations78 ~InstallationLocations()
79 {
80 free(const_cast<char*>(fLocations[0]));
81 free(const_cast<char*>(fLocations[1]));
82 }
83
IsValid__anonacc0a5970111::InstallationLocations84 bool IsValid() const
85 {
86 return fLocations[0] != NULL && fLocations[1] != NULL;
87 }
88
IsUserIndex__anonacc0a5970111::InstallationLocations89 bool IsUserIndex(size_t index) const
90 {
91 return index==0 || index==1;
92 }
93
IsSystemIndex__anonacc0a5970111::InstallationLocations94 bool IsSystemIndex(size_t index) const
95 {
96 return index==2 || index==3;
97 }
98
Default__anonacc0a5970111::InstallationLocations99 static InstallationLocations* Default()
100 {
101 static char sBuffer[sizeof(InstallationLocations)];
102 static InstallationLocations* sDefaultLocations
103 = new(&sBuffer) InstallationLocations;
104 return sDefaultLocations;
105 }
106
Get__anonacc0a5970111::InstallationLocations107 static InstallationLocations* Get()
108 {
109 InstallationLocations* defaultLocations = Default();
110
111 // Get the home config installation location and create a new object,
112 // if it differs from the default.
113 char homeInstallationLocation[B_PATH_NAME_LENGTH];
114 if (__find_directory(B_USER_CONFIG_DIRECTORY, -1, false,
115 homeInstallationLocation, sizeof(homeInstallationLocation))
116 == B_OK) {
117 _kern_normalize_path(homeInstallationLocation, true,
118 homeInstallationLocation);
119 // failure is OK
120 if (strcmp(homeInstallationLocation,
121 defaultLocations->At(kHomeInstallationLocationIndex))
122 != 0) {
123 InstallationLocations* locations
124 = new(std::nothrow) InstallationLocations(
125 homeInstallationLocation);
126 if (locations != NULL && locations->IsValid())
127 return locations;
128 delete locations;
129 }
130 }
131
132 atomic_add(&defaultLocations->fReferenceCount, 1);
133 return defaultLocations;
134 }
135
Put__anonacc0a5970111::InstallationLocations136 void Put()
137 {
138 if (atomic_add(&fReferenceCount, -1) == 1)
139 delete this;
140 }
141
At__anonacc0a5970111::InstallationLocations142 const char* At(size_t index) const
143 {
144 return fLocations[index];
145 }
146
LocationFor__anonacc0a5970111::InstallationLocations147 const char* LocationFor(const char* path, size_t& _index)
148 {
149 for (size_t i = 0; i < kCount; i++) {
150 size_t length = strlen(fLocations[i]);
151 if (strncmp(path, fLocations[i], length) == 0
152 && (path[length] == '/' || path[length] == '\0')) {
153 _index = i;
154 return fLocations[i];
155 }
156 }
157
158 return NULL;
159 }
160
161 private:
162 int32 fReferenceCount;
163 const char* fLocations[kCount];
164 };
165
166
167 } // unnamed namespace
168
169
170 /*! Returns the installation location relative path for the given base directory
171 constant and installation location index. A '%' in the returned path must be
172 replaced by "" for the primary architecture and by "/<arch>" for a secondary
173 architecture.
174 */
175 static const char*
get_relative_directory_path(size_t installationLocationIndex,path_base_directory baseDirectory)176 get_relative_directory_path(size_t installationLocationIndex,
177 path_base_directory baseDirectory)
178 {
179 switch (baseDirectory) {
180 case B_FIND_PATH_INSTALLATION_LOCATION_DIRECTORY:
181 return "";
182 case B_FIND_PATH_ADD_ONS_DIRECTORY:
183 return "/add-ons%";
184 case B_FIND_PATH_APPS_DIRECTORY:
185 return "/apps";
186 case B_FIND_PATH_BIN_DIRECTORY:
187 return "/bin%";
188 case B_FIND_PATH_BOOT_DIRECTORY:
189 return "/boot";
190 case B_FIND_PATH_CACHE_DIRECTORY:
191 return "/cache";
192 case B_FIND_PATH_DATA_DIRECTORY:
193 return "/data";
194 case B_FIND_PATH_DEVELOP_DIRECTORY:
195 return "/develop";
196 case B_FIND_PATH_DEVELOP_LIB_DIRECTORY:
197 return "/develop/lib%";
198 case B_FIND_PATH_DOCUMENTATION_DIRECTORY:
199 return "/documentation";
200 case B_FIND_PATH_ETC_DIRECTORY:
201 return "/settings/etc";
202 case B_FIND_PATH_FONTS_DIRECTORY:
203 return "/data/fonts";
204 case B_FIND_PATH_HEADERS_DIRECTORY:
205 return "/develop/headers%";
206 case B_FIND_PATH_LIB_DIRECTORY:
207 return "/lib%";
208 case B_FIND_PATH_LOG_DIRECTORY:
209 return "/log";
210 case B_FIND_PATH_MEDIA_NODES_DIRECTORY:
211 return "/add-ons%/media";
212 case B_FIND_PATH_PACKAGES_DIRECTORY:
213 return "/packages";
214 case B_FIND_PATH_PREFERENCES_DIRECTORY:
215 return "/preferences";
216 case B_FIND_PATH_SERVERS_DIRECTORY:
217 return "/servers";
218 case B_FIND_PATH_SETTINGS_DIRECTORY:
219 return "/settings";
220 case B_FIND_PATH_SOUNDS_DIRECTORY:
221 return "/data/sounds";
222 case B_FIND_PATH_SPOOL_DIRECTORY:
223 return "/var/spool";
224 case B_FIND_PATH_TRANSLATORS_DIRECTORY:
225 return "/add-ons%/Translators";
226 case B_FIND_PATH_VAR_DIRECTORY:
227 return "/var";
228
229 case B_FIND_PATH_IMAGE_PATH:
230 case B_FIND_PATH_PACKAGE_PATH:
231 default:
232 return NULL;
233 }
234 }
235
236
237 static status_t
create_directory(char * path)238 create_directory(char* path)
239 {
240 // find the first directory that doesn't exist
241 char* slash = path;
242 bool found = false;
243 while (!found && (slash = strchr(slash + 1, '/')) != NULL) {
244 *slash = '\0';
245 struct stat st;
246 if (lstat(path, &st) != 0)
247 break;
248 *slash = '/';
249 }
250
251 if (found)
252 return B_OK;
253
254 // create directories
255 while (slash != NULL) {
256 *slash = '\0';
257 bool created = mkdir(path, 0755);
258 *slash = '/';
259
260 if (!created)
261 return errno;
262
263 slash = strchr(slash + 1, '/');
264 }
265
266 return B_OK;
267 }
268
269
270 static bool
is_in_range(const void * pointer,const void * base,size_t size)271 is_in_range(const void* pointer, const void* base, size_t size)
272 {
273 return pointer >= base && (addr_t)pointer < (addr_t)base + size;
274 }
275
276
277 static status_t
find_image(const void * codePointer,image_info & _info)278 find_image(const void* codePointer, image_info& _info)
279 {
280 int32 cookie = 0;
281
282 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &_info) == B_OK) {
283 if (codePointer == NULL ? _info.type == B_APP_IMAGE
284 : (is_in_range(codePointer, _info.text, _info.text_size)
285 || is_in_range(codePointer, _info.data, _info.data_size))) {
286 return B_OK;
287 }
288 }
289
290 return B_ENTRY_NOT_FOUND;
291 }
292
293
294 static status_t
copy_path(const char * path,char * buffer,size_t bufferSize)295 copy_path(const char* path, char* buffer, size_t bufferSize)
296 {
297 if (strlcpy(buffer, path, bufferSize) >= bufferSize)
298 return B_BUFFER_OVERFLOW;
299 return B_OK;
300 }
301
302
303 static status_t
normalize_path(const char * path,char * buffer,size_t bufferSize)304 normalize_path(const char* path, char* buffer, size_t bufferSize)
305 {
306 status_t error;
307 if (bufferSize >= B_PATH_NAME_LENGTH) {
308 error = _kern_normalize_path(path, true, buffer);
309 } else {
310 char normalizedPath[B_PATH_NAME_LENGTH];
311 error = _kern_normalize_path(path, true, normalizedPath);
312 if (error == B_OK)
313 error = copy_path(path, buffer, bufferSize);
314 }
315
316 if (error != B_OK)
317 return error;
318
319 // make sure the path exists
320 struct stat st;
321 if (lstat(buffer, &st) != 0)
322 return errno;
323
324 return B_OK;
325 }
326
327
328 static status_t
normalize_longest_existing_path_prefix(const char * path,char * buffer,size_t bufferSize)329 normalize_longest_existing_path_prefix(const char* path, char* buffer,
330 size_t bufferSize)
331 {
332 if (strlcpy(buffer, path, bufferSize) >= bufferSize)
333 return B_NAME_TOO_LONG;
334
335 // Until we have an existing path, chop off leaf components.
336 for (;;) {
337 struct stat st;
338 if (lstat(buffer, &st) == 0)
339 break;
340
341 // Chop off the leaf, but fail, it it's "..", since then we'd actually
342 // construct a subpath.
343 char* lastSlash = strrchr(buffer, '/');
344 if (lastSlash == NULL || strcmp(lastSlash + 1, "..") == 0)
345 return B_ENTRY_NOT_FOUND;
346
347 *lastSlash = '\0';
348 }
349
350 // normalize the existing prefix path
351 size_t prefixLength = strlen(buffer);
352 status_t error = normalize_path(buffer, buffer, bufferSize);
353 if (error != B_OK)
354 return error;
355
356 // Re-append the non-existent suffix. Remove duplicate slashes and "."
357 // components.
358 const char* bufferEnd = buffer + bufferSize;
359 char* end = buffer + strlen(buffer);
360 const char* remainder = path + prefixLength + 1;
361 while (*remainder != '\0') {
362 // find component start
363 if (*remainder == '/') {
364 remainder++;
365 continue;
366 }
367
368 // find component end
369 const char* componentEnd = strchr(remainder, '/');
370 if (componentEnd == NULL)
371 componentEnd = remainder + strlen(remainder);
372
373 // skip "." components
374 size_t componentLength = componentEnd - remainder;
375 if (componentLength == 1 && *remainder == '.') {
376 remainder++;
377 continue;
378 }
379
380 // append the component
381 if (end + 1 + componentLength >= bufferEnd)
382 return B_BUFFER_OVERFLOW;
383
384 *end++ = '/';
385 memcpy(end, remainder, componentLength);
386 end += componentLength;
387 remainder += componentLength;
388 }
389
390 *end = '\0';
391 return B_OK;
392 }
393
394
395 static status_t
get_file_attribute(const char * path,const char * attribute,char * nameBuffer,size_t bufferSize)396 get_file_attribute(const char* path, const char* attribute, char* nameBuffer,
397 size_t bufferSize)
398 {
399 int fd = fs_open_attr(path, attribute, B_STRING_TYPE,
400 O_RDONLY | O_NOTRAVERSE);
401 if (fd < 0)
402 return errno;
403
404 status_t error = B_OK;
405 ssize_t bytesRead = read(fd, nameBuffer, bufferSize - 1);
406 if (bytesRead < 0)
407 error = bytesRead;
408 else if (bytesRead == 0)
409 error = B_ENTRY_NOT_FOUND;
410 else
411 nameBuffer[bytesRead] = '\0';
412
413 fs_close_attr(fd);
414
415 return error;
416 }
417
418
419 static status_t
normalize_dependency(const char * dependency,char * buffer,size_t bufferSize)420 normalize_dependency(const char* dependency, char* buffer, size_t bufferSize)
421 {
422 if (strlcpy(buffer, dependency, bufferSize) >= bufferSize)
423 return B_NAME_TOO_LONG;
424
425 // replace all ':' with '~'
426 char* colon = buffer - 1;
427 while ((colon = strchr(colon + 1, ':')) != NULL)
428 *colon = '~';
429
430 return B_OK;
431 }
432
433
434 static ssize_t
process_path(const char * installationLocation,const char * architecture,const char * relativePath,const char * subPath,uint32 flags,char * pathBuffer,size_t bufferSize)435 process_path(const char* installationLocation, const char* architecture,
436 const char* relativePath, const char* subPath, uint32 flags,
437 char* pathBuffer, size_t bufferSize)
438 {
439 // copy the installation location
440 PathBuffer buffer(pathBuffer, bufferSize);
441 buffer.Append(installationLocation);
442
443 // append the relative path, expanding the architecture placeholder
444 if (const char* placeholder = strchr(relativePath, '%')) {
445 buffer.Append(relativePath, placeholder - relativePath);
446
447 if (architecture != NULL) {
448 buffer.Append("/", 1);
449 buffer.Append(architecture);
450 }
451
452 buffer.Append(placeholder + 1);
453 } else
454 buffer.Append(relativePath);
455
456 // append subpath, if given
457 if (subPath != NULL) {
458 buffer.Append("/", 1);
459 buffer.Append(subPath);
460 }
461
462 size_t totalLength = buffer.Length();
463 if (totalLength >= bufferSize)
464 return B_BUFFER_OVERFLOW;
465
466 // handle the flags
467 char* path = pathBuffer;
468
469 status_t error = B_OK;
470 if ((flags & B_FIND_PATH_CREATE_DIRECTORY) != 0) {
471 // create the directory
472 error = create_directory(path);
473 } else if ((flags & B_FIND_PATH_CREATE_PARENT_DIRECTORY) != 0) {
474 // create the parent directory
475 char* lastSlash = strrchr(path, '/');
476 *lastSlash = '\0';
477 error = create_directory(path);
478 *lastSlash = '/';
479 }
480
481 if (error != B_OK)
482 return error;
483
484 if ((flags & B_FIND_PATH_EXISTING_ONLY) != 0) {
485 // check if the entry exists
486 struct stat st;
487 if (lstat(path, &st) != 0)
488 return 0;
489 }
490
491 return totalLength + 1;
492 }
493
494
495 status_t
internal_path_for_path(char * referencePath,size_t referencePathSize,const char * dependency,const char * architecture,path_base_directory baseDirectory,const char * subPath,uint32 flags,char * pathBuffer,size_t bufferSize)496 internal_path_for_path(char* referencePath, size_t referencePathSize,
497 const char* dependency, const char* architecture,
498 path_base_directory baseDirectory, const char* subPath, uint32 flags,
499 char* pathBuffer, size_t bufferSize)
500 {
501 if (strcmp(architecture, __get_primary_architecture()) == 0)
502 architecture = NULL;
503
504 // resolve dependency
505 char packageName[B_FILE_NAME_LENGTH];
506 // Temporarily used here, permanently used below where
507 // B_FIND_PATH_PACKAGE_PATH is handled.
508 if (dependency != NULL) {
509 // get the versioned package name
510 status_t error = get_file_attribute(referencePath, "SYS:PACKAGE",
511 packageName, sizeof(packageName));
512 if (error != B_OK)
513 return error;
514
515 // normalize the dependency name
516 char normalizedDependency[B_FILE_NAME_LENGTH];
517 error = normalize_dependency(dependency, normalizedDependency,
518 sizeof(normalizedDependency));
519 if (error != B_OK)
520 return error;
521
522 // Compute the path of the dependency symlink. This will yield the
523 // installation location path when normalized.
524 if (snprintf(referencePath, referencePathSize,
525 kSystemPackageLinksDirectory "/%s/%s", packageName,
526 normalizedDependency)
527 >= (ssize_t)referencePathSize) {
528 return B_BUFFER_OVERFLOW;
529 }
530 }
531
532 // handle B_FIND_PATH_IMAGE_PATH
533 if (baseDirectory == B_FIND_PATH_IMAGE_PATH)
534 return copy_path(referencePath, pathBuffer, bufferSize);
535
536 // Handle B_FIND_PATH_PACKAGE_PATH: get the package file name and
537 // simply adjust our arguments to look the package file up in the packages
538 // directory.
539 if (baseDirectory == B_FIND_PATH_PACKAGE_PATH) {
540 status_t error = get_file_attribute(referencePath, "SYS:PACKAGE_FILE",
541 packageName, sizeof(packageName));
542 if (error != B_OK)
543 return error;
544
545 dependency = NULL;
546 subPath = packageName;
547 baseDirectory = B_FIND_PATH_PACKAGES_DIRECTORY;
548 flags = B_FIND_PATH_EXISTING_ONLY;
549 }
550
551 // normalize
552 status_t error = normalize_path(referencePath, referencePath,
553 referencePathSize);
554 if (error != B_OK)
555 return error;
556
557 // get the installation location
558 InstallationLocations* installationLocations = InstallationLocations::Get();
559 MethodDeleter<InstallationLocations, void, &InstallationLocations::Put>
560 installationLocationsDeleter(installationLocations);
561
562 size_t installationLocationIndex;
563 const char* installationLocation = installationLocations->LocationFor(
564 referencePath, installationLocationIndex);
565 if (installationLocation == NULL)
566 return B_ENTRY_NOT_FOUND;
567
568 // get base dir and process the path
569 const char* relativePath = get_relative_directory_path(
570 installationLocationIndex, baseDirectory);
571 if (relativePath == NULL)
572 return B_BAD_VALUE;
573
574 ssize_t pathSize = process_path(installationLocation, architecture,
575 relativePath, subPath, flags, pathBuffer, bufferSize);
576 if (pathSize <= 0)
577 return pathSize == 0 ? B_ENTRY_NOT_FOUND : pathSize;
578 return B_OK;
579 }
580
581
582 // #pragma mark -
583
584
585 status_t
__find_path(const void * codePointer,path_base_directory baseDirectory,const char * subPath,char * pathBuffer,size_t bufferSize)586 __find_path(const void* codePointer, path_base_directory baseDirectory,
587 const char* subPath, char* pathBuffer, size_t bufferSize)
588 {
589 return __find_path_etc(codePointer, NULL, NULL, baseDirectory, subPath, 0,
590 pathBuffer, bufferSize);
591 }
592
593
594 status_t
__find_path_etc(const void * codePointer,const char * dependency,const char * architecture,path_base_directory baseDirectory,const char * subPath,uint32 flags,char * pathBuffer,size_t bufferSize)595 __find_path_etc(const void* codePointer, const char* dependency,
596 const char* architecture, path_base_directory baseDirectory,
597 const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize)
598 {
599 if (pathBuffer == NULL)
600 return B_BAD_VALUE;
601
602 // resolve codePointer to image info
603 image_info imageInfo;
604 status_t error = find_image(codePointer, imageInfo);
605 if (error != B_OK)
606 return error;
607
608 if (architecture == NULL)
609 architecture = __get_architecture();
610
611 return internal_path_for_path(imageInfo.name, sizeof(imageInfo.name),
612 dependency, architecture, baseDirectory, subPath, flags, pathBuffer,
613 bufferSize);
614 }
615
616
617 status_t
__find_path_for_path(const char * path,path_base_directory baseDirectory,const char * subPath,char * pathBuffer,size_t bufferSize)618 __find_path_for_path(const char* path, path_base_directory baseDirectory,
619 const char* subPath, char* pathBuffer, size_t bufferSize)
620 {
621 return __find_path_for_path_etc(path, NULL, NULL, baseDirectory, subPath, 0,
622 pathBuffer, bufferSize);
623 }
624
625
626 status_t
__find_path_for_path_etc(const char * path,const char * dependency,const char * architecture,path_base_directory baseDirectory,const char * subPath,uint32 flags,char * pathBuffer,size_t bufferSize)627 __find_path_for_path_etc(const char* path, const char* dependency,
628 const char* architecture, path_base_directory baseDirectory,
629 const char* subPath, uint32 flags, char* pathBuffer, size_t bufferSize)
630 {
631 if (baseDirectory == B_FIND_PATH_IMAGE_PATH)
632 return B_BAD_VALUE;
633
634 char referencePath[B_PATH_NAME_LENGTH];
635 if (strlcpy(referencePath, path, sizeof(referencePath))
636 >= sizeof(referencePath)) {
637 return B_NAME_TOO_LONG;
638 }
639
640 if (architecture == NULL)
641 architecture = __guess_architecture_for_path(path);
642
643 return internal_path_for_path(referencePath, sizeof(referencePath),
644 dependency, architecture, baseDirectory, subPath, flags, pathBuffer,
645 bufferSize);
646 }
647
648
649 status_t
__find_paths(path_base_directory baseDirectory,const char * subPath,char *** _paths,size_t * _pathCount)650 __find_paths(path_base_directory baseDirectory, const char* subPath,
651 char*** _paths, size_t* _pathCount)
652 {
653 return __find_paths_etc(NULL, baseDirectory, subPath, 0, _paths,
654 _pathCount);
655 }
656
657
658 status_t
__find_paths_etc(const char * architecture,path_base_directory baseDirectory,const char * subPath,uint32 flags,char *** _paths,size_t * _pathCount)659 __find_paths_etc(const char* architecture, path_base_directory baseDirectory,
660 const char* subPath, uint32 flags, char*** _paths, size_t* _pathCount)
661 {
662 if (_paths == NULL || _pathCount == NULL)
663 return B_BAD_VALUE;
664
665 // Analyze architecture. If NULL, use the caller's architecture. If the
666 // effective architecture is the primary one, set architecture to NULL to
667 // indicate that we don't need to insert an architecture subdirectory
668 // component.
669 if (architecture == NULL)
670 architecture = __get_architecture();
671 if (strcmp(architecture, __get_primary_architecture()) == 0)
672 architecture = NULL;
673 size_t architectureSize = architecture != NULL
674 ? strlen(architecture) + 1 : 0;
675
676 size_t subPathLength = subPath != NULL ? strlen(subPath) + 1 : 0;
677
678 // get the installation locations
679 InstallationLocations* installationLocations = InstallationLocations::Get();
680 MethodDeleter<InstallationLocations, void, &InstallationLocations::Put>
681 installationLocationsDeleter(installationLocations);
682
683 // Get the relative paths and compute the total size to allocate.
684 const char* relativePaths[InstallationLocations::kCount];
685 size_t totalSize = 0;
686
687 for (size_t i = 0; i < InstallationLocations::kCount; i++) {
688 if (((flags & B_FIND_PATHS_USER_ONLY) != 0
689 && !installationLocations->IsUserIndex(i))
690 || ((flags & B_FIND_PATHS_SYSTEM_ONLY) != 0
691 && !installationLocations->IsSystemIndex(i)))
692 continue;
693
694 relativePaths[i] = get_relative_directory_path(i, baseDirectory);
695 if (relativePaths[i] == NULL)
696 return B_BAD_VALUE;
697
698 totalSize += strlen(installationLocations->At(i))
699 + strlen(relativePaths[i]) + subPathLength + 1;
700 if (strchr(relativePaths[i], '%') != NULL)
701 totalSize += architectureSize - 1;
702 }
703
704 // allocate storage
705 char** paths = (char**)malloc(sizeof(char*) * InstallationLocations::kCount
706 + totalSize);
707 if (paths == NULL)
708 return B_NO_MEMORY;
709 MemoryDeleter pathsDeleter(paths);
710
711 // construct and process the paths
712 size_t count = 0;
713 char* pathBuffer = (char*)(paths + InstallationLocations::kCount);
714 const char* pathBufferEnd = pathBuffer + totalSize;
715 for (size_t i = 0; i < InstallationLocations::kCount; i++) {
716 if (((flags & B_FIND_PATHS_USER_ONLY) != 0
717 && !installationLocations->IsUserIndex(i))
718 || ((flags & B_FIND_PATHS_SYSTEM_ONLY) != 0
719 && !installationLocations->IsSystemIndex(i)))
720 continue;
721
722 ssize_t pathSize = process_path(installationLocations->At(i),
723 architecture, relativePaths[i], subPath, flags, pathBuffer,
724 pathBufferEnd - pathBuffer);
725 if (pathSize < 0)
726 return pathSize;
727 if (pathSize > 0) {
728 paths[count++] = pathBuffer;
729 pathBuffer += pathSize;
730 }
731 }
732
733 if (count == 0)
734 return B_ENTRY_NOT_FOUND;
735
736 *_paths = paths;
737 *_pathCount = count;
738 pathsDeleter.Detach();
739
740 return B_OK;
741 }
742
743
744 const char*
__guess_secondary_architecture_from_path(const char * path,const char * const * secondaryArchitectures,size_t secondaryArchitectureCount)745 __guess_secondary_architecture_from_path(const char* path,
746 const char* const* secondaryArchitectures,
747 size_t secondaryArchitectureCount)
748 {
749 // Get the longest existing prefix path and normalize it.
750 char prefix[B_PATH_NAME_LENGTH];
751 if (normalize_longest_existing_path_prefix(path, prefix, sizeof(prefix))
752 != B_OK) {
753 return NULL;
754 }
755
756 // get an installation location relative path
757 InstallationLocations* installationLocations = InstallationLocations::Get();
758 MethodDeleter<InstallationLocations, void, &InstallationLocations::Put>
759 installationLocationsDeleter(installationLocations);
760
761 size_t installationLocationIndex;
762 const char* installationLocation = installationLocations->LocationFor(
763 prefix, installationLocationIndex);
764 if (installationLocation == NULL)
765 return NULL;
766
767 const char* relativePath = prefix + strlen(installationLocation);
768 if (relativePath[0] != '/')
769 return NULL;
770
771 // Iterate through the known paths that would indicate a secondary
772 // architecture and try to match them with our given path.
773 for (size_t i = 0; i < kArchitectureSpecificBaseDirectoryCount; i++) {
774 const char* basePath = get_relative_directory_path(
775 installationLocationIndex, kArchitectureSpecificBaseDirectories[i]);
776 const char* placeholder = strchr(basePath, '%');
777 if (placeholder == NULL)
778 continue;
779
780 // match the part up to the architecture placeholder
781 size_t prefixLength = placeholder - basePath;
782 if (strncmp(relativePath, basePath, prefixLength) != 0
783 || relativePath[prefixLength] != '/') {
784 continue;
785 }
786
787 // match the architecture
788 const char* architecturePart = relativePath + prefixLength + 1;
789 for (size_t k = 0; k < secondaryArchitectureCount; k++) {
790 const char* architecture = secondaryArchitectures[k];
791 size_t architectureLength = strlen(architecture);
792 if (strncmp(architecturePart, architecture, architectureLength) == 0
793 && (architecturePart[architectureLength] == '/'
794 || architecturePart[architectureLength] == '\0')) {
795 return architecture;
796 }
797 }
798 }
799
800 return NULL;
801 }
802
803
804 B_DEFINE_WEAK_ALIAS(__find_path, find_path);
805 B_DEFINE_WEAK_ALIAS(__find_path_etc, find_path_etc);
806 B_DEFINE_WEAK_ALIAS(__find_path_for_path, find_path_for_path);
807 B_DEFINE_WEAK_ALIAS(__find_path_for_path_etc, find_path_for_path_etc);
808 B_DEFINE_WEAK_ALIAS(__find_paths, find_paths);
809 B_DEFINE_WEAK_ALIAS(__find_paths_etc, find_paths_etc);
810