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.5
   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__)
  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(_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; /* grow buffer. */
 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             /* grow buffer. */
 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             /* grow buffer. */
 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 /* __WIN__ */
 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             /* Windows has no concept of letting you know how much larger
 343              * your buffer needed to be; it just truncates the string and
 344              * returns size. So, we'll guess. */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 387     if (!_sir_validstr(path))
 388         return ".";
 389 
 390 #if !defined(__WIN__)
 391     return basename(path);
 392 #else /* __WIN__ */
 393     return PathFindFileNameA(path);
 394 #endif
 395 }
 396 
 397 char* _sir_getdirname(char* restrict path) {
     /* [previous][next][first][last][top][bottom][index][help] */
 398     if (!_sir_validstr(path))
 399         return ".";
 400 
 401 #if !defined(__WIN__)
 402     return dirname(path);
 403 #else /* __WIN__ */
 404     (void)PathRemoveFileSpecA((LPSTR)path);
 405     return path;
 406 #endif
 407 }
 408 
 409 bool _sir_ispathrelative(const char* restrict path, bool* restrict relative) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* __WIN__ */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 624     if (!_sir_validstr(path))
 625         return false;
 626 
 627 #if !defined(__WIN__)
 628     return (0 == unlink(path)) ? true : _sir_handleerr(errno);
 629 #else /* __WIN__ */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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) {
     /* [previous][next][first][last][top][bottom][index][help] */
 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

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