File: | src/system/libroot/os/find_paths.cpp |
Warning: | line 131, column 3 Potential leak of memory pointed to by 'locations' |
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(*(_errnop())).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: | |||
49 | InstallationLocations() | |||
50 | : | |||
51 | fReferenceCount(1) | |||
52 | { | |||
53 | fLocations[0] = kUserNonpackagedDirectory"/boot/home/config/non-packaged"; | |||
54 | fLocations[1] = kUserConfigDirectory"/boot/home/config"; | |||
55 | fLocations[2] = kSystemNonpackagedDirectory"/boot/system/non-packaged"; | |||
56 | fLocations[3] = kSystemDirectory"/boot/system"; | |||
57 | } | |||
58 | ||||
59 | 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__null) { | |||
68 | strcpy(homeNonPackaged, home); | |||
69 | strcat(homeNonPackaged, kNonPackagedSuffix); | |||
70 | } | |||
71 | ||||
72 | fLocations[1] = strdup(home); | |||
73 | ||||
74 | fLocations[2] = kSystemNonpackagedDirectory"/boot/system/non-packaged"; | |||
75 | fLocations[3] = kSystemDirectory"/boot/system"; | |||
76 | } | |||
77 | ||||
78 | ~InstallationLocations() | |||
79 | { | |||
80 | free(const_cast<char*>(fLocations[0])); | |||
81 | free(const_cast<char*>(fLocations[1])); | |||
82 | } | |||
83 | ||||
84 | bool IsValid() const | |||
85 | { | |||
86 | return fLocations[0] != NULL__null && fLocations[1] != NULL__null; | |||
87 | } | |||
88 | ||||
89 | bool IsUserIndex(size_t index) const | |||
90 | { | |||
91 | return index==0 || index==1; | |||
92 | } | |||
93 | ||||
94 | bool IsSystemIndex(size_t index) const | |||
95 | { | |||
96 | return index==2 || index==3; | |||
97 | } | |||
98 | ||||
99 | static InstallationLocations* Default() | |||
100 | { | |||
101 | static char sBuffer[sizeof(InstallationLocations)]; | |||
102 | static InstallationLocations* sDefaultLocations | |||
103 | = new(&sBuffer) InstallationLocations; | |||
104 | return sDefaultLocations; | |||
105 | } | |||
106 | ||||
107 | 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(1024)]; | |||
114 | if (__find_directory(B_USER_CONFIG_DIRECTORY, -1, false, | |||
115 | homeInstallationLocation, sizeof(homeInstallationLocation)) | |||
116 | == B_OK((int)0)) { | |||
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__null && locations->IsValid()) | |||
127 | return locations; | |||
128 | } | |||
129 | } | |||
130 | ||||
131 | atomic_add(&defaultLocations->fReferenceCount, 1); | |||
| ||||
132 | return defaultLocations; | |||
133 | } | |||
134 | ||||
135 | void Put() | |||
136 | { | |||
137 | if (atomic_add(&fReferenceCount, -1) == 1) | |||
138 | delete this; | |||
139 | } | |||
140 | ||||
141 | const char* At(size_t index) const | |||
142 | { | |||
143 | return fLocations[index]; | |||
144 | } | |||
145 | ||||
146 | const char* LocationFor(const char* path, size_t& _index) | |||
147 | { | |||
148 | for (size_t i = 0; i < kCount; i++) { | |||
149 | size_t length = strlen(fLocations[i]); | |||
150 | if (strncmp(path, fLocations[i], length) == 0 | |||
151 | && (path[length] == '/' || path[length] == '\0')) { | |||
152 | _index = i; | |||
153 | return fLocations[i]; | |||
154 | } | |||
155 | } | |||
156 | ||||
157 | return NULL__null; | |||
158 | } | |||
159 | ||||
160 | private: | |||
161 | int32 fReferenceCount; | |||
162 | const char* fLocations[kCount]; | |||
163 | }; | |||
164 | ||||
165 | ||||
166 | } // unnamed namespace | |||
167 | ||||
168 | ||||
169 | /*! Returns the installation location relative path for the given base directory | |||
170 | constant and installation location index. A '%' in the returned path must be | |||
171 | replaced by "" for the primary architecture and by "/<arch>" for a secondary | |||
172 | architecture. | |||
173 | */ | |||
174 | static const char* | |||
175 | get_relative_directory_path(size_t installationLocationIndex, | |||
176 | path_base_directory baseDirectory) | |||
177 | { | |||
178 | switch (baseDirectory) { | |||
179 | case B_FIND_PATH_INSTALLATION_LOCATION_DIRECTORY: | |||
180 | return ""; | |||
181 | case B_FIND_PATH_ADD_ONS_DIRECTORY: | |||
182 | return "/add-ons%"; | |||
183 | case B_FIND_PATH_APPS_DIRECTORY: | |||
184 | return "/apps"; | |||
185 | case B_FIND_PATH_BIN_DIRECTORY: | |||
186 | return "/bin%"; | |||
187 | case B_FIND_PATH_BOOT_DIRECTORY: | |||
188 | return "/boot"; | |||
189 | case B_FIND_PATH_CACHE_DIRECTORY: | |||
190 | return "/cache"; | |||
191 | case B_FIND_PATH_DATA_DIRECTORY: | |||
192 | return "/data"; | |||
193 | case B_FIND_PATH_DEVELOP_DIRECTORY: | |||
194 | return "/develop"; | |||
195 | case B_FIND_PATH_DEVELOP_LIB_DIRECTORY: | |||
196 | return "/develop/lib%"; | |||
197 | case B_FIND_PATH_DOCUMENTATION_DIRECTORY: | |||
198 | return "/documentation"; | |||
199 | case B_FIND_PATH_ETC_DIRECTORY: | |||
200 | return "/settings/etc"; | |||
201 | case B_FIND_PATH_FONTS_DIRECTORY: | |||
202 | return "/data/fonts"; | |||
203 | case B_FIND_PATH_HEADERS_DIRECTORY: | |||
204 | return "/develop/headers%"; | |||
205 | case B_FIND_PATH_LIB_DIRECTORY: | |||
206 | return "/lib%"; | |||
207 | case B_FIND_PATH_LOG_DIRECTORY: | |||
208 | return "/log"; | |||
209 | case B_FIND_PATH_MEDIA_NODES_DIRECTORY: | |||
210 | return "/add-ons%/media"; | |||
211 | case B_FIND_PATH_PACKAGES_DIRECTORY: | |||
212 | return "/packages"; | |||
213 | case B_FIND_PATH_PREFERENCES_DIRECTORY: | |||
214 | return "/preferences"; | |||
215 | case B_FIND_PATH_SERVERS_DIRECTORY: | |||
216 | return "/servers"; | |||
217 | case B_FIND_PATH_SETTINGS_DIRECTORY: | |||
218 | return installationLocationIndex == kHomeInstallationLocationIndex | |||
219 | ? "/settings/global" : "/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__null; | |||
233 | } | |||
234 | } | |||
235 | ||||
236 | ||||
237 | static status_t | |||
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__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((int)0); | |||
253 | ||||
254 | // create directories | |||
255 | while (slash != NULL__null) { | |||
256 | *slash = '\0'; | |||
257 | bool created = mkdir(path, 0755); | |||
258 | *slash = '/'; | |||
259 | ||||
260 | if (!created) | |||
261 | return errno(*(_errnop())); | |||
262 | ||||
263 | slash = strchr(slash + 1, '/'); | |||
264 | } | |||
265 | ||||
266 | return B_OK((int)0); | |||
267 | } | |||
268 | ||||
269 | ||||
270 | static bool | |||
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 | |||
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)_get_next_image_info((0), (&cookie), (&_info), sizeof (*(&_info))) == B_OK((int)0)) { | |||
283 | if (codePointer == NULL__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((int)0); | |||
287 | } | |||
288 | } | |||
289 | ||||
290 | return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3); | |||
291 | } | |||
292 | ||||
293 | ||||
294 | static status_t | |||
295 | copy_path(const char* path, char* buffer, size_t bufferSize) | |||
296 | { | |||
297 | if (strlcpy(buffer, path, bufferSize) >= bufferSize) | |||
298 | return B_BUFFER_OVERFLOW((((-2147483647 - 1) + 0x7000) + 41)); | |||
299 | return B_OK((int)0); | |||
300 | } | |||
301 | ||||
302 | ||||
303 | static status_t | |||
304 | normalize_path(const char* path, char* buffer, size_t bufferSize) | |||
305 | { | |||
306 | status_t error; | |||
307 | if (bufferSize >= B_PATH_NAME_LENGTH(1024)) { | |||
308 | error = _kern_normalize_path(path, true, buffer); | |||
309 | } else { | |||
310 | char normalizedPath[B_PATH_NAME_LENGTH(1024)]; | |||
311 | error = _kern_normalize_path(path, true, normalizedPath); | |||
312 | if (error == B_OK((int)0)) | |||
313 | error = copy_path(path, buffer, bufferSize); | |||
314 | } | |||
315 | ||||
316 | if (error != B_OK((int)0)) | |||
317 | return error; | |||
318 | ||||
319 | // make sure the path exists | |||
320 | struct stat st; | |||
321 | if (lstat(buffer, &st) != 0) | |||
322 | return errno(*(_errnop())); | |||
323 | ||||
324 | return B_OK((int)0); | |||
325 | } | |||
326 | ||||
327 | ||||
328 | static status_t | |||
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(((-2147483647 - 1) + 0x6000) + 4); | |||
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__null || strcmp(lastSlash + 1, "..") == 0) | |||
345 | return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3); | |||
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((int)0)) | |||
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__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((((-2147483647 - 1) + 0x7000) + 41)); | |||
383 | ||||
384 | *end++ = '/'; | |||
385 | memcpy(end, remainder, componentLength); | |||
386 | end += componentLength; | |||
387 | remainder += componentLength; | |||
388 | } | |||
389 | ||||
390 | *end = '\0'; | |||
391 | return B_OK((int)0); | |||
392 | } | |||
393 | ||||
394 | ||||
395 | static status_t | |||
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_RDONLY0x0000 | O_NOTRAVERSE0x2000); | |||
401 | if (fd < 0) | |||
402 | return errno(*(_errnop())); | |||
403 | ||||
404 | status_t error = B_OK((int)0); | |||
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(((-2147483647 - 1) + 0x6000) + 3); | |||
410 | else | |||
411 | nameBuffer[bytesRead] = '\0'; | |||
412 | ||||
413 | fs_close_attr(fd); | |||
414 | ||||
415 | return error; | |||
416 | } | |||
417 | ||||
418 | ||||
419 | static status_t | |||
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(((-2147483647 - 1) + 0x6000) + 4); | |||
424 | ||||
425 | // replace all ':' with '~' | |||
426 | char* colon = buffer - 1; | |||
427 | while ((colon = strchr(colon + 1, ':')) != NULL__null) | |||
428 | *colon = '~'; | |||
429 | ||||
430 | return B_OK((int)0); | |||
431 | } | |||
432 | ||||
433 | ||||
434 | static ssize_t | |||
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__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__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((((-2147483647 - 1) + 0x7000) + 41)); | |||
465 | ||||
466 | // handle the flags | |||
467 | char* path = pathBuffer; | |||
468 | ||||
469 | status_t error = B_OK((int)0); | |||
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((int)0)) | |||
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 | |||
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__null; | |||
503 | ||||
504 | // resolve dependency | |||
505 | char packageName[B_FILE_NAME_LENGTH(256)]; | |||
506 | // Temporarily used here, permanently used below where | |||
507 | // B_FIND_PATH_PACKAGE_PATH is handled. | |||
508 | if (dependency != NULL__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((int)0)) | |||
513 | return error; | |||
514 | ||||
515 | // normalize the dependency name | |||
516 | char normalizedDependency[B_FILE_NAME_LENGTH(256)]; | |||
517 | error = normalize_dependency(dependency, normalizedDependency, | |||
518 | sizeof(normalizedDependency)); | |||
519 | if (error != B_OK((int)0)) | |||
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"/boot/system/package-links" "/%s/%s", packageName, | |||
526 | normalizedDependency) | |||
527 | >= (ssize_t)referencePathSize) { | |||
528 | return B_BUFFER_OVERFLOW((((-2147483647 - 1) + 0x7000) + 41)); | |||
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((int)0)) | |||
543 | return error; | |||
544 | ||||
545 | dependency = NULL__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((int)0)) | |||
555 | return error; | |||
556 | ||||
557 | // get the installation location | |||
558 | InstallationLocations* installationLocations = InstallationLocations::Get(); | |||
559 | MethodDeleter<InstallationLocations> installationLocationsDeleter( | |||
560 | installationLocations, &InstallationLocations::Put); | |||
561 | ||||
562 | size_t installationLocationIndex; | |||
563 | const char* installationLocation = installationLocations->LocationFor( | |||
564 | referencePath, installationLocationIndex); | |||
565 | if (installationLocation == NULL__null) | |||
566 | return B_ENTRY_NOT_FOUND(((-2147483647 - 1) + 0x6000) + 3); | |||
567 | ||||
568 | // get base dir and process the path | |||
569 | const char* relativePath = get_relative_directory_path( | |||
570 | installationLocationIndex, baseDirectory); | |||
571 | if (relativePath == NULL__null) | |||
572 | return B_BAD_VALUE((-2147483647 - 1) + 5); | |||
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(((-2147483647 - 1) + 0x6000) + 3) : pathSize; | |||
578 | return B_OK((int)0); | |||
579 | } | |||
580 | ||||
581 | ||||
582 | // #pragma mark - | |||
583 | ||||
584 | ||||
585 | status_t | |||
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, NULL__null, baseDirectory, subPath, 0, | |||
590 | pathBuffer, bufferSize); | |||
591 | } | |||
592 | ||||
593 | ||||
594 | status_t | |||
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__null) | |||
600 | return B_BAD_VALUE((-2147483647 - 1) + 5); | |||
601 | ||||
602 | // resolve codePointer to image info | |||
603 | image_info imageInfo; | |||
604 | status_t error = find_image(codePointer, imageInfo); | |||
605 | if (error != B_OK((int)0)) | |||
606 | return error; | |||
607 | ||||
608 | if (architecture == NULL__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 | |||
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, NULL__null, baseDirectory, subPath, 0, | |||
622 | pathBuffer, bufferSize); | |||
623 | } | |||
624 | ||||
625 | ||||
626 | status_t | |||
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((-2147483647 - 1) + 5); | |||
633 | ||||
634 | char referencePath[B_PATH_NAME_LENGTH(1024)]; | |||
635 | if (strlcpy(referencePath, path, sizeof(referencePath)) | |||
636 | >= sizeof(referencePath)) { | |||
637 | return B_NAME_TOO_LONG(((-2147483647 - 1) + 0x6000) + 4); | |||
638 | } | |||
639 | ||||
640 | if (architecture == NULL__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 | |||
650 | __find_paths(path_base_directory baseDirectory, const char* subPath, | |||
651 | char*** _paths, size_t* _pathCount) | |||
652 | { | |||
653 | return __find_paths_etc(NULL__null, baseDirectory, subPath, 0, _paths, | |||
654 | _pathCount); | |||
655 | } | |||
656 | ||||
657 | ||||
658 | status_t | |||
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__null || _pathCount == NULL__null) | |||
663 | return B_BAD_VALUE((-2147483647 - 1) + 5); | |||
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__null) | |||
670 | architecture = __get_architecture(); | |||
671 | if (strcmp(architecture, __get_primary_architecture()) == 0) | |||
672 | architecture = NULL__null; | |||
673 | size_t architectureSize = architecture != NULL__null | |||
674 | ? strlen(architecture) + 1 : 0; | |||
675 | ||||
676 | size_t subPathLength = subPath != NULL__null ? strlen(subPath) + 1 : 0; | |||
677 | ||||
678 | // get the installation locations | |||
679 | InstallationLocations* installationLocations = InstallationLocations::Get(); | |||
680 | MethodDeleter<InstallationLocations> installationLocationsDeleter( | |||
681 | installationLocations, &InstallationLocations::Put); | |||
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__null) | |||
696 | return B_BAD_VALUE((-2147483647 - 1) + 5); | |||
697 | ||||
698 | totalSize += strlen(installationLocations->At(i)) | |||
699 | + strlen(relativePaths[i]) + subPathLength + 1; | |||
700 | if (strchr(relativePaths[i], '%') != NULL__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__null) | |||
708 | return B_NO_MEMORY((-2147483647 - 1) + 0); | |||
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(((-2147483647 - 1) + 0x6000) + 3); | |||
735 | ||||
736 | *_paths = paths; | |||
737 | *_pathCount = count; | |||
738 | pathsDeleter.Detach(); | |||
739 | ||||
740 | return B_OK((int)0); | |||
741 | } | |||
742 | ||||
743 | ||||
744 | const char* | |||
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(1024)]; | |||
751 | if (normalize_longest_existing_path_prefix(path, prefix, sizeof(prefix)) | |||
| ||||
752 | != B_OK((int)0)) { | |||
753 | return NULL__null; | |||
754 | } | |||
755 | ||||
756 | // get an installation location relative path | |||
757 | InstallationLocations* installationLocations = InstallationLocations::Get(); | |||
758 | MethodDeleter<InstallationLocations> installationLocationsDeleter( | |||
759 | installationLocations, &InstallationLocations::Put); | |||
760 | ||||
761 | size_t installationLocationIndex; | |||
762 | const char* installationLocation = installationLocations->LocationFor( | |||
763 | prefix, installationLocationIndex); | |||
764 | if (installationLocation == NULL__null) | |||
765 | return NULL__null; | |||
766 | ||||
767 | const char* relativePath = prefix + strlen(installationLocation); | |||
768 | if (relativePath[0] != '/') | |||
769 | return NULL__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__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__null; | |||
801 | } | |||
802 | ||||
803 | ||||
804 | B_DEFINE_WEAK_ALIAS(__find_path, find_path)extern "C" __typeof(__find_path) find_path __attribute__((weak , alias("__find_path"))); | |||
805 | B_DEFINE_WEAK_ALIAS(__find_path_etc, find_path_etc)extern "C" __typeof(__find_path_etc) find_path_etc __attribute__ ((weak, alias("__find_path_etc"))); | |||
806 | B_DEFINE_WEAK_ALIAS(__find_path_for_path, find_path_for_path)extern "C" __typeof(__find_path_for_path) find_path_for_path __attribute__ ((weak, alias("__find_path_for_path"))); | |||
807 | B_DEFINE_WEAK_ALIAS(__find_path_for_path_etc, find_path_for_path_etc)extern "C" __typeof(__find_path_for_path_etc) find_path_for_path_etc __attribute__((weak, alias("__find_path_for_path_etc"))); | |||
808 | B_DEFINE_WEAK_ALIAS(__find_paths, find_paths)extern "C" __typeof(__find_paths) find_paths __attribute__((weak , alias("__find_paths"))); | |||
809 | B_DEFINE_WEAK_ALIAS(__find_paths_etc, find_paths_etc)extern "C" __typeof(__find_paths_etc) find_paths_etc __attribute__ ((weak, alias("__find_paths_etc"))); |