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

aremmell / libsir / 266

29 Aug 2023 12:36PM UTC coverage: 94.955% (-0.06%) from 95.017%
266

Pull #241

gitlab-ci

web-flow
Merge branch 'master' into maybe-enums
Pull Request #241: Change sir_level and sir_option to defines, rather than enum

86 of 86 new or added lines in 9 files covered. (100.0%)

3030 of 3191 relevant lines covered (94.95%)

603446.22 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.3
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(__EMBARCADEROC__) && defined(_WIN64)
31
#  pragma comment(lib, "shlwapi.a")
32
# else
33
#  pragma comment(lib, "shlwapi.lib")
34
# endif
35
#endif
36

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

41
    memset(st, 0, sizeof(struct stat));
238✔
42

43
    int stat_ret          = -1;
238✔
44
    bool relative         = false;
271✔
45
    const char* base_path = NULL;
271✔
46

47
    if (!_sir_getrelbasepath(path, &relative, &base_path, rel_to))
271✔
48
        return false;
28✔
49

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

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

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

89
# if defined(__EMBARCADEROC__)
90
        /* Embarcadero does not like paths that end in slashes, nor does it appreciate
91
         * paths like './' and '../'; this is a hack until those defects are resolved. */
92
        char resolved_path[SIR_MAXPATH] = {0};
93

94
        if (!GetFullPathNameA(abs_path, SIR_MAXPATH, resolved_path, NULL)) {
95
            _sir_safefree(&base_path);
96
            return _sir_handlewin32err(GetLastError());
97
        }
98

99
        PathRemoveBackslashA(resolved_path);
100
        (void)_sir_strlcpy(abs_path, resolved_path, SIR_MAXPATH);
101
# endif
102

103
        stat_ret = stat(abs_path, st);
104
        _sir_safefree(&base_path);
105
    } else {
106
        stat_ret = stat(path, st);
107
    }
108
#endif
109
    if (-1 == stat_ret && (ENOENT == errno || ENOTDIR == errno))
243✔
110
        st->st_size = SIR_STAT_NONEXISTENT;
74✔
111

112
    return (-1 != stat_ret || ENOENT == errno || ENOTDIR == errno) ? true : _sir_handleerr(errno);
219✔
113
}
114

115
bool _sir_pathexists(const char* path, bool* exists, sir_rel_to rel_to) {
271✔
116
    if (!_sir_validstr(path) || !_sir_validptr(exists))
271✔
117
        return false;
×
118

119
    *exists = false;
271✔
120

121
    struct stat st = {0};
271✔
122
    bool stat_ret  = _sir_pathgetstat(path, &st, rel_to);
271✔
123
    if (!stat_ret)
271✔
124
        return false;
28✔
125

126
    *exists = (st.st_size != SIR_STAT_NONEXISTENT);
243✔
127
    return true;
243✔
128
}
129

130
bool _sir_openfile(FILE* restrict* restrict f, const char* restrict path,
35,926✔
131
    const char* restrict mode, sir_rel_to rel_to) {
132
    if (!_sir_validptrptr(f) || !_sir_validstr(path) || !_sir_validstr(mode))
35,926✔
133
        return false;
×
134

135
    bool relative         = false;
35,926✔
136
    const char* base_path = NULL;
35,926✔
137

138
    if (!_sir_getrelbasepath(path, &relative, &base_path, rel_to))
35,926✔
139
        return false;
4✔
140

141
    if (relative) {
35,922✔
142
        char abs_path[SIR_MAXPATH] = {0};
35,902✔
143
        (void)snprintf(abs_path, SIR_MAXPATH, "%s/%s", base_path, path);
35,902✔
144

145
        int ret = _sir_fopen(f, abs_path, mode);
35,902✔
146
        _sir_safefree(&base_path);
35,902✔
147
        return 0 == ret;
35,902✔
148
    }
149

150
    return 0 == _sir_fopen(f, path, mode);
20✔
151
}
152

