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__)
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(_AIX)
272 if (size <= SIR_MAXPATH) {
273 size = size + SIR_MAXPATH + 1L;
274 continue;
275 }
276 int ret = _sir_aixself(buffer, &size);
277 resolved = ret == 0 ? true : _sir_handleerr(errno);
278 break;
279 # elif defined(__OpenBSD__)
280 size_t length = (size_t)_sir_openbsdself(NULL, 0);
281 if (length < 1) {
282 resolved = _sir_handleerr(errno);
283 break;
284 }
285 if (length > size) {
286 size = length + 1;
287 continue;
288 }
289 (void)_sir_openbsdself(buffer, length);
290 resolved = _sir_validptrnofail(buffer);
291 break;
292 # elif defined(__BSD__)
293 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
294 int ret = sysctl(mib, 4, buffer, &size, NULL, 0);
295 if (0 == ret) {
296 resolved = true;
297 break;
298 } else {
299 if (ENOMEM == errno && 0 == sysctl(mib, 4, NULL, &size, NULL, 0))
300 continue;
301
302 resolved = _sir_handleerr(errno);
303 break;
304 }
305 # elif defined(__HAIKU__)
306 status_t ret =
307 find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, buffer, SIR_MAXPATH);
308 if (B_OK == ret) {
309 resolved = true;
310 break;
311 } else if (B_BUFFER_OVERFLOW == ret) {
312
313 continue;
314 } else {
315 resolved = _sir_handleerr(errno);
316 break;
317 }
318 # elif defined(__MACOS__)
319 int ret = _NSGetExecutablePath(buffer, (uint32_t*)&size);
320 if (0 == ret) {
321 resolved = true;
322 break;
323 } else if (-1 == ret) {
324
325 continue;
326 } else {
327 resolved = _sir_handleerr(errno);
328 break;
329 }
330 # else
331 # error "no implementation for your platform; please contact the developers"
332 # endif
333 #else
334 DWORD ret = GetModuleFileNameA(NULL, buffer, (DWORD)size);
335 if (0UL != ret && ret < (DWORD)size) {
336 resolved = true;
337 break;
338 } else if (0UL == ret) {
339 resolved = _sir_handlewin32err(GetLastError());
340 break;
341 } else if (ret == (DWORD)size || ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
342
343
344
345 size += SIR_PATH_BUFFER_GROW_BY;
346 continue;
347 }
348 #endif
349
350 } while (true);
351
352 if (!resolved)
353 _sir_safefree(&buffer);
354
355 return buffer;
356 }
357
358 char* _sir_getappbasename(void) {
359 char* filename = _sir_getappfilename();
360 if (!_sir_validstr(filename)) {
361 _sir_safefree(&filename);
362 return NULL;
363 }
364
365 const char* retval = _sir_getbasename(filename);
366 char* bname = strndup(retval, strnlen(retval, SIR_MAXPATH));
367
368 _sir_safefree(&filename);
369 return bname;
370 }
371
372 char* _sir_getappdir(void) {
373 char* filename = _sir_getappfilename();
374 if (!_sir_validstr(filename)) {
375 _sir_safefree(&filename);
376 return NULL;
377 }
378
379 const char* retval = _sir_getdirname(filename);
380 char* dname = strndup(retval, strnlen(retval, SIR_MAXPATH));
381
382 _sir_safefree(&filename);
383 return dname;
384 }
385
386 char* _sir_getbasename(char* restrict path) {
387 if (!_sir_validstr(path))
388 return ".";
389
390 #if !defined(__WIN__)
391 return basename(path);
392 #else
393 return PathFindFileNameA(path);
394 #endif
395 }
396
397 char* _sir_getdirname(char* restrict path) {
398 if (!_sir_validstr(path))
399 return ".";
400
401 #if !defined(__WIN__)
402 return dirname(path);
403 #else
404 (void)PathRemoveFileSpecA((LPSTR)path);
405 return path;
406 #endif
407 }
408
409 bool _sir_ispathrelative(const char* restrict path, bool* restrict relative) {
410 bool valid = _sir_validstr(path) && _sir_validptr(relative);
411
412 if (valid) {
413 #if !defined(__WIN__)
414 if (path[0] == '/' || (path[0] == '~' && path[1] == '/'))
415 *relative = false;
416 else
417 *relative = true;
418 #else
419 *relative = (TRUE == PathIsRelativeA(path));
420 #endif
421 }
422
423 return valid;
424 }
425
426 bool _sir_getrelbasepath(const char* restrict path, bool* restrict relative,
427 const char* restrict* restrict base_path, sir_rel_to rel_to) {
428 if (!_sir_validstr(path) || !_sir_validptr(relative) ||
429 !_sir_validptrptr(base_path) || !_sir_ispathrelative(path, relative))
430 return false;
431
432 if (*relative) {
433 switch (rel_to) {
434 case SIR_PATH_REL_TO_APP: return NULL != (*base_path = _sir_getappdir());
435 case SIR_PATH_REL_TO_CWD: return NULL != (*base_path = _sir_getcwd());
436 default: return _sir_seterror(_SIR_E_INVALID);
437 }
438 }
439
440 return true;
441 }
442
443 #if defined(_AIX)
444 # if !defined(__PASE__)
445 # define SIR_MAXSLPATH (SIR_MAXPATH + 16)
446 int _sir_aixself(char* buffer, size_t* size) {
447 ssize_t res;
448 char cwd[SIR_MAXPATH], cwdl[SIR_MAXPATH];
449 char symlink[SIR_MAXSLPATH], temp_buffer[SIR_MAXPATH];
450 char pp[64];
451 struct psinfo ps;
452 int fd;
453 char** argv;
454 char* tokptr;
455
456 if ((buffer == NULL) || (size == NULL))
457 return -1;
458
459 (void)snprintf(pp, sizeof(pp), "/proc/%llu/psinfo", (unsigned long long)_sir_getpid());
460
461 fd = open(pp, O_RDONLY);
462 if (fd < 0)
463 return -1;
464
465 res = read(fd, &ps, sizeof(ps));
466 close(fd);
467 if (res < 0)
468 return -1;
469
470 if (ps.pr_argv == 0)
471 return -1;
472
473 argv = (char**)*((char***)(intptr_t)ps.pr_argv);
474
475 if ((argv == NULL) || (argv[0] == NULL))
476 return -1;
477
478 if (argv[0][0] == '/') {
479 (void)snprintf(symlink, SIR_MAXPATH, "%s", argv[0]);
480
481 res = _sir_readlink(symlink, temp_buffer, SIR_MAXPATH);
482 if (res < 0)
483 (void)_sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
484 else
485 (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink),
486 temp_buffer);
487
488 *size = strnlen(buffer, SIR_MAXPATH);
489 return 0;
490 } else if (argv[0][0] == '.') {
491 char* relative = strchr(argv[0], '/');
492 if (relative == NULL)
493 return -1;
494
495 (void)snprintf(cwd, SIR_MAXPATH, "/proc/%llu/cwd", (unsigned long long)_sir_getpid());
496 res = _sir_readlink(cwd, cwdl, sizeof(cwdl) - 1);
497 if (res < 0)
498 return -1;
499
500 (void)snprintf(symlink, SIR_MAXPATH, "%s%s", cwdl, relative + 1);
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), temp_buffer);
507
508 *size = strnlen(buffer, SIR_MAXPATH);
509 return 0;
510 } else if (strchr(argv[0], '/') != NULL) {
511 (void)snprintf(cwd, SIR_MAXPATH, "/proc/%llu/cwd", (unsigned long long)_sir_getpid());
512
513 res = _sir_readlink(cwd, cwdl, sizeof(cwdl) - 1);
514 if (res < 0)
515 return -1;
516
517 (void)snprintf(symlink, SIR_MAXPATH, "%s%s", cwdl, argv[0]);
518
519 res = _sir_readlink(symlink, temp_buffer, SIR_MAXPATH);
520 if (res < 0)
521 (void)_sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
522 else
523 (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
524
525 *size = strnlen(buffer, SIR_MAXPATH);
526 return 0;
527 } else {
528 char clonedpath[16384];
529 char* token = NULL;
530 struct stat statstruct;
531
532 char* path = getenv("PATH");
533 if (sizeof(clonedpath) <= strnlen(path, SIR_MAXPATH))
534 return -1;
535
536 (void)_sir_strncpy(clonedpath, SIR_MAXPATH, path, SIR_MAXPATH);
537
538 token = strtok_r(clonedpath, ":", &tokptr);
539
540 (void)snprintf(cwd, SIR_MAXPATH, "/proc/%llu/cwd", (unsigned long long)_sir_getpid());
541
542 res = _sir_readlink(cwd, cwdl, sizeof(cwdl) - 1);
543 if (res < 0)
544 return -1;
545
546 while (token != NULL) {
547 if (token[0] == '.') {
548 char* relative = strchr(token, '/');
549 if (relative != NULL) {
550 (void)snprintf(symlink, SIR_MAXSLPATH, "%s%s/%s", cwdl, relative + 1,
551 ps.pr_fname);
552 } else {
553 (void)snprintf(symlink, SIR_MAXSLPATH, "%s%s", cwdl, ps.pr_fname);
554 }
555
556 if (stat(symlink, &statstruct) != -1) {
557 res = _sir_readlink(symlink, temp_buffer, SIR_MAXPATH);
558 if (res < 0)
559 (void)_sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
560 else
561 (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
562
563 *size = strnlen(buffer, SIR_MAXPATH);
564 return 0;
565 }
566 } else {
567 (void)snprintf(symlink, SIR_MAXPATH, "%s/%s", token, ps.pr_fname);
568 if (stat(symlink, &statstruct) != -1) {
569 res = _sir_readlink(symlink, temp_buffer, SIR_MAXPATH);
570 if (res < 0)
571 (void)_sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
572 else
573 (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
574
575 *size = strnlen(buffer, SIR_MAXPATH);
576 return 0;
577 }
578 }
579
580 token = strtok_r(NULL, ":", &tokptr);
581 }
582 return -1;
583 }
584 }
585 # elif defined(__PASE__)
586 int _sir_aixself(char* buffer, size_t* size) {
587 struct procsinfo pinfo[16] = {0};
588 int numproc = 0;
589 int index = 0;
590 pid_t pid = _sir_getpid();
591 while ((numproc = getprocs(pinfo, sizeof(struct procsinfo), NULL, 0, &index, 16)) > 0) {
592 for (int n = 0; n < numproc; n++) {
593 if (pinfo[n].pi_state == SZOMB)
594 continue;
595 if (pinfo[n].pi_pid == pid) {
596 char tmp[SIR_MAXPATH + 2] = {0};
597 if (-1 == getargs(&pinfo[n], sizeof(struct procsinfo), tmp, sizeof(tmp))) {
598 (void)_sir_handleerr(errno);
599 break;
600 }
601 if (strchr(tmp, '/')) {
602 char tmp2[SIR_MAXPATH] = {0};
603 const char* rp = realpath(tmp, tmp2);
604 if (!rp) {
605 (void)_sir_handleerr(errno);
606 break;
607 }
608 (void)_sir_strncpy(buffer, *size, tmp2, strnlen(tmp2, *size - 1));
609 } else {
610 (void)_sir_resolvepath(tmp, buffer, *size);
611 }
612 if (_sir_validstrnofail(buffer))
613 return 0;
614 break;
615 }
616 }
617 }
618 return -1;
619 }
620 # endif
621 #endif
622
623 bool _sir_deletefile(const char* restrict path) {
624 if (!_sir_validstr(path))
625 return false;
626
627 #if !defined(__WIN__)
628 return (0 == unlink(path)) ? true : _sir_handleerr(errno);
629 #else
630 return (FALSE != DeleteFileA(path)) ? true : _sir_handlewin32err(GetLastError());
631 #endif
632 }
633
634 #if defined(__OpenBSD__)
635 int _sir_openbsdself(char* buffer, int size) {
636 char buffer1[4096];
637 char buffer2[SIR_MAXPATH];
638 char** argv = (char**)buffer1;
639 char* resolved = NULL;
640 int length = -1;
641
642 while (true) {
643 size_t mib_size = 0;
644 int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
645
646 if (sysctl(mib, 4, NULL, &mib_size, NULL, 0) != 0)
647 break;
648
649 if (mib_size > sizeof(buffer1)) {
650 argv = (char**)malloc(mib_size);
651 if (!argv)
652 break;
653 }
654
655 if (sysctl(mib, 4, argv, &mib_size, NULL, 0) != 0)
656 break;
657
658 if (strchr(argv[0], '/')) {
659 resolved = realpath(argv[0], buffer2);
660 if (!resolved)
661 break;
662 } else {
663 if (-1 != _sir_resolvepath(argv[0], buffer2, sizeof(buffer2)))
664 resolved = buffer2;
665 if (!resolved)
666 break;
667 }
668
669 length = (int)strnlen(resolved, SIR_MAXPATH);
670 if (length <= size)
671 (void)memcpy(buffer, resolved, (size_t)length);
672 break;
673 }
674 if (argv != (char**)buffer1)
675 _sir_safefree(&argv);
676
677 return length;
678 }
679 #endif
680
681 #if defined(__OpenBSD__) || (defined(_AIX) && defined(__PASE__))
682 int _sir_resolvepath(const char* restrict path, char* restrict buffer, size_t size) {
683 if (!_sir_validstr(path) || !_sir_validptr(buffer))
684 return -1;
685
686 const char* envvar = getenv("PATH");
687 if (!_sir_validstr(envvar))
688 return -1;
689
690 size_t pathlen = strnlen(path, SIR_MAXPATH);
691 const char* cursor = envvar;
692 char tmp[SIR_MAXPATH] = {0};
693 char tmp2[SIR_MAXPATH] = {0};
694 int length = -1;
695
696 while (true) {
697 const char* separator = strchr(cursor, ':');
698 const char* end = separator ? separator : cursor + strnlen(cursor, SIR_MAXPATH);
699 if (end - cursor > 0) {
700 if (*(end - 1) == '/')
701 --end;
702 if (((end - cursor) + 1UL + pathlen + 1UL) <= sizeof(tmp)) {
703 (void)memcpy(tmp, cursor, end - cursor);
704 tmp[end - cursor] = '/';
705 (void)memcpy(tmp + (end - cursor) + 1, path, pathlen + 1);
706 if (realpath(tmp, tmp2))
707 break;
708 }
709 }
710 if (!separator)
711 break;
712 cursor = ++separator;
713 }
714
715 if (_sir_validstrnofail(tmp2)) {
716 length = (int)strnlen(tmp2, SIR_MAXPATH);
717 (void)_sir_strncpy(buffer, size, tmp2, (size_t)length);
718 }
719
720 return length;
721 }
722 #endif