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