153
#if defined(_AIX)
154
static char cur_cwd[SIR_MAXPATH];
155
#endif
156
char* _sir_getcwd(void) {
35,957✔
157
#if !defined(__WIN__)
158
# if defined(__linux__) && (defined(__GLIBC__) && defined(_GNU_SOURCE))
159
    char* cur = get_current_dir_name();
35,957✔
160
    if (!_sir_validptrnofail(cur))
35,957✔
161
        (void)_sir_handleerr(errno);
×
162
    return cur;
35,957✔
163
# elif defined(_AIX)
164
    if (getcwd(cur_cwd, sizeof(cur_cwd)) == 0) {
165
        (void)_sir_handleerr(errno);
166
        return NULL;
167
    } else {
168
        return strndup(cur_cwd, SIR_MAXPATH);
169
    }
170
# else
171
    char* cur = getcwd(NULL, 0);
172
    if (NULL == cur)
173
        (void)_sir_handleerr(errno);
174
    return cur;
175
# endif
176
#else /* __WIN__ */
177
    DWORD size = GetCurrentDirectoryA(0ul, NULL);
178
    if (0ul == size) {
179
        _sir_handlewin32err(GetLastError());
180
        return NULL;
181
    }
182

183
    char* cur = calloc(size, sizeof(char));
184
    if (!cur) {
185
        _sir_handleerr(errno);
186
        return NULL;
187
    }
188

189
    if (!GetCurrentDirectoryA(size, cur)) {
190
        _sir_handlewin32err(GetLastError());
191
        _sir_safefree(cur);
192
        return NULL;
193
    }
194

195
    return cur;
196
#endif
197
}
198

199
char* _sir_getappfilename(void) {
238✔
200
#if defined(__linux__) || defined(__NetBSD__) || defined(__SOLARIS__) || \
201
    defined(__DragonFly__) || defined(__CYGWIN__) || defined(__serenity__) || \
202
    defined(__HURD__)
203
# define __READLINK_OS__
204
# if defined(__linux__) || defined(__CYGWIN__) || \
205
     defined(__serenity__) || defined(__HURD__)
206
#  define PROC_SELF "/proc/self/exe"
207
# elif defined(__NetBSD__)
208
#  define PROC_SELF "/proc/curproc/exe"
209
# elif defined(__DragonFly__)
210
#  define PROC_SELF "/proc/curproc/file"
211
# elif defined(__SOLARIS__)
212
#  define PROC_SELF "/proc/self/path/a.out"
213
# endif
214
    struct stat st;
215
    if (-1 == lstat(PROC_SELF, &st)) {
238✔
216
        (void)_sir_handleerr(errno);
9✔
217
        return NULL;
9✔
218
    }
219

220
    size_t size = (st.st_size > 0) ? st.st_size + 2 : SIR_MAXPATH;
229✔
221
#else
222
    size_t size = SIR_MAXPATH;
223
#endif
224

225
    char* buffer  = NULL;
229✔
226
    bool resolved = false;
196✔
227

228
    do {
×
229
        _sir_safefree(&buffer);
229✔
230
        buffer = (char*)calloc(size, sizeof(char));
229✔
231
        if (NULL == buffer) {
229✔
232
            resolved = _sir_handleerr(errno);
12✔
233
            break;
12✔
234
        }
235

236
#if !defined(__WIN__)
237
# if defined(__READLINK_OS__)
238
        /* Flawfinder: ignore */
239
        ssize_t read = readlink(PROC_SELF, buffer, size - 1);
217✔
240
        if (-1l != read && read < (ssize_t)size - 1) {
217✔
241
            resolved = true;
175✔
242
            break;
175✔
243
        } else if (-1l == read) {
9✔
244
            resolved = _sir_handleerr(errno);
9✔
245
            break;
9✔
246
        } else if (read == (ssize_t)size - 1l) {
×
247
            /*
248
             * It is possible that truncation occurred. As a security
249
             * precaution, fail; someone may have tampered with the link.
250
             */
251
            _sir_selflog("warning: readlink reported truncation; not using result!");
×
252
            resolved = false;
×
253
            break;
×
254
        }
255
# elif defined(_AIX)
256
        if (size <= SIR_MAXPATH) {
257
            size = size + SIR_MAXPATH + 1l;
258
            continue;
259
        }
260
        int ret = _sir_aixself(buffer, &size);
261
        if (ret == 0) {
262
            resolved = true;
263
            break;
264
        } else {
265
            resolved = _sir_handleerr(errno);
266
            break;
267
        }
268
# elif defined(__OpenBSD__)
269
        size_t length;
270
        int dirname_length;
271
        length = _sir_openbsdself(NULL, 0, &dirname_length);
272
        if (length < 1) {
273
            resolved = _sir_handleerr(errno);
274
            break;
275
        }
276
        if (length > size) {
277
            size = length + 1;
278
            continue;
279
        }
280
        (void)_sir_openbsdself(buffer, length, &dirname_length);
281
        if (!buffer) {
282
            resolved = false;
283
            break;
284
        }
285
        resolved = true;
286
        break;
287
# elif defined(__BSD__)
288
        int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
289
        int ret = sysctl(mib, 4, buffer, &size, NULL, 0);
290
        if (0 == ret) {
291
            resolved = true;
292
            break;
293
        } else {
294
            if (ENOMEM == errno && 0 == sysctl(mib, 4, NULL, &size, NULL, 0))
295
                continue; /* grow buffer. */
296

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

345
    } while (true);
346

347
    if (!resolved)
229✔
348
        _sir_safefree(&buffer);
21✔
349

350
    return buffer;
229✔
351
}
352

353
char* _sir_getappbasename(void) {
21✔
354
    char* filename = _sir_getappfilename();
21✔
355
    if (!_sir_validstr(filename)) {
21✔
356
        _sir_safefree(&filename);
3✔
357
        return NULL;
3✔
358
    }
359

360
    char* retval = _sir_getbasename(filename);
18✔
361
    char* bname  = strndup(retval, strnlen(retval, SIR_MAXPATH));
18✔
362

363
    _sir_safefree(&filename);
18✔
364
    return bname;
18✔
365
}
366

367
char* _sir_getappdir(void) {
195✔
368
    char* filename = _sir_getappfilename();
195✔
369
    if (!_sir_validstr(filename)) {
195✔
370
        _sir_safefree(&filename);
24✔
371
        return NULL;
24✔
372
    }
373

374
    char* retval  = _sir_getdirname(filename);
171✔
375
    char* dirname = strndup(retval, strnlen(retval, SIR_MAXPATH));
171✔
376

377
    _sir_safefree(&filename);
171✔
378
    return dirname;
171✔
379
}
380

381
char* _sir_getbasename(char* restrict path) {
141✔
382
    if (!_sir_validstr(path))
141✔
383
        return ".";
18✔
384

385
#if !defined(__WIN__)
386
    return basename(path);
120✔
387
#else /* __WIN__ */
388
    return PathFindFileNameA(path);
389
#endif
390
}
391

392
char* _sir_getdirname(char* restrict path) {
315✔
393
    if (!_sir_validstr(path))
315✔
394
        return ".";
18✔
395

396
#if !defined(__WIN__)
397
    return dirname(path);
294✔
398
#else /* __WIN__ */
399
    (void)PathRemoveFileSpecA((LPSTR)path);
400
    return path;
401
#endif
402
}
403

404
bool _sir_ispathrelative(const char* restrict path, bool* restrict relative) {
36,373✔
405
    bool valid = _sir_validstr(path) && _sir_validptr(relative);
36,373✔
406

407
    if (valid) {
30,260✔
408
#if !defined(__WIN__)
409
        if (path[0] == '/' || (path[0] == '~' && path[1] == '/'))
36,373✔
410
            *relative = false;
174✔
411
        else
412
            *relative = true;
36,199✔
413
#else /* __WIN__ */
414
        *relative = (TRUE == PathIsRelativeA(path));
415
#endif
416
    }
417

418
    return valid;
36,373✔
419
}
420

421
bool _sir_getrelbasepath(const char* restrict path, bool* restrict relative,
36,197✔
422
    const char* restrict* restrict base_path, sir_rel_to rel_to) {
423
    if (!_sir_validstr(path) || !_sir_validptr(relative) ||
42,286✔
424
        !_sir_validptrptr(base_path) || !_sir_ispathrelative(path, relative))
42,286✔
425
        return false;
×
426

427
    if (*relative) {
36,197✔
428
        switch (rel_to) {
36,111✔
429
            case SIR_PATH_REL_TO_APP: return NULL != (*base_path = _sir_getappdir());
176✔
430
            case SIR_PATH_REL_TO_CWD: return NULL != (*base_path = _sir_getcwd());
35,935✔
431
            default: return _sir_seterror(_SIR_E_INVALID);
×
432
        }
433
    }
434

435
    return true;
74✔
436
}
437

438
#if defined(_AIX)
439
# define SIR_MAXSLPATH (SIR_MAXPATH + 16)
440
int _sir_aixself(char* buffer, size_t* size) {
441
    ssize_t res;
442
    char cwd[SIR_MAXPATH], cwdl[SIR_MAXPATH];
443
    char symlink[SIR_MAXSLPATH], temp_buffer[SIR_MAXPATH];
444
    char pp[64];
445
    struct psinfo ps;
446
    int fd;
447
    char** argv;
448
    char* tokptr;
449

450
    if ((buffer == NULL) || (size == NULL))
451
        return -1;
452

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

455
    fd = open(pp, O_RDONLY);
456
    if (fd < 0)
457
        return -1;
458

459
    res = read(fd, &ps, sizeof(ps));
460
    close(fd);
461
    if (res < 0)
462
        return -1;
463

464
    if (ps.pr_argv == 0)
465
        return -1;
466

467
    argv = (char**)*((char***)(intptr_t)ps.pr_argv);
468

469
    if ((argv == NULL) || (argv[0] == NULL))
470
        return -1;
471

472
    if (argv[0][0] == '/') {
473
        (void)snprintf(symlink, SIR_MAXPATH, "%s", argv[0]);
474

475
        /* Flawfinder: ignore */
476
        res = readlink(symlink, temp_buffer, SIR_MAXPATH);
477
        if (res < 0)
478
            _sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
479
        else
480
            (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink),
481
                temp_buffer);
482

483
        *size = strnlen(buffer, SIR_MAXPATH);
484
        return 0;
485
    } else if (argv[0][0] == '.') {
486
        char* relative = strchr(argv[0], '/');
487
        if (relative == NULL)
488
            return -1;
489

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

492
        /* Flawfinder: ignore */
493
        res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
494
        if (res < 0)
495
            return -1;
496

497
        (void)snprintf(symlink, SIR_MAXPATH, "%s%s", cwdl, relative + 1);
498

499
        /* Flawfinder: ignore */
500
        res = readlink(symlink, temp_buffer, SIR_MAXPATH);
501
        if (res < 0)
502
            _sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
503
        else
504
            (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
505

506
        *size = strnlen(buffer, SIR_MAXPATH);
507
        return 0;
508
    } else if (strchr(argv[0], '/') != NULL) {
509
        (void)snprintf(cwd, SIR_MAXPATH, "/proc/%llu/cwd", (unsigned long long)_sir_getpid());
510

511
        /* Flawfinder: ignore */
512
        res = readlink(cwd, cwdl, sizeof(cwdl) - 1);
513
        if (res < 0)
514
            return -1;
515

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

518
        /* Flawfinder: ignore */
519
        res = readlink(symlink, temp_buffer, SIR_MAXPATH);
520
        if (res < 0)
521
            _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
        _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
        /* Flawfinder: ignore */
542
        res = 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
                    /* Flawfinder: ignore */
558
                    res = readlink(symlink, temp_buffer, SIR_MAXPATH);
559
                    if (res < 0)
560
                        _sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
561
                    else
562
                        (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
563

564
                    *size = strnlen(buffer, SIR_MAXPATH);
565
                    return 0;
566
                }
567
            } else {
568
                (void)snprintf(symlink, SIR_MAXPATH, "%s/%s", token, ps.pr_fname);
569
                if (stat(symlink, &statstruct) != -1) {
570
                    /* Flawfinder: ignore */
571
                    res = readlink(symlink, temp_buffer, SIR_MAXPATH);
572
                    if (res < 0)
573
                        _sir_strncpy(buffer, SIR_MAXPATH, symlink, SIR_MAXPATH);
574
                    else
575
                        (void)snprintf(buffer, *size - 1, "%s/%s", (char*)dirname(symlink), temp_buffer);
576

577
                    *size = strnlen(buffer, SIR_MAXPATH);
578
                    return 0;
579
                }
580
            }
581

582
            token = strtok_r(NULL, ":", &tokptr);
583
        }
584
        return -1;
585
    }
