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

aremmell / libsir / 839

23 Sep 2023 06:32AM UTC coverage: 94.27% (-0.3%) from 94.537%
839

Pull #292

gitlab-ci

johnsonjh
Docs ...

Signed-off-by: Jeffrey H. Johnson <trnsz@pobox.com>
Pull Request #292: Python/Ch bindings (& general support for new bindings), WIP C++ header-only wrapper implementation

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

3570 of 3787 relevant lines covered (94.27%)

530034.79 hits per line

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

88.67
/src/sirfilecache.c
1
/*
2
 * sirfilecache.c
3
 *
4
 * Author:    Ryan M. Lederman <lederman@gmail.com>
5
 * Copyright: Copyright (c) 2018-2023
6
 * Version:   2.2.4
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/filecache.h"
27
#include "sir/filesystem.h"
28
#include "sir/internal.h"
29
#include "sir/defaults.h"
30

31
sirfileid _sir_addfile(const char* path, sir_levels levels, sir_options opts) {
36,968✔
32
    (void)_sir_seterror(_SIR_E_NOERROR);
36,968✔
33

34
    if (!_sir_sanity())
36,968✔
35
        return 0U;
×
36

37
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, 0U);
36,968✔
38

39
    _sir_defaultlevels(&levels, sir_file_def_lvls);
36,968✔
40
    _sir_defaultopts(&opts, sir_file_def_opts);
36,968✔
41

42
    sirfileid retval = _sir_fcache_add(sfc, path, levels, opts);
36,968✔
43
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
36,968✔
44

45
    return retval;
36,968✔
46
}
47

48
bool _sir_updatefile(sirfileid id, const sir_update_config_data* data) {
36,212✔
49
    (void)_sir_seterror(_SIR_E_NOERROR);
36,212✔
50

51
    if (!_sir_sanity() || !_sir_validfileid(id) || !_sir_validupdatedata(data))
36,212✔
52
        return false;
3✔
53

54
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
36,208✔
55
    bool retval = _sir_fcache_update(sfc, id, data);
36,209✔
56
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
36,209✔
57

58
    return retval;
36,208✔
59
}
60

61
bool _sir_remfile(sirfileid id) {
36,795✔
62
    (void)_sir_seterror(_SIR_E_NOERROR);
36,795✔
63

64
    if (!_sir_sanity() || !_sir_validfileid(id))
36,794✔
65
        return false;
81✔
66

67
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
36,711✔
68
    bool retval = _sir_fcache_rem(sfc, id);
36,716✔
69
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
36,716✔
70

71
    return retval;
36,716✔
72
}
73

74
sirfile* _sirfile_create(const char* path, sir_levels levels, sir_options opts) {
36,869✔
75
    if (!_sir_validstr(path) || !_sir_validlevels(levels) || !_sir_validopts(opts))
36,869✔
76
        return NULL;
×
77

78
    sirfile* sf = (sirfile*)calloc(1, sizeof(sirfile));
36,869✔
79
    if (!sf) {
36,869✔
80
        (void)_sir_handleerr(errno);
31✔
81
        return NULL;
31✔
82
    }
83

84
    sf->path = strndup(path, strnlen(path, SIR_MAXPATH));
36,838✔
85
    if (!sf->path) {
36,838✔
86
        (void)_sir_handleerr(errno);
35✔
87
        _sir_safefree(&sf);
35✔
88
        return NULL;
35✔
89
    }
90

91
    sf->levels = levels;
36,803✔
92
    sf->opts   = opts;
36,803✔
93

94
    if (!_sirfile_open(sf) || !_sirfile_validate(sf)) {
36,803✔
95
        _sirfile_destroy(&sf);
71✔
96
        return NULL;
71✔
97
    }
98

99
    return sf;
36,732✔
100
}
101

102
bool _sirfile_open(sirfile* sf) {
36,819✔
103
    if (!_sir_validptr(sf) && !_sir_validstr(sf->path))
36,819✔
104
        return false;
×
105

106
    FILE* f  = NULL;
36,819✔
107
    bool open = _sir_openfile(&f, sf->path, SIR_FOPENMODE, SIR_PATH_REL_TO_CWD);
36,819✔
108
    if (!open || !f)
36,819✔
109
        return false;
65✔
110

111
    _sirfile_close(sf);
36,748✔
112

113
    sf->f  = f;
36,748✔
114
    sf->id = FNV32_1a((const uint8_t*)sf->path, strnlen(sf->path, SIR_MAXPATH));
36,748✔
115

116
    return true;
36,748✔
117
}
118

119
void _sirfile_close(sirfile* sf) {
73,551✔
120
    if (!_sir_validptrnofail(sf))
73,551✔
121
        return;
×
122

123
    _sir_safefclose(&sf->f);
73,551✔
124
}
125

126
bool _sirfile_write(sirfile* sf, const char* output) {
1,322,331✔
127
    if (!_sirfile_validate(sf) || !_sir_validstr(output))
1,322,331✔
128
        return false;
×
129

130
    if (sf->writes_since_size_chk++ > SIR_FILE_CHK_SIZE_WRITES) {
1,322,331✔
131
        sf->writes_since_size_chk = 0;
93,695✔
132

133
        if (_sirfile_needsroll(sf)) {
93,695✔
134
            bool rolled   = false;
79,319✔
135
            char* newpath = NULL;
79,322✔
136

137
            _sir_selflog("file (path: '%s', id: %"PRIx32") reached ~%d bytes in size;"
79,321✔
138
                         " rolling...", sf->path, sf->id, SIR_FROLLSIZE);
139

140
            _sir_fflush(sf->f);
79,322✔
141

142
            if (_sirfile_roll(sf, &newpath)) {
79,322✔
143
                char header[SIR_MAXFHEADER] = {0};
16✔
144
                (void)snprintf(header, SIR_MAXFHEADER, SIR_FHROLLED, newpath);
16✔
145
                rolled = _sirfile_writeheader(sf, header);
16✔
146
            }
147

148
            _sir_safefree(&newpath);
79,322✔
149
            if (!rolled) /* write anyway; don't want to lose data. */
