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 //-V::522
  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) {
     /* [previous][next][first][last][top][bottom][index][help] */
  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         // HACKHACK: fstatat does not work properly for any fd other than AT_FDCWD.
  91         SIR_UNUSED(open_flags);
  92         int fd = AT_FDCWD;
  93         if (rel_to == SIR_PATH_REL_TO_CWD) {
  94             /* cppcheck-suppress invalidFunctionArg */
  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 /* __WIN__ */
 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         /* Embarcadero <12 does not like paths that end in slashes, nor does it appreciate
 113          * paths like './' and '../'; this hack is needed for RAD Studio 11.3 and earlier. */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* __WIN__ */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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             /* it is possible that truncation occurred. as a security
 269              * precaution, fail; someone may have tampered with the link. */
 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; /* grow buffer. */
 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             /* grow buffer. */
 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             /* grow buffer. */
 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 /* __WIN__ */
 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             /* Windows has no concept of letting you know how much larger
 364              * your buffer needed to be; it just truncates the string and
 365              * returns size. So, we'll guess. */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 408     if (!_sir_validstr(path))
 409         return ".";
 410 
 411 #if !defined(__WIN__)
 412     return basename(path);
 413 #else /* __WIN__ */
 414     return PathFindFileNameA(path);
 415 #endif
 416 }
 417 
 418 char* _sir_getdirname(char* restrict path) {
     /* [previous][next][first][last][top][bottom][index][help] */
 419     if (!_sir_validstr(path))
 420         return ".";
 421 
 422 #if !defined(__WIN__)
 423     return dirname(path);
 424 #else /* __WIN__ */
 425     (void)PathRemoveFileSpecA((LPSTR)path);
 426     return path;
 427 #endif
 428 }
 429 
 430 bool _sir_ispathrelative(const char* restrict path, bool* restrict relative) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* __WIN__ */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 645     if (!_sir_validstr(path))
 646         return false;
 647 
 648 #if !defined(__WIN__)
 649     return (0 == unlink(path)) ? true : _sir_handleerr(errno);
 650 #else /* __WIN__ */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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

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