This source file includes following definitions.
- _sir_pathgetstat
- _sir_pathexists
- _sir_openfile
- _sir_getcwd
- _sir_getappfilename
- _sir_getappbasename
- _sir_getappdir
- _sir_getbasename
- _sir_getdirname
- _sir_ispathrelative
- _sir_getrelbasepath
- _sir_aixself
- _sir_aixself
- _sir_deletefile
- _sir_openbsdself
- _sir_resolvepath
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include "sir/filesystem.h"
35 #include "sir/internal.h"
36
37 #if defined(__WIN__)
38 # if defined(__EMBARCADEROC__) && defined(_WIN64)
39 # pragma comment(lib, "shlwapi.a")
40 # else
41 # pragma comment(lib, "shlwapi.lib")
42 # endif
43 #endif
44
45 bool _sir_pathgetstat(const char* restrict path, struct stat* restrict st, sir_rel_to rel_to) {
46 if (!_sir_validstr(path) || !_sir_validptr(st))
47 return false;
48
49 (void)memset(st, 0, sizeof(struct stat));
50
51 int stat_ret = -1;
52 bool relative = false;
53 const char* base_path = NULL;
54
55 if (!_sir_getrelbasepath(path, &relative, &base_path, rel_to))
56 return false;
57
58 if (relative) {
59 #if !defined(__WIN__)
60 # if defined(__MACOS__) || defined(_AIX) || defined(__EMSCRIPTEN__)
61 # if !defined(O_SEARCH)
62 int open_flags = O_DIRECTORY;
63 # else
64 int open_flags = O_SEARCH;
65 # endif
66 # elif defined(__linux__) || defined(__HURD__) || defined(__QNX__) || \
67 defined(__managarm__)
68 # if !defined(__SUNPRO_C) && !defined(__SUNPRO_CC) && defined(O_PATH)
69 int open_flags = O_PATH | O_DIRECTORY;
70 # else
71 int open_flags = O_DIRECTORY;
72 # endif
73 # elif defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__serenity__)
74 int open_flags = O_EXEC | O_DIRECTORY;
75 # elif defined(__SOLARIS__) || defined(__DragonFly__) || \
76 defined(__NetBSD__) || defined(__HAIKU__) || defined(__OpenBSD__)
77 int open_flags = O_DIRECTORY;
78 # else
79 # error "unknown open_flags for your platform; please contact the developers"
80 # endif
81
82 # if !(defined(_AIX) || !defined(__PASE__))
83 int fd = open(base_path, open_flags);
84 if (-1 == fd) {
85 _sir_safefree(&base_path);
86 return _sir_handleerr(errno);
87 }
88 stat_ret = fstatat(fd, path, st, AT_SYMLINK_NOFOLLOW);
89 # else
90
91 SIR_UNUSED(open_flags);
92 int fd = AT_FDCWD;
93 if (rel_to == SIR_PATH_REL_TO_CWD) {
94
95 stat_ret = fstatat(fd, path, st, AT_SYMLINK_NOFOLLOW);
96 } else if (rel_to == SIR_PATH_REL_TO_APP) {
97 char abs_path[SIR_MAXPATH] = {0};
98 (void)snprintf(abs_path, SIR_MAXPATH, "%s/%s", base_path, path);
99 stat_ret = stat(abs_path, st);
100 }
101 # endif
102 _sir_safeclose(&fd);
103 _sir_safefree(&base_path);
104 } else {
105 stat_ret = stat(path, st);
106 }
107 #else
108 char abs_path[SIR_MAXPATH] = {0};
109 (void)snprintf(abs_path, SIR_MAXPATH, "%s\\%s", base_path, path);
110
111 # if defined(__EMBARCADEROC__) && (__clang_major__ < 15)
112
113
114 char resolved_path[SIR_MAXPATH] = {0};
115 if (!GetFullPathNameA(abs_path, SIR_MAXPATH, resolved_path, NULL)) {
116 _sir_safefree(&base_path);
117 return _sir_handlewin32err(GetLastError());
118 }
119
120 PathRemoveBackslashA(resolved_path);
121 (void)_sir_strlcpy(abs_path, resolved_path, SIR_MAXPATH);
122 # endif
123
124 stat_ret = stat(abs_path, st);
125 _sir_safefree(&base_path);
126 } else {
127 stat_ret = stat(path, st);
128 }
129 #endif
130 if (-1 == stat_ret && (ENOENT == errno || ENOTDIR == errno))
131 st->st_size = SIR_STAT_NONEXISTENT;
132
133 return (-1 != stat_ret || ENOENT == errno || ENOTDIR == errno) ? true : _sir_handleerr(errno);
134 }
135
136 bool _sir_pathexists(const char* path, bool* exists, sir_rel_to rel_to) {
137 if (!_sir_validstr(path) || !_sir_validptr(exists))
138 return false;
139
140 *exists = false;
141
142 struct stat st = {0};
143 bool stat_ret = _sir_pathgetstat(path, &st, rel_to);
144 if (!stat_ret)
145 return false;
146
147 *exists = (st.st_size != SIR_STAT_NONEXISTENT);
148 return true;
149 }
150
151 bool _sir_openfile(FILE* restrict* restrict f, const char* restrict path,
152 const char* restrict mode, sir_rel_to rel_to) {
153 if (!_sir_validptrptr(f) || !_sir_validstr(path) || !_sir_validstr(mode))
154 return false;
155
156 bool relative = false;
157 const char* base_path = NULL;
158
159 if (!_sir_getrelbasepath(path, &relative, &base_path, rel_to))
160 return false;
161
162 if (relative) {
163 char abs_path[SIR_MAXPATH] = {0};
164 (void)snprintf(abs_path, SIR_MAXPATH, "%s/%s", base_path, path);
165
166 int ret = _sir_fopen(f, abs_path, mode);
167 _sir_safefree(&base_path);
168 return 0 == ret;
169 }
170
171 return 0 == _sir_fopen(f, path, mode);
172 }
173
174 #if defined(_AIX)
175 static char cur_cwd[SIR_MAXPATH];
176 #endif
177 char* _sir_getcwd(void) {
178 #if !defined(__WIN__)
179 # if defined(__linux__) && (defined(__GLIBC__) && defined(_GNU_SOURCE))
180 char* cur = get_current_dir_name();
181 if (!_sir_validptrnofail(cur))
182 (void)_sir_handleerr(errno);
183 return cur;
184 # elif defined(_AIX)
185 if (getcwd(cur_cwd, sizeof(cur_cwd)) == 0) {
186 (void)_sir_handleerr(errno);
187 return NULL;
188 } else {
189 return strndup(cur_cwd, SIR_MAXPATH);
190 }
191 # else
192 char* cur = getcwd(NULL, 0);
193 if (NULL == cur)
194 (void)_sir_handleerr(errno);
195 return cur;
196 # endif
197 #else
198 DWORD size = GetCurrentDirectoryA(0UL, NULL);
199 if (0UL == size) {
200 _sir_handlewin32err(GetLastError());
201 return NULL;
202 }
203
204 char* cur = calloc(size, sizeof(char));
205 if (!cur) {
206 (void)_sir_handleerr(errno);
207 return NULL;
208 }
209
210 if (!GetCurrentDirectoryA(size, cur)) {
211 _sir_handlewin32err(GetLastError());
212 _sir_safefree(cur);
213 return NULL;
214 }
215
216 return cur;
217 #endif
218 }
219
220 char* _sir_getappfilename(void) {
221 #if defined(__linux__) || defined(__NetBSD__) || defined(__SOLARIS__) || \
222 defined(__DragonFly__) || defined(__CYGWIN__) || defined(__serenity__) || \
223 defined(__HURD__) || defined(__EMSCRIPTEN__) || defined(__managarm__)
224 # define __READLINK_OS__
225 # if defined(__linux__) || defined(__CYGWIN__) || \
226 defined(__serenity__) || defined(__HURD__) || defined(__EMSCRIPTEN__) || \
227 defined(__managarm__)
228 # define PROC_SELF "/proc/self/exe"
229 # elif defined(__NetBSD__)
230 # define PROC_SELF "/proc/curproc/exe"
231 # elif defined(__DragonFly__)
232 # define PROC_SELF "/proc/curproc/file"
233 # elif defined(__SOLARIS__)
234 # define PROC_SELF "/proc/self/path/a.out"
235 # endif
236 struct stat st;
237 if (-1 == lstat(PROC_SELF, &st)) {
238 (void)_sir_handleerr(errno);
239 return NULL;
240 }
241
242 size_t size = (st.st_size > 0) ? st.st_size + 2 : SIR_MAXPATH;
243 #else
244 size_t size = SIR_MAXPATH;
245 #endif
246
247 char* buffer = NULL;
248 bool resolved = false;
249
250 do {
251 _sir_safefree(&buffer);
252 buffer = (char*)calloc(size, sizeof(char));
253 if (NULL == buffer) {
254 resolved = _sir_handleerr(errno);
255 break;
256 }
257
258 #if !defined(__WIN__)
259 # if defined(__READLINK_OS__)
260 ssize_t rdlink = _sir_readlink(PROC_SELF, buffer, size - 1);
261 if (-1L != rdlink && rdlink < (ssize_t)size - 1) {
262 resolved = true;
263 break;
264 } else if (-1L == rdlink) {
265 resolved = _sir_handleerr(errno);
266 break;
267 } else if (rdlink == (ssize_t)size - 1L) {
268
269
270 _sir_selflog("warning: readlink reported truncation; not using result!");
271 resolved = false;
272 break;
273 }
274 # elif defined(__QNX__)
275 FILE *self = fopen("/proc/self/exefile", "r");
276 if (!self) {
277 resolved = _sir_handleerr(errno);
278 break;
279 }
280 int ch;
281 size_t length = 0;
282 while ((ch = fgetc(self)) != EOF) {
283 if (length > size) {
284 size = length + 1;
285 continue;
286 }
287 buffer[length++] = ch;
288 }
289 int ret = fclose(self);
290 resolved = ret == 0 ? true : _sir_handleerr(errno);
291 break;
292 # elif defined(_AIX)
293 if (size <= SIR_MAXPATH) {
294 size = size + SIR_MAXPATH + 1L;
295 continue;
296 }
297 int ret = _sir_aixself(buffer, &size);
298 resolved = ret == 0 ? true : _sir_handleerr(errno);
299 break;
300 # elif defined(__OpenBSD__)
301 size_t length = (size_t)_sir_openbsdself(NULL, 0);
302 if (length < 1) {
303 resolved = _sir_handleerr(errno);
304 break;
305 }
306 if (length > size) {
307 size = length + 1;
308 continue;
309 }
310 (void)_sir_openbsdself(buffer, length);
311 resolved = _sir_validptrnofail(buffer);
312 break;
313 # elif defined(__BSD__)
314 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
315 int ret = sysctl(mib, 4, buffer, &size, NULL, 0);
316 if (0 == ret) {
317 resolved = true;
318 break;
319 } else {
320 if (ENOMEM == errno && 0 == sysctl(mib, 4, NULL, &size, NULL, 0))
321 continue;
322
323 resolved = _sir_handleerr(errno);
324 break;
325 }
326 # elif defined(__HAIKU__)
327 status_t ret =
328 find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, buffer, SIR_MAXPATH);
329 if (B_OK == ret) {
330 resolved = true;
331 break;
332 } else if (B_BUFFER_OVERFLOW == ret) {
333
334 continue;
335 } else {
336 resolved = _sir_handleerr(errno);
337 break;
338 }
339 # elif defined(__MACOS__)
340 int ret = _NSGetExecutablePath(buffer, (uint32_t*)&size);
341 if (0 == ret) {
342 resolved = true;
343 break;
344 } else if (-1 == ret) {
345
346 continue;
347 } else {
348 resolved = _sir_handleerr(errno);
349 break;
350 }
351 # else
352 # error "no implementation for your platform; please contact the developers"
353 # endif
354 #else
355 DWORD ret = GetModuleFileNameA(NULL, buffer, (DWORD)size);
356 if (0UL != ret && ret < (DWORD)size) {
357 resolved = true;
358 break;
359 } else if (0UL == ret) {
360 resolved = _sir_handlewin32err(GetLastError());
361 break;
362 } else if (ret == (DWORD)size || ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
363
364
365
366 size += SIR_PATH_BUFFER_GROW_BY;
367 continue;
368 }
369 #endif
370
371 } while (true);
372
373 if (!resolved)
374 _sir_safefree(&buffer);
375
376 return buffer;
377 }
378
379 char* _sir_getappbasename(void) {
380 char* filename = _sir_getappfilename();
381 if (!_sir_validstr(filename)) {
382 _sir_safefree(&filename);
383 return NULL;
384 }
385
386 const char* retval = _sir_getbasename(filename);
387 char* bname = strndup(retval, strnlen(retval, SIR_MAXPATH));
388
389 _sir_safefree(&filename);
390 return bname;
391 }
392
393 char* _sir_getappdir(void) {
394 char* filename = _sir_getappfilename();
395 if (!_sir_validstr(filename)) {
396 _sir_safefree(&filename);
397 return NULL;
398 }
399
400 const char* retval = _sir_getdirname(filename);
401 char* dname = strndup(retval, strnlen(retval, SIR_MAXPATH));
402
403 _sir_safefree(&filename);
404 return dname;
405 }
406
407 char* _sir_getbasename(char* restrict path) {
408 if (!_sir_validstr(path))
409 return ".";
410
411 #if !defined(__WIN__)
412 return basename(path);
413 #else
414 return PathFindFileNameA(path);
415 #endif
416 }
417
418 char* _sir_getdirname(char* restrict path) {
419 if (!_sir_validstr(path))
420 return ".";
421
422 #if !defined(__WIN__)
423 return dirname(path);
424 #else
425 (void)PathRemoveFileSpecA((LPSTR)path);
426 return path;
427 #endif
428 }
429
430 bool _sir_ispathrelative(const char* restrict path, bool* restrict relative) {
431 bool valid = _sir_validstr(path) && _sir_validptr(relative);
432
433 if (valid) {
434 #if !defined(__WIN__)
435 if (path[0] == '/' || (path[0] == '~' && path[1] == '/'))
436 *relative = false;
437 else
438 *relative = true;
439 #else
440 *relative = (TRUE == PathIsRelativeA(path));
441 #endif
442 }
443
444 return valid;
445 }
446
447 bool _sir_getrelbasepath(const char* restrict path, bool* restrict relative,
448 const char* restrict* restrict base_path, sir_rel_to rel_to) {
449 if (!_sir_validstr(path) || !_sir_validptr(relative) ||
450 !_sir_validptrptr(base_path) || !_sir_ispathrelative(path, relative))
451 return false;
452
453 if (*relative) {
454 switch (rel_to) {
455 case SIR_PATH_REL_TO_APP: return NULL != (*base_path = _sir_getappdir());
456 case SIR_PATH_REL_TO_CWD: return NULL != (*base_path = _sir_getcwd());
457 default: return _sir_seterror(_SIR_E_INVALID);
458 }
459 }
460
461 return true;
462 }
463
464 #if defined(_AIX)
465 # if !defined(__PASE__)
466 # define SIR_MAXSLPATH (SIR_MAXPATH + 16)
467 int _sir_aixself(char* buffer, size_t* size) {
468 ssize_t res;
469 char cwd[SIR_MAXPATH], cwdl[SIR_MAXPATH];
470 char symlink[SIR_MAXSLPATH], temp_buffer[SIR_MAXPATH];
471 char pp[64];
472 struct psinfo ps;
473 int fd;
474 char** argv;
475 char* tokptr;
476
477 if ((buffer == NULL) || (size == NULL))
478 return -1;
479
480 (void)snprintf(pp, sizeof(pp), "/proc/%llu/psinfo", (unsigned long long)_sir_getpid());
481
482 fd = open(pp, O_RDONLY);
483 if (fd < 0)
484 return -1;
485
486 res = read(fd, &ps, sizeof(ps));
487 close(fd);
488 if (res < 0)
489 return -1;
490
491 if (ps.pr_argv == 0)
492 return -1;
493
494 argv = (char**)*((char***)(intptr_t)ps.pr_argv);
495
496 if ((argv == NULL) || (argv[0] == NULL))
497 return -1;
498
499 if (argv[0][0] == '/') {
500 (void)snprintf(symlink, SIR_MAXPATH, "%s", argv[0]);
501
502 res = _sir_readlink(symlink, temp_buffer, SIR_MAXPATH);
503 if (res < 0)
504 (void)_sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
505 else
506 (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink),
507 temp_buffer);
508
509 *size = strnlen(buffer, SIR_MAXPATH);
510 return 0;
511 } else if (argv[0][0] == '.') {
512 char* relative = strchr(argv[0], '/');
513 if (relative == NULL)
514 return -1;
515
516 (void)snprintf(cwd, SIR_MAXPATH, "/proc/%llu/cwd", (unsigned long long)_sir_getpid());
517 res = _sir_readlink(cwd, cwdl, sizeof(cwdl) - 1);
518 if (res < 0)
519 return -1;
520
521 (void)snprintf(symlink, SIR_MAXPATH, "%s%s", cwdl, relative + 1);
522
523 res = _sir_readlink(symlink, temp_buffer, SIR_MAXPATH);
524 if (res < 0)
525 (void)_sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
526 else
527 (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
528
529 *size = strnlen(buffer, SIR_MAXPATH);
530 return 0;
531 } else if (strchr(argv[0], '/') != NULL) {
532 (void)snprintf(cwd, SIR_MAXPATH, "/proc/%llu/cwd", (unsigned long long)_sir_getpid());
533
534 res = _sir_readlink(cwd, cwdl, sizeof(cwdl) - 1);
535 if (res < 0)
536 return -1;
537
538 (void)snprintf(symlink, SIR_MAXPATH, "%s%s", cwdl, argv[0]);
539
540 res = _sir_readlink(symlink, temp_buffer, SIR_MAXPATH);
541 if (res < 0)
542 (void)_sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
543 else
544 (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
545
546 *size = strnlen(buffer, SIR_MAXPATH);
547 return 0;
548 } else {
549 char clonedpath[16384];
550 char* token = NULL;
551 struct stat statstruct;
552
553 char* path = getenv("PATH");
554 if (sizeof(clonedpath) <= strnlen(path, SIR_MAXPATH))
555 return -1;
556
557 (void)_sir_strncpy(clonedpath, SIR_MAXPATH, path, SIR_MAXPATH);
558
559 token = strtok_r(clonedpath, ":", &tokptr);
560
561 (void)snprintf(cwd, SIR_MAXPATH, "/proc/%llu/cwd", (unsigned long long)_sir_getpid());
562
563 res = _sir_readlink(cwd, cwdl, sizeof(cwdl) - 1);
564 if (res < 0)
565 return -1;
566
567 while (token != NULL) {
568 if (token[0] == '.') {
569 char* relative = strchr(token, '/');
570 if (relative != NULL) {
571 (void)snprintf(symlink, SIR_MAXSLPATH, "%s%s/%s", cwdl, relative + 1,
572 ps.pr_fname);
573 } else {
574 (void)snprintf(symlink, SIR_MAXSLPATH, "%s%s", cwdl, ps.pr_fname);
575 }
576
577 if (stat(symlink, &statstruct) != -1) {
578 res = _sir_readlink(symlink, temp_buffer, SIR_MAXPATH);
579 if (res < 0)
580 (void)_sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
581 else
582 (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
583
584 *size = strnlen(buffer, SIR_MAXPATH);
585 return 0;
586 }
587 } else {
588 (void)snprintf(symlink, SIR_MAXPATH, "%s/%s", token, ps.pr_fname);
589 if (stat(symlink, &statstruct) != -1) {
590 res = _sir_readlink(symlink, temp_buffer, SIR_MAXPATH);
591 if (res < 0)
592 (void)_sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
593 else
594 (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
595
596 *size = strnlen(buffer, SIR_MAXPATH);
597 return 0;
598 }
599 }
600
601 token = strtok_r(NULL, ":", &tokptr);
602 }
603 return -1;
604 }
605 }
606 # elif defined(__PASE__)
607 int _sir_aixself(char* buffer, size_t* size) {
608 struct procsinfo pinfo[16] = {0};
609 int numproc = 0;
610 int index = 0;
611 pid_t pid = _sir_getpid();
612 while ((numproc = getprocs(pinfo, sizeof(struct procsinfo), NULL, 0, &index, 16)) > 0) {
613 for (int n = 0; n < numproc; n++) {
614 if (pinfo[n].pi_state == SZOMB)
615 continue;
616 if (pinfo[n].pi_pid == pid) {
617 char tmp[SIR_MAXPATH + 2] = {0};
618 if (-1 == getargs(&pinfo[n], sizeof(struct procsinfo), tmp, sizeof(tmp))) {
619 (void)_sir_handleerr(errno);
620 break;
621 }
622 if (strchr(tmp, '/')) {
623 char tmp2[SIR_MAXPATH] = {0};
624 const char* rp = realpath(tmp, tmp2);
625 if (!rp) {
626 (void)_sir_handleerr(errno);
627 break;
628 }
629 (void)_sir_strncpy(buffer, *size, tmp2, strnlen(tmp2, *size - 1));
630 } else {
631 (void)_sir_resolvepath(tmp, buffer, *size);
632 }
633 if (_sir_validstrnofail(buffer))
634 return 0;
635 break;
636 }
637 }
638 }
639 return -1;
640 }
641 # endif
642 #endif
643
644 bool _sir_deletefile(const char* restrict path) {
645 if (!_sir_validstr(path))
646 return false;
647
648 #if !defined(__WIN__)
649 return (0 == unlink(path)) ? true : _sir_handleerr(errno);
650 #else
651 return (FALSE != DeleteFileA(path)) ? true : _sir_handlewin32err(GetLastError());
652 #endif
653 }
654
655 #if defined(__OpenBSD__)
656 int _sir_openbsdself(char* buffer, int size) {
657 char buffer1[4096];
658 char buffer2[SIR_MAXPATH];
659 char** argv = (char**)buffer1;
660 char* resolved = NULL;
661 int length = -1;
662
663 while (true) {
664 size_t mib_size = 0;
665 int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
666
667 if (sysctl(mib, 4, NULL, &mib_size, NULL, 0) != 0)
668 break;
669
670 if (mib_size > sizeof(buffer1)) {
671 argv = (char**)malloc(mib_size);
672 if (!argv)
673 break;
674 }
675
676 if (sysctl(mib, 4, argv, &mib_size, NULL, 0) != 0)
677 break;
678
679 if (strchr(argv[0], '/')) {
680 resolved = realpath(argv[0], buffer2);
681 if (!resolved)
682 break;
683 } else {
684 if (-1 != _sir_resolvepath(argv[0], buffer2, sizeof(buffer2)))
685 resolved = buffer2;
686 if (!resolved)
687 break;
688 }
689
690 length = (int)strnlen(resolved, SIR_MAXPATH);
691 if (length <= size)
692 (void)memcpy(buffer, resolved, (size_t)length);
693 break;
694 }
695 if (argv != (char**)buffer1)
696 _sir_safefree(&argv);
697
698 return length;
699 }
700 #endif
701
702 #if defined(__OpenBSD__) || (defined(_AIX) && defined(__PASE__))
703 int _sir_resolvepath(const char* restrict path, char* restrict buffer, size_t size) {
704 if (!_sir_validstr(path) || !_sir_validptr(buffer))
705 return -1;
706
707 const char* envvar = getenv("PATH");
708 if (!_sir_validstr(envvar))
709 return -1;
710
711 size_t pathlen = strnlen(path, SIR_MAXPATH);
712 const char* cursor = envvar;
713 char tmp[SIR_MAXPATH] = {0};
714 char tmp2[SIR_MAXPATH] = {0};
715 int length = -1;
716
717 while (true) {
718 const char* separator = strchr(cursor, ':');
719 const char* end = separator ? separator : cursor + strnlen(cursor, SIR_MAXPATH);
720 if (end - cursor > 0) {
721 if (*(end - 1) == '/')
722 --end;
723 if (((end - cursor) + 1UL + pathlen + 1UL) <= sizeof(tmp)) {
724 (void)memcpy(tmp, cursor, end - cursor);
725 tmp[end - cursor] = '/';
726 (void)memcpy(tmp + (end - cursor) + 1, path, pathlen + 1);
727 if (realpath(tmp, tmp2))
728 break;
729 }
730 }
731 if (!separator)
732 break;
733 cursor = ++separator;
734 }
735
736 if (_sir_validstrnofail(tmp2)) {
737 length = (int)strnlen(tmp2, SIR_MAXPATH);
738 (void)_sir_strncpy(buffer, size, tmp2, (size_t)length);
739 }
740
741 return length;
742 }
743 #endif