• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aremmell / libsir / 90

10 Aug 2023 01:34AM UTC coverage: 94.832% (+0.03%) from 94.804%
90

push

gitlab-ci

johnsonjh
Handle ENOTDIR as well as ENOENT; adjust test display

Signed-off-by: Jeffrey H. Johnson <trnsz@pobox.com>

8 of 8 new or added lines in 2 files covered. (100.0%)

3046 of 3212 relevant lines covered (94.83%)

1608107.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.8
/src/sirfilesystem.c
1
/*
2
 * sirfilesystem.c
3
 *
4
 * Author:    Ryan M. Lederman <lederman@gmail.com>
5
 * Copyright: Copyright (c) 2018-2023
6
 * Version:   2.2.2
7
 * License:   The MIT License (MIT)
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
10
 * this software and associated documentation files (the "Software"), to deal in
11
 * the Software without restriction, including without limitation the rights to
12
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13
 * the Software, and to permit persons to whom the Software is furnished to do so,
14
 * subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in all
17
 * copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
21
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
22
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
#include "sir/filesystem.h"
27
#include "sir/internal.h"
28

29
#if defined(__WIN__)
30
# if (defined(__TURBOC__) || defined(__BORLANDC__) || \
31
     defined(__BCPLUSPLUS__) || defined(__CODEGEARC__)) && \
32
     defined(_WIN64)
33
#  pragma comment(lib, "shlwapi.a")
34
# else
35
#  pragma comment(lib, "shlwapi.lib")
36
# endif
37
#endif
38

39
bool _sir_pathgetstat(const char* restrict path, struct stat* restrict st, sir_rel_to rel_to) {
375✔
40
    if (!_sir_validstr(path) || !_sir_validptr(st))
375✔
41
        return false;
×
42

43
    memset(st, 0, sizeof(struct stat));
324✔
44

45
    int stat_ret          = -1;
324✔
46
    bool relative         = false;
375✔
47
    const char* base_path = NULL;
375✔
48

49
    if (!_sir_getrelbasepath(path, &relative, &base_path, rel_to))
375✔
50
        return false;
48✔
51

52
    if (relative) {
327✔
53
#if !defined(__WIN__)
54
# if defined(__MACOS__) || defined(_AIX)
55
#  if !defined(O_SEARCH)
56
        int open_flags = O_DIRECTORY;
57
#  else
58
        int open_flags = O_SEARCH;
59
#  endif
60
# elif defined(__linux__) || defined(__HURD__)
61
#  if !defined(__SUNPRO_C) && !defined(__SUNPRO_CC) && defined(O_PATH)
62
        int open_flags = O_PATH | O_DIRECTORY;
204✔
63
#  else
64
        int open_flags = O_DIRECTORY;
65
#  endif
66
# elif defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__serenity__)
67
        int open_flags = O_EXEC | O_DIRECTORY;
68
# elif defined(__SOLARIS__) || defined(__DragonFly__) || \
69
       defined(__NetBSD__) || defined(__HAIKU__) || defined(__OpenBSD__)
70
        int open_flags = O_DIRECTORY;
71
# else
72
#  error "unknown open_flags for your platform; please contact the author."
73
# endif
74

75
        int fd = open(base_path, open_flags);
243✔
76
        if (-1 == fd) {
243✔
77
            _sir_safefree(&base_path);
×
78
            return _sir_handleerr(errno);
×
79
        }
80

81
        stat_ret = fstatat(fd, path, st, AT_SYMLINK_NOFOLLOW);
243✔
82
        _sir_safeclose(&fd);
243✔
83
        _sir_safefree(&base_path);
243✔
84
    } else {
85
        stat_ret = stat(path, st);
84✔
86
    }
87
#else /* __WIN__ */
88
        char abs_path[SIR_MAXPATH] = {0};
89
        (void)snprintf(abs_path, SIR_MAXPATH, "%s\\%s", base_path, path);
90

91
# if (defined(__TURBOC__) || defined(__BORLANDC__) || \
92
     defined(__BCPLUSPLUS__) || defined(__CODEGEARC__))