79,321✔
150
                _sir_selflog("error: failed to roll file (path: '%s', id: %" PRIx32")!",
79,306✔
151
                    sf->path, sf->id);
152
        }
153
    }
154

155
    size_t writeLen = strnlen(output, SIR_MAXOUTPUT);
1,322,331✔
156
    size_t write    = fwrite(output, sizeof(char), writeLen, sf->f);
1,322,331✔
157

158
    SIR_ASSERT(write == writeLen);
1,304,323✔
159

160
    if (write < writeLen) {
1,322,331✔
161
        (void)_sir_handleerr(errno);
×
162
        clearerr(sf->f);
×
163
    }
164

165
    return write == writeLen;
1,322,331✔
166
}
167

168
bool _sirfile_writeheader(sirfile* sf, const char* msg) {
36,692✔
169
    if (!_sirfile_validate(sf) || !_sir_validstr(msg))
36,692✔
170
        return false;
×
171

172
    time_t now = -1;
36,692✔
173
    time(&now);
36,692✔
174

175
    char timestamp[SIR_MAXTIME] = {0};
36,692✔
176
    bool fmttime = _sir_formattime(now, timestamp, SIR_FHTIMEFORMAT);
36,692✔
177
    if (!fmttime)
36,692✔
178
        return false;
1,977✔
179

180
    char header[SIR_MAXFHEADER] = {0};
34,715✔
181
    (void)snprintf(header, SIR_MAXFHEADER, SIR_FHFORMAT, msg, timestamp);
28,602✔
182

183
    return _sirfile_write(sf, header);
34,715✔
184
}
185

