root/src/libsir/src/sirfilesystem.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _sir_pathgetstat
  2. _sir_pathexists
  3. _sir_openfile
  4. _sir_getcwd
  5. _sir_getappfilename
  6. _sir_getappbasename
  7. _sir_getappdir
  8. _sir_getbasename
  9. _sir_getdirname
  10. _sir_ispathrelative
  11. _sir_getrelbasepath
  12. _sir_aixself
  13. _sir_aixself
  14. _sir_deletefile
  15. _sir_openbsdself
  16. _sir_resolvepath

   1 /*
   2  * sirfilesystem.c
   3  *
   4  * Version: 2.2.6
   5  *
   6  * -----------------------------------------------------------------------------
   7  *
   8  * SPDX-License-Identifier: MIT
   9  *
  10  * Copyright (c) 2018-2024 Ryan M. Lederman <lederman@gmail.com>
  11  * Copyright (c) 2018-2024 Jeffrey H. Johnson <trnsz@pobox.com>
  12  *
  13  * Permission is hereby granted, free of charge, to any person obtaining a copy of
  14  * this software and associated documentation files (the "Software"), to deal in
  15  * the Software without restriction, including without limitation the rights to
  16  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  17  * the Software, and to permit persons to whom the Software is furnished to do so,
  18  * subject to the following conditions:
  19  *
  20  * The above copyright notice and this permission notice shall be included in all
  21  * copies or substantial portions of the Software.
  22  *
  23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  25  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  26  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  27  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  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) {
     /* [previous][next][first][last][top][bottom][index][help] */
  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         // HACKHACK: fstatat does not work properly for any fd other than AT_FDCWD.
  89         SIR_UNUSED(open_flags);
  90         int fd = AT_FDCWD;
  91         if (rel_to == SIR_PATH_REL_TO_CWD) {
  92             /* cppcheck-suppress invalidFunctionArg */
  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 /* __WIN__ */
 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         /* Embarcadero <12 does not like paths that end in slashes, nor does it appreciate
 111          * paths like './' and '../'; this hack is needed for RAD Studio 11.3 and earlier. */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* __WIN__ */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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             /* it is possible that truncation occurred. as a security
 266              * precaution, fail; someone may have tampered with the link. */
 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; /* grow buffer. */
 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             /* grow buffer. */
 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             /* grow buffer. */
 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 /* __WIN__ */
 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             /* Windows has no concept of letting you know how much larger
 361              * your buffer needed to be; it just truncates the string and
 362              * returns size. So, we'll guess. */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 405     if (!_sir_validstr(path))
 406         return ".";
 407 
 408 #if !defined(__WIN__)
 409     return basename(path);
 410 #else /* __WIN__ */
 411     return PathFindFileNameA(path);
 412 #endif
 413 }
 414 
 415 char* _sir_getdirname(char* restrict path) {
     /* [previous][next][first][last][top][bottom][index][help] */
 416     if (!_sir_validstr(path))
 417         return ".";
 418 
 419 #if !defined(__WIN__)
 420     return dirname(path);
 421 #else /* __WIN__ */
 422     (void)PathRemoveFileSpecA((LPSTR)path);
 423     return path;
 424 #endif
 425 }
 426 
 427 bool _sir_ispathrelative(const char* restrict path, bool* restrict relative) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* __WIN__ */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 642     if (!_sir_validstr(path))
 643         return false;
 644 
 645 #if !defined(__WIN__)
 646     return (0 == unlink(path)) ? true : _sir_handleerr(errno);
 647 #else /* __WIN__ */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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

/* [previous][next][first][last][top][bottom][index][help] */