93
        if (_sir_validstr(abs_path) && strnlen(abs_path, SIR_MAXPATH) > 2) {
94
          while(1) {
95
            if ((abs_path[strnlen(abs_path, SIR_MAXPATH) - 2] != '/') &&
96
                (abs_path[strnlen(abs_path, SIR_MAXPATH) - 2] != '\\') &&
97
                (abs_path[strnlen(abs_path, SIR_MAXPATH) - 2] != '.') &&
98
                (abs_path[strnlen(abs_path, SIR_MAXPATH) - 1] != '\\') &&
99
                (abs_path[strnlen(abs_path, SIR_MAXPATH) - 2] != '/'))
100
                  break;
101
            if (((abs_path[strnlen(abs_path, SIR_MAXPATH) - 1] == '/') ||
102
                 (abs_path[strnlen(abs_path, SIR_MAXPATH) - 1] == '\\')) &&
103
                ((abs_path[strnlen(abs_path, SIR_MAXPATH) - 2] != '/') ||
104
                 (abs_path[strnlen(abs_path, SIR_MAXPATH) - 2] != '\\'))) {
105
              abs_path[strnlen(abs_path, SIR_MAXPATH) - 1] = 0;
106
            } else {
107
              break;
108
            }
109
          }
110
        }
111
# endif
112
        stat_ret = stat(abs_path, st);
113
        _sir_safefree(&base_path);
114
    } else {
115
        stat_ret = stat(path, st);
116
    }
117
#endif
118
    if (-1 == stat_ret && ((ENOENT == errno) || (ENOTDIR == errno)))
327✔
119
        st->st_size = SIR_STAT_NONEXISTENT;
123✔
120

121
    return (-1 != stat_ret || (ENOENT == errno) || (ENOTDIR == errno)) ? true : _sir_handleerr(errno);
294✔
122
}
123

124
bool _sir_pathexists(const char* path, bool* exists, sir_rel_to rel_to) {
375✔
125
    if (!_sir_validstr(path) || !_sir_validptr(exists))
375✔
126
        return false;
×
127

128
    *exists = false;
375✔
129

130
    struct stat st = {0};
375✔
131
    bool stat_ret  = _sir_pathgetstat(path, &st, rel_to);
375✔
132
    if (!stat_ret)
375✔
133
        return false;
48✔
134

135
    *exists = (st.st_size != SIR_STAT_NONEXISTENT);
327✔
136
    return true;
327✔
137
}
138

139
bool _sir_openfile(FILE* restrict* restrict f, const char* restrict path,
35,011✔
140
    const char* restrict mode, sir_rel_to rel_to) {
141
    if (!_sir_validptrptr(f) || !_sir_validstr(path) || !_sir_validstr(mode))
35,011✔
142
        return false;
×
143

144
    bool relative         = false;
35,011✔
145
    const char* base_path = NULL;
35,011✔
146

147
    if (!_sir_getrelbasepath(path, &relative, &base_path, rel_to))
35,011✔
148
        return false;
4✔
149

150
    if (relative) {
35,007✔
151
        char abs_path[SIR_MAXPATH] = {0};
34,988✔
152
        (void)snprintf(abs_path, SIR_MAXPATH, "%s/%s", base_path, path);
34,988✔
153

154
        int ret = _sir_fopen(f, abs_path, mode);
34,988✔
155
        _sir_safefree(&base_path);
34,988✔
156
        return 0 == ret;
34,988✔
157
    }
158

159
    return 0 == _sir_fopen(f, path, mode);
19✔
160
}
161

162
#if defined(_AIX)
163
static char cur_cwd[SIR_MAXPATH];
164
#endif
165
char* _sir_getcwd(void) {
35,031✔
166
#if !defined(__WIN__)
167
# if defined(__linux__) && (defined(__GLIBC__) && defined(_GNU_SOURCE))
168
    char* cur = get_current_dir_name();
35,031✔
169
    if (NULL == cur)
35,031✔
170
        (void)_sir_handleerr(errno);
×
171
    return cur;
35,031✔
172
# elif defined(_AIX)
173
    if (getcwd(cur_cwd, sizeof(cur_cwd)) == 0) {
174
        (void)_sir_handleerr(errno);
175
        return NULL;
176
    } else {
177
        return strndup(cur_cwd, SIR_MAXPATH);
178
    }
179
# else
180
    char* cur = getcwd(NULL, 0);
181
    if (NULL == cur)
182
        (void)_sir_handleerr(errno);
183
    return cur;
184
# endif
185
#else /* __WIN__ */
186
    DWORD size = GetCurrentDirectoryA(0, NULL);
187
    if (0 == size) {
188
        _sir_handlewin32err(GetLastError());
189
        return NULL;
190
    }
191

192
    char* cur = calloc(size, sizeof(char));
193
    if (!cur) {
194
        _sir_handleerr(errno);
195
        return NULL;
196
    }
197

198
    if (!GetCurrentDirectoryA(size, cur)) {
199
        _sir_handlewin32err(GetLastError());
200
        _sir_safefree(cur);
201
        return NULL;
202
    }
203

204
    return cur;
205
#endif
206
}
207