186
bool _sirfile_needsroll(sirfile* sf) {
93,695✔
187
    if (!_sirfile_validate(sf))
93,695✔
188
        return false;
×
189

190
    struct stat st = {0};
93,695✔
191
    int getstat    = fstat(fileno(sf->f), &st);
93,695✔
192

193
    if (0 != getstat) { /* if fstat fails, try stat on the path. */
93,695✔
194
        getstat = stat(sf->path, &st);
584✔
195
        if (0 != getstat)
584✔
196
            return _sir_handleerr(errno);
×
197
    }
198

199
    return st.st_size + BUFSIZ >= SIR_FROLLSIZE ||
108,078✔
200
        SIR_FROLLSIZE - (st.st_size + BUFSIZ) <= BUFSIZ;
14,380✔
201
}
202

203
bool _sirfile_roll(sirfile* sf, char** newpath) {
79,322✔
204
    if (!_sirfile_validate(sf) || !_sir_validptrptr(newpath))
79,322✔
205
        return false;
×
206

207
    bool retval = false;
79,319✔
208
    char* name = NULL;
79,322✔
209
    char* ext  = NULL;
79,322✔
210

211
    bool split = _sirfile_splitpath(sf, &name, &ext);
79,322✔
212
    SIR_ASSERT(split);
79,321✔
213

214
    if (split) {
79,320✔
215
        time_t now = -1;
28✔
216

217
        time(&now);
28✔
218
        SIR_ASSERT(-1 != now);
27✔
219

220
        if (-1 != now) {
28✔
221
            char timestamp[SIR_MAXTIME] = {0};
22✔
222
            bool fmttime = _sir_formattime(now, timestamp, SIR_FNAMETIMEFORMAT);
22✔
223
            SIR_ASSERT(fmttime);
21✔
224

225
            if (fmttime) {
20✔
226
                *newpath = (char*)calloc(SIR_MAXPATH, sizeof(char));
16✔
227

228
                if (_sir_validptr(*newpath)) {
16✔
229
                    char seqbuf[7] = {0};
16✔
230
                    bool exists = false;
16✔
231
                    bool resolved = false;
13✔
232
                    uint16_t sequence = 0U;
13✔
233

234
                    do {
235
                        (void)snprintf(*newpath, SIR_MAXPATH, SIR_FNAMEFORMAT, name,
19✔
236
                            timestamp, (sequence > 0U ? seqbuf : ""),
237
                            _sir_validstrnofail(ext) ? ext : "");
16✔
238

239
                        /* if less than one second has elapsed since the last roll
240
                         * operation, then we'll overwrite the last rolled log file,
241
                         * and that = data loss. make sure the target path does not
242
                         * already exist. */
243
                        if (!_sir_pathexists(*newpath, &exists, SIR_PATH_REL_TO_CWD)) {
16✔
244
                            /* failed to determine if the file already exists; it is better
245
                             * to continue logging to the same file than to possibly overwrite
246
                             * another (if it failed this time, it will again, so there's no
247
                             * way to definitively choose a good new path). */
248
                            break;
×
249
                        } else if (exists) {
16✔
250
                            /* the file already exists; add a number to the file name
251
                             * until one that does not exist is found. */
252
                            _sir_selflog("path: '%s' already exists; incrementing sequence", *newpath); //-V576
×
253
                            sequence++;
×
254
                        } else {
255
                            _sir_selflog("found good path: '%s'", *newpath);
15✔
256
                            resolved = true;
13✔
257
                            break;
13✔
258
                        }
259

260
                        if (sequence > 0)
×
261
                            (void)snprintf(seqbuf, 7, SIR_FNAMESEQFORMAT, sequence);
×
262

263
                    } while (sequence <= 999U);
×
264

265
                    if (!resolved)
13✔
266
                        _sir_selflog("error: unable to determine suitable path for '%s';"
×
267
                                        " not rolling!", sf->path);
268

269
                    retval = resolved && _sirfile_archive(sf, *newpath);
16✔
270
                }
271
            }
272
        }
273
    }
274

275
    _sir_safefree(&name);
79,322✔
276
    _sir_safefree(&ext);
79,322✔
277

278
    return retval;
79,322✔
279

280
}
281

282
bool _sirfile_archive(sirfile* sf, const char* newpath) {
16✔
283
    if (!_sirfile_validate(sf) || !_sir_validstr(newpath))
16✔
284
        return false;
×
285

286
#if defined(__WIN__)
287
    /* apparently, need to close the old file first on windows. */
288
    _sirfile_close(sf);
289
#endif
290

291
    if (0 != rename(sf->path, newpath))
16✔
292
        return _sir_handleerr(errno);
×
293

294
    if (_sirfile_open(sf)) {
16✔
295
        _sir_selflog("archived '%s' " SIR_R_ARROW " '%s'", sf->path, newpath);
15✔
296
        return true;
15✔
297
    }
298

299
    return false;
×
300
}
301

302
bool _sirfile_splitpath(const sirfile* sf, char** name, char** ext) {
79,322✔
303
    if (_sir_validptrptr(name))
79,322✔
304
        *name = NULL;
79,322✔
305
    if (_sir_validptrptr(ext))
79,322✔
306
        *ext = NULL;
79,322✔
307

308
    if (!_sirfile_validate(sf) || !_sir_validptrptr(name) || !_sir_validptrptr(ext))
79,322✔
309
        return false;
×
310

311
    char* tmp = strndup(sf->path, strnlen(sf->path, SIR_MAXPATH));
79,322✔
312
    if (!tmp)
79,322✔
313
        return _sir_handleerr(errno);
×
314

315
    const char* lastfullstop = strrchr(tmp, '.');
79,322✔
316
    if (lastfullstop) {
79,322✔
317
        uintptr_t namesize = lastfullstop - tmp;
79,322✔
318
        SIR_ASSERT(namesize < SIR_MAXPATH);
79,321✔
319

320
        tmp[namesize] = '\0';
79,322✔
321
        *name = (char*)calloc(namesize + 1, sizeof(char));
79,322✔
322
        if (!*name) {
79,322✔
323
            _sir_safefree(&tmp);
×
324
            return _sir_handleerr(errno);
×
325
        }
326

327
        _sir_strncpy(*name, namesize + 1, tmp, namesize);
79,322✔
328
        *ext = strndup(sf->path + namesize, strnlen(sf->path + namesize, SIR_MAXPATH));
79,322✔
329
    } else {
330
        *name = strndup(sf->path, strnlen(sf->path, SIR_MAXPATH));
×
331
    }
332

333
    _sir_safefree(&tmp);
79,322✔
334
    return _sir_validstr(*name) && (!lastfullstop || _sir_validstr(*ext));
79,325✔
335
}
336

337
void _sirfile_destroy(sirfile** sf) {
36,803✔
338
    if (sf && *sf) {
36,803✔
339
        _sirfile_close(*sf);
36,803✔
340
        _sir_safefree(&(*sf)->path);
36,803✔
341
        _sir_safefree(sf);
36,803✔
342
    }
343
}
36,803✔
344

345
bool _sirfile_validate(const sirfile* sf) {
3,071,278✔
346
    return _sir_validptrnofail(sf) && _sir_validptrnofail(sf->f) &&
9,213,560✔
347
           _sir_validstrnofail(sf->path) && _sir_validfileid(sf->id);
9,213,560✔
348
}
349

350
bool _sirfile_update(sirfile* sf, const sir_update_config_data* data) {
36,209✔
351
    if (!_sirfile_validate(sf))
36,209✔
352
        return false;
×
353

354
    if (_sir_bittest(data->fields, SIRU_LEVELS)) {
36,209✔
355
        if (sf->levels != *data->levels) {
200✔
356
            _sir_selflog("updating file (id: %"PRIx32") levels from %04"PRIx16
170✔
357
                         " to %04"PRIx16, sf->id, sf->levels, *data->levels);
358
            sf->levels = *data->levels;
181✔
359
        } else {
360
            _sir_selflog("skipped superfluous update of file (id: %"PRIx32")"
19✔
361
                         " levels: %04"PRIx16, sf->id, sf->levels);
362
        }
363

364
        return true;
200✔
365
    }
366

367
    if (_sir_bittest(data->fields, SIRU_OPTIONS)) {
36,009✔
368
        if (sf->opts != *data->opts) {
36,009✔
369
            _sir_selflog("updating file (id: %"PRIx32") options from %08"PRIx32
17,112✔
370
                         " to %08"PRIx32, sf->id, sf->opts, *data->opts);
371
            sf->opts = *data->opts;
18,132✔
372
        } else {
373
            _sir_selflog("skipped superfluous update of file (id: %"PRIx32")"
16,932✔
374
                         " options: %08"PRIx32, sf->id, sf->opts);
375
        }
376

377
        return true;
36,009✔
378
    }
379

380
    return false;
×
381
}
382

383
sirfileid _sir_fcache_add(sirfcache* sfc, const char* path, sir_levels levels,
36,968✔
384
    sir_options opts) {
385
    if (!_sir_validptr(sfc) || !_sir_validstr(path) || !_sir_validlevels(levels) ||
43,105✔
386
        !_sir_validopts(opts))
36,945✔
387
        return 0U;
23✔
388

389
    if (sfc->count >= SIR_MAXFILES)
36,945✔
390
        return _sir_seterror(_SIR_E_NOROOM);
19✔
391

392
    const sirfile* existing = _sir_fcache_find(sfc, (const void*)path, _sir_fcache_pred_path);
36,926✔
393
    if (NULL != existing) {
36,926✔
394
        _sir_selflog("error: already have file (path: '%s', id: %"PRIx32")",
54✔
395
            path, existing->id);
396
        return _sir_seterror(_SIR_E_DUPITEM);
57✔
397
    }
398

399
    sirfile* sf = _sirfile_create(path, levels, opts);
36,869✔
400
    if (_sirfile_validate(sf)) {
36,869✔
401
        _sir_selflog("adding file (path: '%s', id: %"PRIx32"); count = %zu", //-V522
36,732✔
402
            sf->path, sf->id, sfc->count + 1);
403

404
        sfc->files[sfc->count++] = sf;
36,732✔
405

406
        if (!_sir_bittest(sf->opts, SIRO_NOHDR))
36,732✔
407
            _sirfile_writeheader(sf, SIR_FHBEGIN);
36,676✔
408

409
        return sf->id;
36,732✔
410
    }
411

412
    _sir_safefree(&sf);
137✔
413

414
    return 0U;
137✔
415
}
416

417
bool _sir_fcache_update(const sirfcache* sfc, sirfileid id, const sir_update_config_data* data) {
36,209✔
418
    if (!_sir_validptr(sfc) || !_sir_validfileid(id) || !_sir_validupdatedata(data))
36,209✔
419
        return false;
×
420

421
    sirfile* found = _sir_fcache_find(sfc, (const void*)&id, _sir_fcache_pred_id);
36,209✔
422
    return found ? _sirfile_update(found, data) : _sir_seterror(_SIR_E_NOITEM);
36,209✔
423
}
424

425
bool _sir_fcache_rem(sirfcache* sfc, sirfileid id) {
36,716✔
426
    if (!_sir_validptr(sfc) || !_sir_validfileid(id))
36,716✔
427
        return false;
×
428

429
    for (size_t n = 0; n < sfc->count; n++) {
80,891✔
430
        SIR_ASSERT(_sirfile_validate(sfc->files[n]));
76,193✔
431

432
        if (sfc->files[n]->id == id) {
80,869✔
433
            _sir_selflog("removing file (path: '%s', id: %"PRIx32"); count = %zu",
34,622✔
434
                sfc->files[n]->path, sfc->files[n]->id, sfc->count - 1);
435

436
            _sirfile_destroy(&sfc->files[n]);
36,694✔
437

438
            for (size_t i = n; i < sfc->count - 1; i++) {
100,445✔
439
                sfc->files[i] = sfc->files[i + 1];
63,751✔
440
                sfc->files[i + 1] = NULL;
63,751✔
441
            }
442

443
            sfc->count--;
36,694✔
444
            return true;
36,694✔
445
        }
446
    }
447

448
    return _sir_seterror(_SIR_E_NOITEM);
22✔
449
}
450