586
}
587
#endif
588

589
bool _sir_deletefile(const char* restrict path) {
473✔
590
    if (!_sir_validstr(path))
473✔
591
        return false;
×
592

593
#if !defined(__WIN__)
594
    return (0 == unlink(path)) ? true : _sir_handleerr(errno);
473✔
595
#else /* __WIN__ */
596
    return (FALSE != DeleteFileA(path)) ? true : _sir_handlewin32err(GetLastError());
597
#endif
598
}
599

600
#if defined(__OpenBSD__)
601
int _sir_openbsdself(char* out, int capacity, int* dirname_length) {
602
    char buffer1[4096];
603
    char buffer2[SIR_MAXPATH];
604
    char buffer3[SIR_MAXPATH];
605
    char** argv    = (char**)buffer1;
606
    char* resolved = NULL;
607
    int length     = -1;
608

609
    while (1) {
610
        int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
611
        size_t size;
612

613
        if (sysctl(mib, 4, NULL, &size, NULL, 0) != 0)
614
            break;
615

616
        if (size > sizeof(buffer1)) {
617
            argv = (char**)malloc(size);
618
            if (!argv)
619
                break;
620
        }
621

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

625
        if (strchr(argv[0], '/')) {
626
            resolved = realpath(argv[0], buffer2);
627
            if (!resolved)
628
                break;
629
        } else {
630
            const char* PATH = getenv("PATH");
631
            if (!PATH)
632
                break;
633
            size_t argv0_length = strnlen(argv[0], SIR_MAXPATH);
634
            const char* begin   = PATH;
635
            while (1) {
636
                const char* separator = strchr(begin, ':');
637
                const char* end = separator ? separator : begin + strnlen(begin, SIR_MAXPATH);
638
                if (end - begin > 0) {
639
                    if (*(end - 1) == '/')
640
                        --end;
641
                    if (((end - begin) + 1UL + argv0_length + 1UL) <= sizeof(buffer2)) {
642
                        memcpy(buffer2, begin, end - begin);
643
                        buffer2[end - begin] = '/';
644
                        memcpy(buffer2 + (end - begin) + 1, argv[0], argv0_length + 1);
645
                        resolved = realpath(buffer2, buffer3);
646
                        if (resolved)
647
                            break;
648
                    }
649
                }
650
                if (!separator)
651
                    break;
652
                begin = ++separator;
653
            }
654
            if (!resolved)
655
                break;
656
        }
657

658
        length = (int)strnlen(resolved, SIR_MAXPATH);
659
        if (length <= capacity) {
660
            memcpy(out, resolved, (unsigned long)length);
661
            if (dirname_length) {
662
                int i;
663
                for (i = length - 1; i >= 0; --i) {
664
                    if (out[i] == '/') {
665
                        *dirname_length = i;
666
                        break;
667
                    }
668
                }
669
            }
670
        }
671
        break;
672
    }
673
    if (argv != (char**)buffer1)
674
        free(argv);
675

676
    return length;
677
}
678
#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