208
char* _sir_getappfilename(void) {
338✔
209
#if defined(__linux__) || defined(__NetBSD__) || defined(__SOLARIS__) || \
210
    defined(__DragonFly__) || defined(__CYGWIN__) || defined(__serenity__) || \
211
    defined(__HURD__)
212
# define __READLINK_OS__
213
# if defined(__linux__) || defined(__CYGWIN__) || \
214
     defined(__serenity__) || defined(__HURD__)
215
#  define PROC_SELF "/proc/self/exe"
216
# elif defined(__NetBSD__)
217
#  define PROC_SELF "/proc/curproc/exe"
218
# elif defined(__DragonFly__)
219
#  define PROC_SELF "/proc/curproc/file"
220
# elif defined(__SOLARIS__)
221
#  define PROC_SELF "/proc/self/path/a.out"
222
# endif
223
    struct stat st;
224
    if (-1 == lstat(PROC_SELF, &st)) {
338✔
225
        (void)_sir_handleerr(errno);
14✔
226
        return NULL;
14✔
227
    }
228

229
    size_t size = (st.st_size > 0) ? st.st_size + 2 : SIR_MAXPATH;
324✔
230
#else
231
    size_t size = SIR_MAXPATH;
232
#endif
233

234
    char* buffer  = NULL;
324✔
235
    bool resolved = false;
275✔
236

237
    do {
×
238
        _sir_safefree(&buffer);
324✔
239
        buffer = (char*)calloc(size, sizeof(char));
324✔
240
        if (NULL == buffer) {
324✔
241
            resolved = _sir_handleerr(errno);
17✔
242
            break;
17✔
243
        }
244

245
#if !defined(__WIN__)
246
# if defined(__READLINK_OS__)
247
        /* Flawfinder: ignore */
248
        ssize_t read = readlink(PROC_SELF, buffer, size - 1);
307✔
249
        if (-1 != read && read < (ssize_t)size - 1) {
307✔
250
            resolved = true;
244✔
251
            break;
244✔
252
        } else if (-1 == read) {
14✔
253
            resolved = _sir_handleerr(errno);
14✔
254
            break;
14✔
255
        } else if (read == (ssize_t)size - 1) {
×
256
            /*
257
             * It is possible that truncation occurred. As a security
258
             * precaution, fail; someone may have tampered with the link.
259
             */
260
            _sir_selflog("warning: readlink reported truncation; not using result!");
×
261
            resolved = false;
×
262
            break;
×
263
        }
264
# elif defined(_AIX)
265
        if (size <= SIR_MAXPATH) {
266
            size = size + SIR_MAXPATH + 1;
267
            continue;
268
        }
269
        int ret = _sir_aixself(buffer, &size);
270
        if (ret == 0) {
271
            resolved = true;
272
            break;
273
        } else {
274
            resolved = _sir_handleerr(errno);
275
            break;
276
        }
277
# elif defined(__OpenBSD__)
278
        size_t length;
279
        int dirname_length;
280
        length = _sir_openbsdself(NULL, 0, &dirname_length);
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, &dirname_length);
290
        if (!buffer) {
291
            resolved = false;
292
            break;
293
        }
294
        resolved = true;
295
        break;
296
# elif defined(__BSD__)
297
        int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
298
        int ret = sysctl(mib, 4, buffer, &size, NULL, 0);
299
        if (0 == ret) {
300
            resolved = true;
301
            break;
302
        } else {
303
            if (ENOMEM == errno && 0 == sysctl(mib, 4, NULL, &size, NULL, 0))
304
                continue; /* grow buffer. */
305

306
            resolved = _sir_handleerr(errno);
307
            break;
308
        }
309
# elif defined(__HAIKU__)
310
        status_t ret =
311
            find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, buffer, SIR_MAXPATH);
312
        if (B_OK == ret) {
313
            resolved = true;
314
            break;
315
        } else if (B_BUFFER_OVERFLOW == ret) {
316
            /* grow buffer. */
317
            continue;
318
        } else {
319
            resolved = _sir_handleerr(errno);
320
            break;
321
        }