451
bool _sir_fcache_pred_path(const void* match, const sirfile* iter) {
108,021✔
452
    const char* path = (const char*)match;
89,845✔
453
    bool equal       = false;
89,845✔
454

455
    _sir_selflog("comparing '%s' == '%s'", path, iter->path);
101,911✔
456

457
#if !defined(__WIN__)
458
    /* if we're able to stat both files then we can use that information for the
459
     * comparison. otherwise, fall back on comparing the canonical path strings
460
     * returned by realpath. */
461
    char resolved1[SIR_MAXPATH] = {0};
108,021✔
462
    char resolved2[SIR_MAXPATH] = {0};
108,021✔
463
    struct stat st1             = {0};
108,021✔
464
    struct stat st2             = {0};
108,021✔
465

466
    const char* real1 = realpath(path, resolved1);
89,845✔
467
    const char* real2 = realpath(iter->path, resolved2);
108,021✔
468

469
    SIR_UNUSED(real1);
470
    SIR_UNUSED(real2);
471

472
    if ((!stat(resolved1, &st1) && !stat(resolved2, &st2)) ||
116,535✔
473
        (!stat(path, &st1) && !stat(iter->path, &st2))) {
8,514✔
474
        equal = st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
99,507✔
475
        _sir_selflog("returning %d for '%s' == '%s'", equal, path, iter->path);
99,507✔
476
    } else {
477
        _sir_selflog("falling back to canonical path string compare");
8,385✔
478
        equal = 0 == strncmp(resolved1, resolved2, SIR_MAXPATH);
8,514✔
479
        _sir_selflog("returning %d for '%s' == '%s'", equal, resolved1, resolved2);
8,385✔
480
    }
481

482
    return equal;
108,021✔
483
#else /* __WIN__ */
484
    /* open both files (only if they already exist) and compare their
485
     * filesystem info. failing that, fall back on conversion to canonical path
486
     * and string comparison. */
487
    DWORD sh_flags   = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
488
    DWORD open_type  = OPEN_EXISTING;
489
    DWORD attr_flags = FILE_ATTRIBUTE_NORMAL;
490
    BY_HANDLE_FILE_INFORMATION fi1 = {0};
491
    BY_HANDLE_FILE_INFORMATION fi2 = {0};
492

493
    HANDLE h1 = CreateFileA(path, 0, sh_flags, NULL, open_type, attr_flags, NULL);
494
    HANDLE h2 = CreateFileA(iter->path,0, sh_flags, NULL, open_type, attr_flags, NULL);
495

496
    if (INVALID_HANDLE_VALUE != h1 && INVALID_HANDLE_VALUE != h2 &&
497
        GetFileInformationByHandle(h1, &fi1) && GetFileInformationByHandle(h2, &fi2)) {
498
        equal = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
499
                fi1.nFileIndexLow        == fi2.nFileIndexLow        &&
500
                fi1.nFileIndexHigh       == fi2.nFileIndexHigh;
501
        _sir_selflog("returning %d for '%s' == '%s'", equal, path, iter->path);
502
    } else {
503
        _sir_selflog("falling back to canonical path string compare");
504
        char resolved1[SIR_MAXPATH] = {0}, resolved2[SIR_MAXPATH] = {0};
505
        if (GetFullPathNameA(path, SIR_MAXPATH, resolved1, NULL) &&
506
            GetFullPathNameA(iter->path, SIR_MAXPATH, resolved2, NULL))
507
            equal = 0 == StrCmpIA(resolved1, resolved2);
508
        _sir_selflog("returning %d for '%s' == '%s'", equal, resolved1, resolved2);
509
    }
510

511
    if (INVALID_HANDLE_VALUE != h1)
512
        CloseHandle(h1);
513

514
    if (INVALID_HANDLE_VALUE != h2)
515
        CloseHandle(h2);
516

517
    return equal;
518
#endif
519
}
520

