fix length check when reading a dictionary file
[RRG-proxmark3.git] / client / deps / whereami / whereami.c
blobca2220953565e8bb6643cca93ae693ed4d8ffbf4
1 // (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses
2 // without any warranty.
3 // by Gregory Pakosz (@gpakosz)
4 // https://github.com/gpakosz/whereami
6 #ifdef WAI_PM3_TUNED
8 #include "whereami.h"
10 #if defined(__linux__)
11 // make realpath() available:
12 #define _DEFAULT_SOURCE
13 #endif
15 #else // WAI_PM3_TUNED
17 // in case you want to #include "whereami.c" in a larger compilation unit
18 #if !defined(WHEREAMI_H)
19 #include <whereami.h>
20 #endif
22 #endif // WAI_PM3_TUNED
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
28 #if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC)
29 #include <stdlib.h>
30 #endif
32 #if !defined(WAI_MALLOC)
33 #define WAI_MALLOC(size) malloc(size)
34 #endif
36 #if !defined(WAI_FREE)
37 #define WAI_FREE(p) free(p)
38 #endif
40 #if !defined(WAI_REALLOC)
41 #define WAI_REALLOC(p, size) realloc(p, size)
42 #endif
44 #ifndef WAI_NOINLINE
45 #if defined(_MSC_VER)
46 #define WAI_NOINLINE __declspec(noinline)
47 #elif defined(__GNUC__)
48 #define WAI_NOINLINE __attribute__((noinline))
49 #else
50 #error unsupported compiler
51 #endif
52 #endif
54 #if defined(_MSC_VER)
55 #define WAI_RETURN_ADDRESS() _ReturnAddress()
56 #elif defined(__GNUC__)
57 #define WAI_RETURN_ADDRESS() __builtin_extract_return_addr(__builtin_return_address(0))
58 #else
59 #error unsupported compiler
60 #endif
62 #if defined(_WIN32)
64 #ifndef WIN32_LEAN_AND_MEAN
65 #define WIN32_LEAN_AND_MEAN
66 #endif
67 #if defined(_MSC_VER)
68 #pragma warning(push, 3)
69 #endif
70 #include <windows.h>
71 #include <intrin.h>
72 #if defined(_MSC_VER)
73 #pragma warning(pop)
74 #endif
76 static int WAI_PREFIX(getModulePath_)(HMODULE module, char *out, int capacity, int *dirname_length) {
77 wchar_t buffer1[MAX_PATH];
78 wchar_t buffer2[MAX_PATH];
79 wchar_t *path = NULL;
80 int length = -1;
82 for (;;) {
83 DWORD size;
84 int length_, length__;
86 size = GetModuleFileNameW(module, buffer1, sizeof(buffer1) / sizeof(buffer1[0]));
88 if (size == 0)
89 break;
90 else if (size == (DWORD)(sizeof(buffer1) / sizeof(buffer1[0]))) {
91 DWORD size_ = size;
92 do {
93 wchar_t *path_;
95 path_ = (wchar_t *)WAI_REALLOC(path, sizeof(wchar_t) * size_ * 2);
96 if (!path_)
97 break;
98 size_ *= 2;
99 path = path_;
100 size = GetModuleFileNameW(module, path, size_);
101 } while (size == size_);
103 if (size == size_)
104 break;
105 } else
106 path = buffer1;
108 if (!_wfullpath(buffer2, path, MAX_PATH))
109 break;
110 length_ = (int)wcslen(buffer2);
111 length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, out, capacity, NULL, NULL);
113 if (length__ == 0)
114 length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, NULL, 0, NULL, NULL);
115 if (length__ == 0)
116 break;
118 if (length__ <= capacity && dirname_length) {
119 int i;
121 for (i = length__ - 1; i >= 0; --i) {
122 if (out[i] == '\\') {
123 *dirname_length = i;
124 break;
129 length = length__;
131 break;
134 if (path != buffer1)
135 WAI_FREE(path);
137 return length;
140 WAI_NOINLINE WAI_FUNCSPEC
141 int WAI_PREFIX(getExecutablePath)(char *out, int capacity, int *dirname_length) {
142 return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length);
145 // GetModuleHandleEx() is not available on old mingw environments. We don't need getModulePath() yet.
146 // Sacrifice it for the time being to improve backwards compatibility
147 #ifndef WAI_PM3_TUNED
149 WAI_NOINLINE WAI_FUNCSPEC
150 int WAI_PREFIX(getModulePath)(char *out, int capacity, int *dirname_length) {
151 HMODULE module;
152 int length = -1;
154 #if defined(_MSC_VER)
155 #pragma warning(push)
156 #pragma warning(disable: 4054)
157 #endif
158 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)WAI_RETURN_ADDRESS(), &module))
159 #if defined(_MSC_VER)
160 #pragma warning(pop)
161 #endif
163 length = WAI_PREFIX(getModulePath_)(module, out, capacity, dirname_length);
166 return length;
169 #endif // WAI_PM3_TUNED
171 #elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun) || defined(WAI_USE_PROC_SELF_EXE)
173 #include <stdio.h>
174 #include <stdlib.h>
175 #include <string.h>
176 #if defined(__linux__)
177 #include <linux/limits.h>
178 #else
179 #include <limits.h>
180 #endif
181 #ifndef __STDC_FORMAT_MACROS
182 #define __STDC_FORMAT_MACROS
183 #endif
184 #include <inttypes.h>
186 #if !defined(WAI_PROC_SELF_EXE)
187 #if defined(__sun)
188 #define WAI_PROC_SELF_EXE "/proc/self/path/a.out"
189 #else
190 #define WAI_PROC_SELF_EXE "/proc/self/exe"
191 #endif
192 #endif
194 WAI_FUNCSPEC
195 int WAI_PREFIX(getExecutablePath)(char *out, int capacity, int *dirname_length) {
196 char buffer[PATH_MAX];
197 char *resolved = NULL;
198 int length = -1;
200 for (;;) {
201 resolved = realpath(WAI_PROC_SELF_EXE, buffer);
202 if (!resolved)
203 break;
205 length = (int)strlen(resolved);
206 if (length <= capacity) {
207 memcpy(out, resolved, length);
209 if (dirname_length) {
210 int i;
212 for (i = length - 1; i >= 0; --i) {
213 if (out[i] == '/') {
214 *dirname_length = i;
215 break;
221 break;
224 return length;
227 #if !defined(WAI_PROC_SELF_MAPS_RETRY)
228 #define WAI_PROC_SELF_MAPS_RETRY 5
229 #endif
231 #if !defined(WAI_PROC_SELF_MAPS)
232 #if defined(__sun)
233 #define WAI_PROC_SELF_MAPS "/proc/self/map"
234 #else
235 #define WAI_PROC_SELF_MAPS "/proc/self/maps"
236 #endif
237 #endif
239 #if defined(__ANDROID__) || defined(ANDROID)
240 #include <fcntl.h>
241 #include <sys/mman.h>
242 #include <unistd.h>
243 #endif
245 #ifndef WAI_PM3_TUNED
247 WAI_NOINLINE WAI_FUNCSPEC
248 int WAI_PREFIX(getModulePath)(char *out, int capacity, int *dirname_length) {
249 int length = -1;
250 FILE *maps = NULL;
252 for (int r = 0; r < WAI_PROC_SELF_MAPS_RETRY; ++r) {
253 maps = fopen(WAI_PROC_SELF_MAPS, "r");
254 if (!maps)
255 break;
257 for (;;) {
258 char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX];
259 uint64_t low, high;
260 char perms[5];
261 uint64_t offset;
262 uint32_t major, minor;
263 char path[PATH_MAX];
264 uint32_t inode;
266 if (!fgets(buffer, sizeof(buffer), maps))
267 break;
269 if (sscanf(buffer, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %u %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8) {
270 uint64_t addr = (uintptr_t)WAI_RETURN_ADDRESS();
271 if (low <= addr && addr <= high) {
272 char *resolved;
274 resolved = realpath(path, buffer);
275 if (!resolved)
276 break;
278 length = (int)strlen(resolved);
279 #if defined(__ANDROID__) || defined(ANDROID)
280 if (length > 4
281 && buffer[length - 1] == 'k'
282 && buffer[length - 2] == 'p'
283 && buffer[length - 3] == 'a'
284 && buffer[length - 4] == '.') {
285 int fd = open(path, O_RDONLY);
286 char *begin;
287 char *p;
289 begin = (char *)mmap(0, offset + sizeof(p), PROT_READ, MAP_SHARED, fd, 0);
290 p = begin + offset;
292 while (p >= begin) { // scan backwards
293 if (*((uint32_t *)p) == 0x04034b50UL) { // local file header found
294 uint16_t length_ = *((uint16_t *)(p + 26));
296 if (length + 2 + length_ < (int)sizeof(buffer)) {
297 memcpy(&buffer[length], "!/", 2);
298 memcpy(&buffer[length + 2], p + 30, length_);
299 length += 2 + length_;
302 break;
305 --p;
308 munmap(begin, offset);
309 close(fd);
311 #endif
312 if (length <= capacity) {
313 memcpy(out, resolved, length);
315 if (dirname_length) {
316 int i;
318 for (i = length - 1; i >= 0; --i) {
319 if (out[i] == '/') {
320 *dirname_length = i;
321 break;
327 break;
332 fclose(maps);
333 maps = NULL;
335 if (length != -1)
336 break;
339 if (maps)
340 fclose(maps);
342 return length;
344 #endif // WAI_PM3_TUNED
346 #elif defined(__APPLE__)
348 #define _DARWIN_BETTER_REALPATH
349 #include <mach-o/dyld.h>
350 #include <limits.h>
351 #include <stdlib.h>
352 #include <string.h>
353 #include <dlfcn.h>
355 WAI_FUNCSPEC
356 int WAI_PREFIX(getExecutablePath)(char *out, int capacity, int *dirname_length) {
357 char buffer1[PATH_MAX];
358 char buffer2[PATH_MAX];
359 char *path = buffer1;
360 char *resolved = NULL;
361 int length = -1;
363 for (;;) {
364 uint32_t size = (uint32_t)sizeof(buffer1);
365 if (_NSGetExecutablePath(path, &size) == -1) {
366 path = (char *)WAI_MALLOC(size);
367 if (!_NSGetExecutablePath(path, &size))
368 break;
371 resolved = realpath(path, buffer2);
372 if (!resolved)
373 break;
375 length = (int)strlen(resolved);
376 if (length <= capacity) {
377 memcpy(out, resolved, length);
379 if (dirname_length) {
380 int i;
382 for (i = length - 1; i >= 0; --i) {
383 if (out[i] == '/') {
384 *dirname_length = i;
385 break;
391 break;
394 if (path != buffer1)
395 WAI_FREE(path);
397 return length;
400 #ifndef WAI_PM3_TUNED
402 WAI_NOINLINE WAI_FUNCSPEC
403 int WAI_PREFIX(getModulePath)(char *out, int capacity, int *dirname_length) {
404 char buffer[PATH_MAX];
405 char *resolved = NULL;
406 int length = -1;
408 for (;;) {
409 Dl_info info;
411 if (dladdr(WAI_RETURN_ADDRESS(), &info)) {
412 resolved = realpath(info.dli_fname, buffer);
413 if (!resolved)
414 break;
416 length = (int)strlen(resolved);
417 if (length <= capacity) {
418 memcpy(out, resolved, length);
420 if (dirname_length) {
421 int i;
423 for (i = length - 1; i >= 0; --i) {
424 if (out[i] == '/') {
425 *dirname_length = i;
426 break;
433 break;
436 return length;
439 #endif // WAI_PM3_TUNED
441 #elif defined(__QNXNTO__)
443 #include <limits.h>
444 #include <stdio.h>
445 #include <stdlib.h>
446 #include <string.h>
447 #include <dlfcn.h>
449 #if !defined(WAI_PROC_SELF_EXE)
450 #define WAI_PROC_SELF_EXE "/proc/self/exefile"
451 #endif
453 WAI_FUNCSPEC
454 int WAI_PREFIX(getExecutablePath)(char *out, int capacity, int *dirname_length) {
455 char buffer1[PATH_MAX];
456 char buffer2[PATH_MAX];
457 char *resolved = NULL;
458 FILE *self_exe = NULL;
459 int length = -1;
461 for (;;) {
462 self_exe = fopen(WAI_PROC_SELF_EXE, "r");
463 if (!self_exe)
464 break;
466 if (!fgets(buffer1, sizeof(buffer1), self_exe))
467 break;
469 resolved = realpath(buffer1, buffer2);
470 if (!resolved)
471 break;
473 length = (int)strlen(resolved);
474 if (length <= capacity) {
475 memcpy(out, resolved, length);
477 if (dirname_length) {
478 int i;
480 for (i = length - 1; i >= 0; --i) {
481 if (out[i] == '/') {
482 *dirname_length = i;
483 break;
489 break;
492 fclose(self_exe);
494 return length;
497 #ifndef WAI_PM3_TUNED
499 WAI_FUNCSPEC
500 int WAI_PREFIX(getModulePath)(char *out, int capacity, int *dirname_length) {
501 char buffer[PATH_MAX];
502 char *resolved = NULL;
503 int length = -1;
505 for (;;) {
506 Dl_info info;
508 if (dladdr(WAI_RETURN_ADDRESS(), &info)) {
509 resolved = realpath(info.dli_fname, buffer);
510 if (!resolved)
511 break;
513 length = (int)strlen(resolved);
514 if (length <= capacity) {
515 memcpy(out, resolved, length);
517 if (dirname_length) {
518 int i;
520 for (i = length - 1; i >= 0; --i) {
521 if (out[i] == '/') {
522 *dirname_length = i;
523 break;
530 break;
533 return length;
536 #endif // WAI_PM3_TUNED
538 #elif defined(__DragonFly__) || defined(__FreeBSD__) || \
539 defined(__FreeBSD_kernel__) || defined(__NetBSD__)
541 #include <limits.h>
542 #include <stdlib.h>
543 #include <string.h>
544 #include <sys/types.h>
545 #include <sys/sysctl.h>
546 #include <dlfcn.h>
548 WAI_FUNCSPEC
549 int WAI_PREFIX(getExecutablePath)(char *out, int capacity, int *dirname_length) {
550 char buffer1[PATH_MAX];
551 char buffer2[PATH_MAX];
552 char *path = buffer1;
553 char *resolved = NULL;
554 int length = -1;
556 for (;;) {
557 #if defined(__NetBSD__)
558 int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME };
559 #else
560 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
561 #endif
562 size_t size = sizeof(buffer1);
564 if (sysctl(mib, (u_int)(sizeof(mib) / sizeof(mib[0])), path, &size, NULL, 0) != 0)
565 break;
567 resolved = realpath(path, buffer2);
568 if (!resolved)
569 break;
571 length = (int)strlen(resolved);
572 if (length <= capacity) {
573 memcpy(out, resolved, length);
575 if (dirname_length) {
576 int i;
578 for (i = length - 1; i >= 0; --i) {
579 if (out[i] == '/') {
580 *dirname_length = i;
581 break;
587 break;
590 if (path != buffer1)
591 WAI_FREE(path);
593 return length;
596 #ifndef WAI_PM3_TUNED
598 WAI_NOINLINE WAI_FUNCSPEC
599 int WAI_PREFIX(getModulePath)(char *out, int capacity, int *dirname_length) {
600 char buffer[PATH_MAX];
601 char *resolved = NULL;
602 int length = -1;
604 for (;;) {
605 Dl_info info;
607 if (dladdr(WAI_RETURN_ADDRESS(), &info)) {
608 resolved = realpath(info.dli_fname, buffer);
609 if (!resolved)
610 break;
612 length = (int)strlen(resolved);
613 if (length <= capacity) {
614 memcpy(out, resolved, length);
616 if (dirname_length) {
617 int i;
619 for (i = length - 1; i >= 0; --i) {
620 if (out[i] == '/') {
621 *dirname_length = i;
622 break;
629 break;
632 return length;
635 #endif // WAI_PM3_TUNED
637 #else
639 #error unsupported platform
641 #endif
643 #ifdef __cplusplus
645 #endif