322
# elif defined(__MACOS__)
323
        int ret = _NSGetExecutablePath(buffer, (uint32_t*)&size);
324
        if (0 == ret) {
325
            resolved = true;
326
            break;
327
        } else if (-1 == ret) {
328
            /* grow buffer. */
329
            continue;
330
        } else {
331
            resolved = _sir_handleerr(errno);
332
            break;
333
        }
334
# else
335
#  error "no implementation for your platform; please contact the author."
336
# endif
337
#else /* __WIN__ */
338
        DWORD ret = GetModuleFileNameA(NULL, buffer, (DWORD)size);
339
        if (0 != ret && ret < (DWORD)size) {
340
            resolved = true;
341
            break;
342
        } else if (0 == ret) {
343
            resolved = _sir_handlewin32err(GetLastError());
344
            break;
345
        } else if (ret == (DWORD)size || ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
346
            /* Windows has no concept of letting you know how much larger
347
             * your buffer needed to be; it just truncates the string and
348
             * returns size. So, we'll guess. */
349
            size += SIR_PATH_BUFFER_GROW_BY;
350
            continue;
351
        }
352
#endif
353

354
    } while (true);
355

356
    if (!resolved)
324✔
357
        _sir_safefree(&buffer);
31✔
358

359
    return buffer;
324✔
360
}
361

362
char* _sir_getappbasename(void) {
26✔
363
    char* filename = _sir_getappfilename();
26✔
364
    if (!_sir_validstr(filename)) {
26✔
365
        _sir_safefree(&filename);
3✔
366
        return NULL;
3✔
367
    }
368

369
    char* retval = _sir_getbasename(filename);
23✔
370
    char* bname  = strndup(retval, strnlen(retval, SIR_MAXPATH));
23✔
371

372
    _sir_safefree(&filename);
23✔
373
    return bname;
23✔
374
}
375

376
char* _sir_getappdir(void) {
291✔
377
    char* filename = _sir_getappfilename();
291✔
378
    if (!_sir_validstr(filename)) {
291✔
379
        _sir_safefree(&filename);
39✔
380
        return NULL;
39✔
381
    }
382

383
    char* retval  = _sir_getdirname(filename);
252✔
384
    char* dirname = strndup(retval, strnlen(retval, SIR_MAXPATH));
252✔
385

386
    _sir_safefree(&filename);
252✔
387
    return dirname;
252✔
388
}
389

390
char* _sir_getbasename(char* restrict path) {
140✔
391
    if (!_sir_validstr(path))
140✔
392
        return ".";
17✔
393

394
#if !defined(__WIN__)
395
    return basename(path);
120✔
396
#else /* __WIN__ */
397
    return PathFindFileNameA(path);
398
#endif
399
}
400

401
char* _sir_getdirname(char* restrict path) {
389✔
402
    if (!_sir_validstr(path))
389✔
403
        return ".";
17✔
404

405
#if !defined(__WIN__)
406
    return dirname(path);
369✔
407
#else /* __WIN__ */
408
    (void)PathRemoveFileSpecA((LPSTR)path);
409
    return path;
410
#endif
411
}
412

413
bool _sir_ispathrelative(const char* restrict path, bool* restrict relative) {
35,554✔
414
    bool valid = _sir_validstr(path) && _sir_validptr(relative);
35,554✔
415

416
    if (valid) {
29,291✔
417
#if !defined(__WIN__)
418
        if (path[0] == '/' || (path[0] == '~' && path[1] == '/'))
35,554✔
419
            *relative = false;
187✔
420
        else
421
            *relative = true;
35,367✔
422
#else /* __WIN__ */
423
        *relative = (TRUE == PathIsRelativeA(path));
424
#endif
425
    }
426

427
    return valid;
35,554✔
428
}
429

430
bool _sir_getrelbasepath(const char* restrict path, bool* restrict relative,
35,386✔
431
    const char* restrict* restrict base_path, sir_rel_to rel_to) {
432
    if (!_sir_validstr(path) || !_sir_validptr(relative) ||
41,625✔
433
        !_sir_validptrptr(base_path) || !_sir_ispathrelative(path, relative))
41,625✔
434
        return false;
×
435

436
    if (*relative) {
35,386✔
437
        switch (rel_to) {
35,283✔
438
            case SIR_PATH_REL_TO_APP: return NULL != (*base_path = _sir_getappdir());
273✔
439
            case SIR_PATH_REL_TO_CWD: return NULL != (*base_path = _sir_getcwd());
35,010✔
440
            default: return _sir_seterror(_SIR_E_INVALID);
×
441
        }
442
    }
443

444
    return true;
88✔
445
}
446