521
bool _sir_fcache_pred_id(const void* match, const sirfile* iter) {
77,086✔
522
    const sirfileid* id = (const sirfileid*)match;
64,091✔
523
    return iter->id == *id;
77,086✔
524
}
525

526
sirfile* _sir_fcache_find(const sirfcache* sfc, const void* match, sir_fcache_pred pred) {
73,135✔
527
    if (!_sir_validptr(sfc) || !_sir_validptr(match) || !_sir_validfnptr(pred))
73,135✔
528
        return NULL;
×
529

530
    for (size_t n = 0; n < sfc->count; n++) {
221,976✔
531
        if (pred(match, sfc->files[n]))
185,107✔
532
            return sfc->files[n];
36,266✔
533
    }
534

535
    return NULL;
30,744✔
536
}
537

538
bool _sir_fcache_destroy(sirfcache* sfc) {
788✔
539
    if (!_sir_validptr(sfc))
788✔
540
        return false;
×
541

542
    while (sfc->count > 0) {
826✔
543
        size_t idx = sfc->count - 1;
38✔
544
        SIR_ASSERT(_sirfile_validate(sfc->files[idx]));
36✔
545
        _sirfile_destroy(&sfc->files[idx]);
38✔
546
        sfc->files[idx] = NULL;
38✔
547
        sfc->count--;
38✔
548
    }
549

550
    memset(sfc, 0, sizeof(sirfcache));
680✔
551
    return true;
788✔
552
}
553

554
bool _sir_fcache_dispatch(const sirfcache* sfc, sir_level level, sirbuf* buf,
2,126,134✔
555
    size_t* dispatched, size_t* wanted) {
556
    if (!_sir_validptr(sfc) || !_sir_validlevel(level) || !_sir_validptr(buf) ||
2,145,673✔
557
        !_sir_validptr(dispatched) || !_sir_validptr(wanted))
2,145,673✔
558
        return false;
×
559

560
    const char* write    = NULL;
2,106,595✔
561
    sir_options lastopts = 0U;
2,106,595✔
562

563
    *dispatched = 0;
2,126,134✔
564
    *wanted     = 0;
2,126,134✔
565

566
    for (size_t n = 0; n < sfc->count; n++) {
3,416,058✔
567
        SIR_ASSERT(_sirfile_validate(sfc->files[n]));
1,273,861✔
568

569
        if (!_sir_bittest(sfc->files[n]->levels, level)) {
1,289,924✔
570
            _sir_selflog("level %04"PRIx16" not set in level mask (%04"PRIx16
2,181✔
571
                         ") for file (path: '%s', id: %"PRIx32"); skipping",
572
                         level, sfc->files[n]->levels, sfc->files[n]->path,
573
                         sfc->files[n]->id);
574
            continue;
2,308✔
575
        }
576

577
        (*wanted)++;
1,287,616✔
578

579
        if (!write || sfc->files[n]->opts != lastopts) {
1,287,616✔
580
            write = _sir_format(false, sfc->files[n]->opts, buf);
1,146,247✔
581
            SIR_ASSERT(write);
1,137,805✔
582
            lastopts = sfc->files[n]->opts;
1,146,247✔
583
        }
584

585
        if (write && _sirfile_write(sfc->files[n], write)) {
1,287,616✔
586
            (*dispatched)++;
1,287,616✔
587
        } else {
588
            _sir_selflog("error: write to file (path: '%s', id: %"PRIx32") failed!",
×
589
                sfc->files[n]->path, sfc->files[n]->id);
590
        }
591
    }
592

593
    return (*dispatched == *wanted);
2,126,134✔
594
}
595

596
void _sir_fflush(FILE* f) {
79,322✔
597
    if (_sir_validptr(f) && 0 != fflush(f))
79,322✔
598
        (void)_sir_handleerr(errno);
×
599
}
79,322✔
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