447
#if defined(_AIX)
448
# define SIR_MAXSLPATH (SIR_MAXPATH + 16)
449
int _sir_aixself(char* buffer, size_t* size) {
450
    ssize_t res;
451
    char cwd[SIR_MAXPATH], cwdl[SIR_MAXPATH];
452
    char symlink[SIR_MAXSLPATH], temp_buffer[SIR_MAXPATH];
453
    char pp[64];
454
    struct psinfo ps;
455
    int fd;
456
    char** argv;
457
    char* tokptr;
458

459
    if ((buffer == NULL) || (size == NULL))
460
        return -1;
461

462
    (void)snprintf(pp, sizeof(pp), "/proc/%llu/psinfo", (unsigned long long)_sir_getpid());
463

464
    fd = open(pp, O_RDONLY);
465
    if (fd < 0)
466
        return -1;
467

468
    res = read(fd, &ps, sizeof(ps));
469
    close(fd);
470
    if (res < 0)
471
        return -1;
472

473
    if (ps.pr_argv == 0)
474
        return -1;
475

476
    argv = (char**)*((char***)(intptr_t)ps.pr_argv);
477

478
    if ((argv == NULL) || (argv[0] == NULL))
479
        return -1;
480

481
    if (argv[0][0] == '/') {
482
        (void)snprintf(symlink, SIR_MAXPATH, "%s", argv[0]);
483

484
        /* Flawfinder: ignore */
485
        res = readlink(symlink, temp_buffer, SIR_MAXPATH);
486
        if (res < 0)
487
            _sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
488
        else
489
            (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink),
490
                temp_buffer);
491

492
        *size = strnlen(buffer, SIR_MAXPATH);
493
        return 0;
494
    } else if (argv[0][0] == '.') {
495
        char* relative = strchr(argv[0], '/');
496
        if (relative == NULL)
497
            return -1;
498

499
        (void)snprintf(cwd, SIR_MAXPATH, "/proc/%llu/cwd", (unsigned long long)_sir_getpid());
500

501
        /* Flawfinder: ignore */
502
        res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
503
        if (res < 0)
504
            return -1;
505

506
        (void)snprintf(symlink, SIR_MAXPATH, "%s%s", cwdl, relative + 1);
507

508
        /* Flawfinder: ignore */
509
        res = readlink(symlink, temp_buffer, SIR_MAXPATH);
510
        if (res < 0)
511
            _sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
512
        else
513
            (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
514

515
        *size = strnlen(buffer, SIR_MAXPATH);
516
        return 0;
517
    } else if (strchr(argv[0], '/') != NULL) {
518
        (void)snprintf(cwd, SIR_MAXPATH, "/proc/%llu/cwd", (unsigned long long)_sir_getpid());
519

520
        /* Flawfinder: ignore */
521
        res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
522
        if (res < 0)
523
            return -1;
524

525
        (void)snprintf(symlink, SIR_MAXPATH, "%s%s", cwdl, argv[0]);
526

527
        /* Flawfinder: ignore */
528
        res = readlink(symlink, temp_buffer, SIR_MAXPATH);
529
        if (res < 0)
530
            _sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
531
        else
532
            (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
533

534
        *size = strnlen(buffer, SIR_MAXPATH);
535
        return 0;
536
    } else {
537
        char clonedpath[16384];
538
        char* token = NULL;
539
        struct stat statstruct;
540

541
        char* path = getenv("PATH");
542
        if (sizeof(clonedpath) <= strnlen(path, SIR_MAXPATH))
543
            return -1;
544

545
        _sir_strncpy(clonedpath, SIR_MAXPATH, path, SIR_MAXPATH);
546

547
        token = strtok_r(clonedpath, ":", &tokptr);
548

549
        (void)snprintf(cwd, SIR_MAXPATH, "/proc/%llu/cwd", (unsigned long long)_sir_getpid());
550
        /* Flawfinder: ignore */
551
        res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
552
        if (res < 0)
553
            return -1;
554

555
        while (token != NULL) {
556
            if (token[0] == '.') {
557
                char* relative = strchr(token, '/');
558
                if (relative != NULL) {
559
                    (void)snprintf(symlink, SIR_MAXSLPATH, "%s%s/%s", cwdl, relative + 1,
560
                        ps.pr_fname);
561
                } else {
562
                    (void)snprintf(symlink, SIR_MAXSLPATH, "%s%s", cwdl, ps.pr_fname);
563
                }
564

565
                if (stat(symlink, &statstruct) != -1) {
566
                    /* Flawfinder: ignore */
567
                    res = readlink(symlink, temp_buffer, SIR_MAXPATH);
568
                    if (res < 0)
569
                        _sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
570
                    else
571
                        (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
572

573
                    *size = strnlen(buffer, SIR_MAXPATH);
574
                    return 0;
575
                }
576
            } else {
577
                (void)snprintf(symlink, SIR_MAXPATH, "%s/%s", token, ps.pr_fname);
578
                if (stat(symlink, &statstruct) != -1) {
579
                    /* Flawfinder: ignore */
580
                    res = readlink(symlink, temp_buffer, SIR_MAXPATH);
581
                    if (res < 0)
582
                        _sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
583
                    else
584
                        (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
585

586
                    *size = strnlen(buffer, SIR_MAXPATH);
587
                    return 0;
588
                }
589
            }
590

591
            token = strtok_r(NULL, ":", &tokptr);
592
        }
593
        return -1;
594
    }
595
}
596
#endif
597

598
bool _sir_deletefile(const char* restrict path) {
446✔
599
    if (!_sir_validstr(path))
446✔
600
        return false;
×
601

602
#if !defined(__WIN__)
603
    return (0 == unlink(path)) ? true : _sir_handleerr(errno);
446✔
604
#else /* __WIN__ */
605
    return (FALSE != DeleteFileA(path)) ? true : _sir_handlewin32err(GetLastError());
606
#endif
607
}
608

609
#if defined(__OpenBSD__)
610
int _sir_openbsdself(char* out, int capacity, int* dirname_length) {
611
    char buffer1[4096];
612
    char buffer2[SIR_MAXPATH];
613
    char buffer3[SIR_MAXPATH];
614
    char** argv    = (char**)buffer1;
615
    char* resolved = NULL;
616
    int length     = -1;
617

618
    while (1) {
619
        int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
620
        size_t size;
621

622
        if (sysctl(mib, 4, NULL, &size, NULL, 0) != 0)
623
            break;
624

625
        if (size > sizeof(buffer1)) {
626
            argv = (char**)malloc(size);
627
            if (!argv)
628
                break;
629
        }
630

631
        if (sysctl(mib, 4, argv, &size, NULL, 0) != 0)
632
            break;
633

634
        if (strchr(argv[0], '/')) {
635
            resolved = realpath(argv[0], buffer2);
636
            if (!resolved)
637
                break;
638
        } else {
639
            const char* PATH = getenv("PATH");
640
            if (!PATH)
641
                break;
642
            size_t argv0_length = strnlen(argv[0], SIR_MAXPATH);
643
            const char* begin   = PATH;
644
            while (1) {
645
                const char* separator = strchr(begin, ':');
646
                const char* end = separator ? separator : begin + strnlen(begin, SIR_MAXPATH);
647
                if (end - begin > 0) {
648
                    if (*(end - 1) == '/')
649
                        --end;
650
                    if (((end - begin) + 1UL + argv0_length + 1UL) <= sizeof(buffer2)) {
651
                        memcpy(buffer2, begin, end - begin);
652
                        buffer2[end - begin] = '/';
653
                        memcpy(buffer2 + (end - begin) + 1, argv[0], argv0_length + 1);
654
                        resolved = realpath(buffer2, buffer3);
655
                        if (resolved)
656
                            break;
657
                    }
658
                }
659
                if (!separator)
660
                    break;
661
                begin = ++separator;
662
            }
663
            if (!resolved)
664
                break;
665
        }
666

667
        length = (int)strnlen(resolved, SIR_MAXPATH);
668
        if (length <= capacity) {
669
            memcpy(out, resolved, (unsigned long)length);
670
            if (dirname_length) {
671
                int i;
672
                for (i = length - 1; i >= 0; --i) {
673
                    if (out[i] == '/') {
674
                        *dirname_length = i;
675
                        break;
676
                    }
677
                }
678
            }
679
        }
680
        break;
681
    }
682
    if (argv != (char**)buffer1)
683
        free(argv);
684

685
    return length;
686
}
687
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc