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

jasonish / suricata / 23019292042

12 Mar 2026 07:08PM UTC coverage: 79.245% (-0.004%) from 79.249%
23019292042

push

github

jasonish
github-ci: add schema ordering check for yaml schema

266163 of 335873 relevant lines covered (79.25%)

4877167.7 hits per line

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

87.04
/src/util-file.c
1
/* Copyright (C) 2007-2020 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
/**
19
 * \file
20
 *
21
 * \author Victor Julien <victor@inliniac.net>
22
 * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
23
 *
24
 */
25

26
#include "suricata-common.h"
27
#include "suricata.h"
28
#include "flow.h"
29
#include "stream.h"
30
#include "stream-tcp.h"
31
#include "runmodes.h"
32
#include "util-hash.h"
33
#include "util-debug.h"
34
#include "util-memcmp.h"
35
#include "util-print.h"
36
#include "app-layer-parser.h"
37
#include "util-validate.h"
38
#include "rust.h"
39

40
extern int g_detect_disabled;
41

42
/** \brief mask of file flags we'll not set
43
 *  This mask is set based on global file settings and
44
 *  cannot be overridden by detection.
45
 */
46
static uint16_t g_file_flow_mask = 0;
47

48
/** \brief switch to force filestore on all files
49
 *         regardless of the rules.
50
 */
51
static int g_file_force_filestore = 0;
52

53
/** \brief switch to force magic checks on all files
54
 *         regardless of the rules.
55
 */
56
static int g_file_force_magic = 0;
57

58
/** \brief switch to force md5 calculation on all files
59
 *         regardless of the rules.
60
 */
61
static int g_file_force_md5 = 0;
62

63
/** \brief switch to force sha1 calculation on all files
64
 *         regardless of the rules.
65
 */
66
static int g_file_force_sha1 = 0;
67

68
/** \brief switch to force sha256 calculation on all files
69
 *         regardless of the rules.
70
 */
71
static int g_file_force_sha256 = 0;
72

73
/** \brief switch to force tracking off all files
74
 *         regardless of the rules.
75
 */
76
static int g_file_force_tracking = 0;
77

78
/** \brief switch to use g_file_store_reassembly_depth
79
 *         to reassembly files
80
 */
81
static int g_file_store_enable = 0;
82

83
/** \brief stream_config.reassembly_depth equivalent
84
 *         for files
85
 */
86
static uint32_t g_file_store_reassembly_depth = 0;
87

88
/* prototypes */
89
static void FileFree(File *, const StreamingBufferConfig *cfg);
90
static void FileEndSha256(File *ff);
91

92
void FileForceFilestoreEnable(void)
93
{
28✔
94
    g_file_force_filestore = 1;
28✔
95
    g_file_flow_mask |= (FLOWFILE_NO_STORE_TS|FLOWFILE_NO_STORE_TC);
28✔
96
}
28✔
97

98
void FileForceMagicEnable(void)
99
{
2✔
100
    g_file_force_magic = 1;
2✔
101
    g_file_flow_mask |= (FLOWFILE_NO_MAGIC_TS|FLOWFILE_NO_MAGIC_TC);
2✔
102
}
2✔
103

104
void FileForceMd5Enable(void)
105
{
11✔
106
    g_file_force_md5 = 1;
11✔
107
    g_file_flow_mask |= (FLOWFILE_NO_MD5_TS|FLOWFILE_NO_MD5_TC);
11✔
108
}
11✔
109

110
void FileForceSha1Enable(void)
111
{
3✔
112
    g_file_force_sha1 = 1;
3✔
113
    g_file_flow_mask |= (FLOWFILE_NO_SHA1_TS|FLOWFILE_NO_SHA1_TC);
3✔
114
}
3✔
115

116
void FileForceSha256Enable(void)
117
{
53✔
118
    g_file_force_sha256 = 1;
53✔
119
    g_file_flow_mask |= (FLOWFILE_NO_SHA256_TS|FLOWFILE_NO_SHA256_TC);
53✔
120
}
53✔
121

122
int FileForceFilestore(void)
123
{
×
124
    return g_file_force_filestore;
×
125
}
×
126

127
void FileReassemblyDepthEnable(uint32_t size)
128
{
2✔
129
    g_file_store_enable = 1;
2✔
130
    g_file_store_reassembly_depth = size;
2✔
131
}
2✔
132

133
uint32_t FileReassemblyDepth(void)
134
{
69,002✔
135
    if (g_file_store_enable == 1)
69,002✔
136
        return g_file_store_reassembly_depth;
101✔
137
    else
68,901✔
138
        return stream_config.reassembly_depth;
68,901✔
139
}
69,002✔
140

141
int FileForceMagic(void)
142
{
123,534✔
143
    return g_file_force_magic;
123,534✔
144
}
123,534✔
145

146
int FileForceMd5(void)
147
{
×
148
    return g_file_force_md5;
×
149
}
×
150

151
int FileForceSha1(void)
152
{
×
153
    return g_file_force_sha1;
×
154
}
×
155

156
int FileForceSha256(void)
157
{
×
158
    return g_file_force_sha256;
×
159
}
×
160

161
void FileForceTrackingEnable(void)
162
{
2,982✔
163
    g_file_force_tracking = 1;
2,982✔
164
}
2,982✔
165

166
/**
167
 * \brief Function to parse forced file hashing configuration.
168
 */
169
void FileForceHashParseCfg(SCConfNode *conf)
170
{
2,979✔
171
    BUG_ON(conf == NULL);
2,979✔
172

173
    SCConfNode *forcehash_node = NULL;
2,979✔
174

175
    if (conf != NULL)
2,979✔
176
        forcehash_node = SCConfNodeLookupChild(conf, "force-hash");
2,979✔
177

178
    if (forcehash_node != NULL) {
2,979✔
179
        SCConfNode *field = NULL;
16✔
180

181
        TAILQ_FOREACH(field, &forcehash_node->head, next) {
22✔
182
            if (strcasecmp("md5", field->val) == 0) {
22✔
183
                if (g_disable_hashing) {
11✔
184
                    SCLogInfo("not forcing md5 calculation for logged files: hashing globally "
×
185
                              "disabled");
×
186
                } else {
11✔
187
                    FileForceMd5Enable();
11✔
188
                    SCLogConfig("forcing md5 calculation for logged or stored files");
11✔
189
                }
11✔
190
            } else if (strcasecmp("sha1", field->val) == 0) {
11✔
191
                if (g_disable_hashing) {
3✔
192
                    SCLogInfo("not forcing sha1 calculation for logged files: hashing globally "
×
193
                              "disabled");
×
194
                } else {
3✔
195
                    FileForceSha1Enable();
3✔
196
                    SCLogConfig("forcing sha1 calculation for logged or stored files");
3✔
197
                }
3✔
198
            } else if (strcasecmp("sha256", field->val) == 0) {
8✔
199
                if (g_disable_hashing) {
7✔
200
                    SCLogInfo("not forcing sha256 calculation for logged files: hashing globally "
×
201
                              "disabled");
×
202
                } else {
7✔
203
                    FileForceSha256Enable();
7✔
204
                    SCLogConfig("forcing sha256 calculation for logged or stored files");
7✔
205
                }
7✔
206
            } else {
7✔
207
                FatalError("Invalid configuration: force-hash algorithm '%s' must be one of: md5, "
1✔
208
                           "sha1, sha256",
1✔
209
                        field->val);
1✔
210
            }
1✔
211
        }
22✔
212
    }
16✔
213
}
2,979✔
214

215
uint16_t SCFileFlowFlagsToFlags(const uint16_t flow_file_flags, uint8_t direction)
216
{
773,457✔
217
    uint16_t flags = 0;
773,457✔
218

219
    if (direction == STREAM_TOSERVER) {
773,457✔
220
        if ((flow_file_flags & (FLOWFILE_NO_STORE_TS | FLOWFILE_STORE_TS)) ==
522,169✔
221
                FLOWFILE_NO_STORE_TS) {
522,169✔
222
            flags |= FILE_NOSTORE;
190,068✔
223
        } else if (flow_file_flags & FLOWFILE_STORE_TS) {
519,471✔
224
            flags |= FILE_STORE;
×
225
        }
×
226

227
        if (flow_file_flags & FLOWFILE_NO_MAGIC_TS) {
522,169✔
228
            flags |= FILE_NOMAGIC;
509,411✔
229
        }
509,411✔
230

231
        if (flow_file_flags & FLOWFILE_NO_MD5_TS) {
522,169✔
232
            flags |= FILE_NOMD5;
520,286✔
233
        }
520,286✔
234

235
        if (flow_file_flags & FLOWFILE_NO_SHA1_TS) {
522,169✔
236
            flags |= FILE_NOSHA1;
520,303✔
237
        }
520,303✔
238

239
        if (flow_file_flags & FLOWFILE_NO_SHA256_TS) {
522,169✔
240
            flags |= FILE_NOSHA256;
187,032✔
241
        }
187,032✔
242
    } else {
522,254✔
243
        if ((flow_file_flags & (FLOWFILE_NO_STORE_TC | FLOWFILE_STORE_TC)) ==
251,288✔
244
                FLOWFILE_NO_STORE_TC) {
251,288✔
245
            flags |= FILE_NOSTORE;
22,902✔
246
        } else if (flow_file_flags & FLOWFILE_STORE_TC) {
247,604✔
247
            flags |= FILE_STORE;
×
248
        }
×
249

250
        if (flow_file_flags & FLOWFILE_NO_MAGIC_TC) {
251,288✔
251
            flags |= FILE_NOMAGIC;
145,455✔
252
        }
145,455✔
253

254
        if (flow_file_flags & FLOWFILE_NO_MD5_TC) {
251,288✔
255
            flags |= FILE_NOMD5;
247,024✔
256
        }
247,024✔
257

258
        if (flow_file_flags & FLOWFILE_NO_SHA1_TC) {
251,288✔
259
            flags |= FILE_NOSHA1;
247,481✔
260
        }
247,481✔
261

262
        if (flow_file_flags & FLOWFILE_NO_SHA256_TC) {
251,288✔
263
            flags |= FILE_NOSHA256;
22,866✔
264
        }
22,866✔
265
    }
251,288✔
266
    DEBUG_VALIDATE_BUG_ON((flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE));
773,457✔
267

268
    SCLogDebug("direction %02x flags %02x", direction, flags);
773,457✔
269
    return flags;
773,457✔
270
}
773,457✔
271

272
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
273
{
450,904✔
274
    return SCFileFlowFlagsToFlags(flow->file_flags, direction);
450,904✔
275
}
450,904✔
276

277
void FileApplyTxFlags(const AppLayerTxData *txd, const uint8_t direction, File *file)
278
{
226,422✔
279
    SCLogDebug("file flags %04x STORE %s NOSTORE %s", file->flags,
226,422✔
280
            (file->flags & FILE_STORE) ? "true" : "false",
226,422✔
281
            (file->flags & FILE_NOSTORE) ? "true" : "false");
226,422✔
282
    uint16_t update_flags = SCFileFlowFlagsToFlags(txd->file_flags, direction);
226,422✔
283
    DEBUG_VALIDATE_BUG_ON(
226,422✔
284
            (file->flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE));
226,422✔
285
    if (file->flags & FILE_STORE)
226,422✔
286
        update_flags &= ~FILE_NOSTORE;
207,949✔
287

288
    file->flags |= update_flags;
226,422✔
289
    SCLogDebug("file flags %04x STORE %s NOSTORE %s", file->flags,
226,422✔
290
            (file->flags & FILE_STORE) ? "true" : "false",
226,422✔
291
            (file->flags & FILE_NOSTORE) ? "true" : "false");
226,422✔
292
    DEBUG_VALIDATE_BUG_ON(
226,422✔
293
            (file->flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE));
226,422✔
294
}
226,422✔
295

296
static int FileMagicSize(void)
297
{
20,219✔
298
    /** \todo make this size configurable */
299
    return 512;
20,219✔
300
}
20,219✔
301

302
/**
303
 *  \brief get the size of the file data
304
 *
305
 *  This doesn't reflect how much of the file we have in memory, just the
306
 *  total size of filedata so far.
307
 */
308
uint64_t FileDataSize(const File *file)
309
{
329,080✔
310
    if (file != NULL && file->sb != NULL) {
329,081✔
311
        const uint64_t size = StreamingBufferGetConsecutiveDataRightEdge(file->sb);
329,080✔
312
        SCLogDebug("returning %" PRIu64, size);
329,080✔
313
        return size;
329,080✔
314
    }
329,080✔
315
    SCLogDebug("returning 0 (default)");
×
316
    return 0;
×
317
}
329,080✔
318

319
/**
320
 *  \brief get the size of the file
321
 *
322
 *  This doesn't reflect how much of the file we have in memory, just the
323
 *  total size of file so far.
324
 */
325
uint64_t FileTrackedSize(const File *file)
326
{
23,412✔
327
    if (file != NULL) {
23,412✔
328
        return file->size;
23,412✔
329
    }
23,412✔
330
    return 0;
×
331
}
23,412✔
332

333
/** \brief test if file is ready to be pruned
334
 *
335
 *  If a file is in the 'CLOSED' state, it means it has been processed
336
 *  completely by the pipeline in the correct direction. So we can
337
 *  prune it then.
338
 *
339
 *  For other states, as well as for files we may not need to track
340
 *  until the close state, more specific checks are done.
341
 *
342
 *  Also does house keeping within the file: move streaming buffer
343
 *  forward if possible.
344
 *
345
 *  \retval 1 prune (free) this file
346
 *  \retval 0 file not ready to be freed
347
 */
348
static int FilePruneFile(File *file, const StreamingBufferConfig *cfg)
349
{
121,729✔
350
    SCEnter();
121,729✔
351

352
    /* file is done when state is closed+, logging/storing is done (if any) */
353
    SCLogDebug("file->state %d. Is >= FILE_STATE_CLOSED: %s",
121,729✔
354
            file->state, (file->state >= FILE_STATE_CLOSED) ? "yes" : "no");
121,729✔
355
    if (file->state >= FILE_STATE_CLOSED) {
121,729✔
356
        SCReturnInt(1);
19,503✔
357
    }
19,503✔
358

359
#ifdef HAVE_MAGIC
102,226✔
360
    if (!(file->flags & FILE_NOMAGIC)) {
102,226✔
361
        /* need magic but haven't set it yet, bail out */
362
        if (file->magic == NULL)
47,885✔
363
            SCReturnInt(0);
10,982✔
364
        else
36,903✔
365
            SCLogDebug("file->magic %s", file->magic);
36,903✔
366
    } else {
61,744✔
367
        SCLogDebug("file->flags & FILE_NOMAGIC == true");
54,341✔
368
    }
54,341✔
369
#endif
91,244✔
370
    uint64_t left_edge = FileDataSize(file);
91,244✔
371
    if (file->flags & FILE_STORE) {
91,244✔
372
        left_edge = MIN(left_edge,file->content_stored);
77,573✔
373
    }
77,573✔
374

375
    if (!g_detect_disabled) {
91,247✔
376
        left_edge = MIN(left_edge, file->content_inspected);
89,631✔
377
        /* if file has inspect window and min size set, we
378
         * do some house keeping here */
379
        if (file->inspect_window != 0 && file->inspect_min_size != 0) {
89,631✔
380
            const uint64_t file_offset = StreamingBufferGetOffset(file->sb);
89,630✔
381
            uint32_t window = file->inspect_window;
89,630✔
382
            if (file_offset == 0)
89,630✔
383
                window = MAX(window, file->inspect_min_size);
82,053✔
384

385
            uint64_t file_size = FileDataSize(file);
89,630✔
386
            uint64_t data_size = file_size - file_offset;
89,630✔
387

388
            SCLogDebug("window %"PRIu32", file_size %"PRIu64", data_size %"PRIu64,
89,630✔
389
                    window, file_size, data_size);
89,630✔
390

391
            if (data_size > (window * 3)) {
89,630✔
392
                file->content_inspected = MAX(file->content_inspected, file->size - window);
4,098✔
393
                SCLogDebug("file->content_inspected now %" PRIu64, file->content_inspected);
4,098✔
394
            }
4,098✔
395

396
            if (left_edge > window)
89,630✔
397
                left_edge -= window;
7,910✔
398
            else
81,720✔
399
                left_edge = 0;
81,720✔
400
        }
89,630✔
401
    }
89,631✔
402

403
    if (left_edge) {
91,244✔
404
        SCLogDebug("sliding to %" PRIu64, left_edge);
9,523✔
405
        StreamingBufferSlideToOffset(file->sb, cfg, left_edge);
9,523✔
406
    }
9,523✔
407

408
    SCReturnInt(0);
91,244✔
409
}
102,226✔
410

411
#ifdef DEBUG
412
#define P(file, flag) ((file)->flags & (flag)) ? "true" : "false"
413
void FilePrintFlags(const File *file)
414
{
415
    SCLogDebug("file %p flags %04x "
416
               "FILE_TRUNCATED %s "
417
               "FILE_NOMAGIC %s "
418
               "FILE_NOMD5 %s "
419
               "FILE_MD5 %s "
420
               "FILE_NOSHA1 %s "
421
               "FILE_SHA1 %s "
422
               "FILE_NOSHA256 %s "
423
               "FILE_SHA256 %s "
424
               "FILE_LOGGED %s "
425
               "FILE_NOSTORE %s "
426
               "FILE_STORE %s "
427
               "FILE_STORED %s "
428
               "FILE_NOTRACK %s "
429
               "FILE_HAS_GAPS %s",
430
            file, file->flags, P(file, FILE_TRUNCATED), P(file, FILE_NOMAGIC), P(file, FILE_NOMD5),
431
            P(file, FILE_MD5), P(file, FILE_NOSHA1), P(file, FILE_SHA1), P(file, FILE_NOSHA256),
432
            P(file, FILE_SHA256), P(file, FILE_LOGGED), P(file, FILE_NOSTORE), P(file, FILE_STORE),
433
            P(file, FILE_STORED), P(file, FILE_NOTRACK), P(file, FILE_HAS_GAPS));
434
}
435
#undef P
436
#endif
437

438
static void FilePrune(FileContainer *ffc, const StreamingBufferConfig *cfg)
439
{
264,816✔
440
    SCEnter();
264,816✔
441
    SCLogDebug("ffc %p head %p", ffc, ffc->head);
264,816✔
442
    File *file = ffc->head;
264,816✔
443
    File *prev = NULL;
264,816✔
444

445
    while (file) {
386,546✔
446
#ifdef DEBUG
447
        FilePrintFlags(file);
448
#endif
449
        if (FilePruneFile(file, cfg) == 0) {
121,730✔
450
            prev = file;
102,228✔
451
            file = file->next;
102,228✔
452
            continue;
102,228✔
453
        }
102,228✔
454

455
        SCLogDebug("removing file %p", file);
19,502✔
456

457
        File *file_next = file->next;
19,502✔
458

459
        if (prev)
19,502✔
460
            prev->next = file_next;
×
461
        /* update head and tail */
462
        if (file == ffc->head)
19,502✔
463
            ffc->head = file_next;
19,503✔
464
        if (file == ffc->tail)
19,502✔
465
            ffc->tail = prev;
19,480✔
466

467
        FileFree(file, cfg);
19,502✔
468
        file = file_next;
19,502✔
469
    }
19,502✔
470
    SCReturn;
264,816✔
471
}
264,816✔
472

473
/**
474
 *  \brief allocate a FileContainer
475
 *
476
 *  \retval new newly allocated FileContainer
477
 *  \retval NULL error
478
 */
479
FileContainer *FileContainerAlloc(void)
480
{
5,324✔
481
    FileContainer *new = SCCalloc(1, sizeof(FileContainer));
5,324✔
482
    if (unlikely(new == NULL)) {
5,324✔
483
        SCLogError("Error allocating mem");
×
484
        return NULL;
×
485
    }
×
486
    new->head = new->tail = NULL;
5,324✔
487
    return new;
5,324✔
488
}
5,324✔
489

490
/**
491
 *  \brief Recycle a FileContainer
492
 *
493
 *  \param ffc FileContainer
494
 */
495
void FileContainerRecycle(FileContainer *ffc, const StreamingBufferConfig *cfg)
496
{
106,364✔
497
    SCLogDebug("ffc %p", ffc);
106,364✔
498
    if (ffc == NULL)
106,364✔
499
        return;
×
500

501
    File *cur = ffc->head;
106,364✔
502
    File *next = NULL;
106,364✔
503
    for (;cur != NULL; cur = next) {
110,049✔
504
        next = cur->next;
3,685✔
505
        FileFree(cur, cfg);
3,685✔
506
    }
3,685✔
507
    ffc->head = ffc->tail = NULL;
106,364✔
508
}
106,364✔
509

510
/**
511
 *  \brief Free a FileContainer
512
 *
513
 *  \param ffc FileContainer
514
 */
515
void FileContainerFree(FileContainer *ffc, const StreamingBufferConfig *cfg)
516
{
3,432,279✔
517
    SCLogDebug("ffc %p", ffc);
3,432,279✔
518
    if (ffc == NULL)
3,432,279✔
519
        return;
3,426,982✔
520

521
    File *ptr = ffc->head;
5,297✔
522
    File *next = NULL;
5,297✔
523
    for (;ptr != NULL; ptr = next) {
5,347✔
524
        next = ptr->next;
50✔
525
        FileFree(ptr, cfg);
50✔
526
    }
50✔
527
    ffc->head = ffc->tail = NULL;
5,297✔
528
    SCFree(ffc);
5,297✔
529
}
5,297✔
530

531
/**
532
 *  \brief Alloc a new File
533
 *
534
 *  \param name character array containing the name (not a string)
535
 *  \param name_len length in bytes of the name
536
 *
537
 *  \retval new File object or NULL on error
538
 */
539
static File *FileAlloc(const uint8_t *name, uint16_t name_len)
540
{
23,264✔
541
    File *new = SCCalloc(1, sizeof(File));
23,264✔
542
    if (unlikely(new == NULL)) {
23,264✔
543
        SCLogError("Error allocating mem");
×
544
        return NULL;
×
545
    }
×
546

547
    new->name = SCMalloc(name_len);
23,264✔
548
    if (new->name == NULL) {
23,264✔
549
        SCFree(new);
×
550
        return NULL;
×
551
    }
×
552

553
    new->name_len = name_len;
23,264✔
554
    memcpy(new->name, name, name_len);
23,264✔
555

556
    new->sid_cnt = 0;
23,264✔
557
    new->sid_max = 8;
23,264✔
558
    /* SCMalloc() is allowed to fail here because sid well be checked later on */
559
    new->sid = SCMalloc(sizeof(uint32_t) * new->sid_max);
23,264✔
560
    if (new->sid == NULL)
23,264✔
561
        new->sid_max = 0;
×
562

563
    return new;
23,264✔
564
}
23,264✔
565

566
static void FileFree(File *ff, const StreamingBufferConfig *sbcfg)
567
{
23,238✔
568
    SCLogDebug("ff %p", ff);
23,238✔
569
    if (ff == NULL)
23,238✔
570
        return;
×
571

572
    if (ff->name != NULL)
23,238✔
573
        SCFree(ff->name);
23,238✔
574
    if (ff->sid != NULL)
23,238✔
575
        SCFree(ff->sid);
23,238✔
576
#ifdef HAVE_MAGIC
23,238✔
577
    /* magic returned by libmagic is strdup'd by MagicLookup. */
578
    if (ff->magic != NULL)
23,238✔
579
        SCFree(ff->magic);
2,379✔
580
#endif
23,238✔
581
    if (ff->sb != NULL) {
23,238✔
582
        StreamingBufferFree(ff->sb, sbcfg);
23,238✔
583
    }
23,238✔
584

585
    if (ff->md5_ctx)
23,238✔
586
        SCMd5Free(ff->md5_ctx);
27✔
587
    if (ff->sha1_ctx)
23,238✔
588
        SCSha1Free(ff->sha1_ctx);
27✔
589
    if (ff->sha256_ctx)
23,238✔
590
        SCSha256Free(ff->sha256_ctx);
1,450✔
591
    SCFree(ff);
23,238✔
592
}
23,238✔
593

594
void FileContainerAdd(FileContainer *ffc, File *ff)
595
{
23,275✔
596
    SCLogDebug("ffc %p ff %p", ffc, ff);
23,275✔
597
    if (ffc->head == NULL || ffc->tail == NULL) {
23,275✔
598
        ffc->head = ffc->tail = ff;
23,244✔
599
    } else {
23,244✔
600
        ffc->tail->next = ff;
31✔
601
        ffc->tail = ff;
31✔
602
    }
31✔
603
}
23,275✔
604

605
/**
606
 *  \brief Tag a file for storing
607
 *
608
 *  \param ff The file to store
609
 */
610
int FileStore(File *ff)
611
{
18,604✔
612
    SCLogDebug("ff %p", ff);
18,604✔
613
    ff->flags |= FILE_STORE;
18,604✔
614
    SCReturnInt(0);
18,604✔
615
}
18,604✔
616

617
/**
618
 *  \brief check if we have stored enough
619
 *
620
 *  \param ff file
621
 *
622
 *  \retval 0 limit not reached yet
623
 *  \retval 1 limit reached
624
 */
625
static int FileStoreNoStoreCheck(File *ff)
626
{
22,181✔
627
    SCEnter();
22,181✔
628

629
    if (ff == NULL) {
22,181✔
630
        SCReturnInt(0);
×
631
    }
×
632

633
    if (ff->flags & FILE_NOSTORE) {
22,181✔
634
        if (ff->state == FILE_STATE_OPENED &&
20,219✔
635
            FileDataSize(ff) >= (uint64_t)FileMagicSize())
20,219✔
636
        {
19,706✔
637
            SCReturnInt(1);
19,706✔
638
        }
19,706✔
639
    }
20,219✔
640

641
    SCReturnInt(0);
22,181✔
642
}
22,181✔
643

644
static int AppendData(
645
        const StreamingBufferConfig *sbcfg, File *file, const uint8_t *data, uint32_t data_len)
646
{
473,455✔
647
    DEBUG_VALIDATE_BUG_ON(
473,455✔
648
            data_len > BIT_U32(26)); // 64MiB as a limit per chunk seems already excessive
473,455✔
649

650
    SCLogDebug("file %p data_len %u", file, data_len);
473,455✔
651
    if (StreamingBufferAppendNoTrack(file->sb, sbcfg, data, data_len) != 0) {
473,455✔
652
        SCLogDebug("file %p StreamingBufferAppendNoTrack failed", file);
×
653
        SCReturnInt(-1);
×
654
    }
×
655

656
    if (file->md5_ctx) {
473,455✔
657
        SCMd5Update(file->md5_ctx, data, data_len);
1,787✔
658
    }
1,787✔
659
    if (file->sha1_ctx) {
473,455✔
660
        SCSha1Update(file->sha1_ctx, data, data_len);
1,764✔
661
    }
1,764✔
662
    if (file->sha256_ctx) {
473,455✔
663
        SCLogDebug("SHA256 file %p data %p data_len %u", file, data, data_len);
292,617✔
664
        SCSha256Update(file->sha256_ctx, data, data_len);
292,617✔
665
    } else {
469,433✔
666
        SCLogDebug("NO SHA256 file %p data %p data_len %u", file, data, data_len);
180,838✔
667
    }
180,838✔
668
    SCReturnInt(0);
473,455✔
669
}
473,455✔
670

671
/** \internal
672
 *  \brief Flags a file as having gaps
673
 *
674
 *  \param ff the file
675
 */
676
static void FileFlagGap(File *ff) {
450✔
677
    ff->flags |= FILE_HAS_GAPS;
450✔
678
    ff->flags |= (FILE_NOMD5|FILE_NOSHA1|FILE_NOSHA256);
450✔
679
    ff->flags &= ~(FILE_MD5|FILE_SHA1|FILE_SHA256);
450✔
680
}
450✔
681

682
/** \internal
683
 *  \brief Store/handle a chunk of file data in the File structure
684
 *
685
 *  \param ff the file
686
 *  \param data data chunk
687
 *  \param data_len data chunk len
688
 *
689
 *  \retval  0 ok
690
 *  \retval -1 error
691
 *  \retval -2 no store for this file
692
 */
693
static int FileAppendDataDo(
694
        const StreamingBufferConfig *sbcfg, File *ff, const uint8_t *data, uint32_t data_len)
695
{
481,209✔
696
    SCEnter();
481,209✔
697
#ifdef DEBUG_VALIDATION
698
    BUG_ON(ff == NULL);
699
#endif
700

701
    ff->size += data_len;
481,209✔
702
    if (data == NULL) {
481,209✔
703
        FileFlagGap(ff);
308✔
704
        SCReturnInt(0);
308✔
705
    }
308✔
706

707
    if (ff->state != FILE_STATE_OPENED) {
480,901✔
708
        if (ff->flags & FILE_NOSTORE) {
×
709
            SCReturnInt(-2);
×
710
        }
×
711
        SCReturnInt(-1);
×
712
    }
×
713

714
    if (g_detect_disabled && FileStoreNoStoreCheck(ff) == 1) {
480,901✔
715
        int hash_done = 0;
19,706✔
716
        /* no storage but forced hashing */
717
        if (ff->md5_ctx) {
19,706✔
718
            SCMd5Update(ff->md5_ctx, data, data_len);
×
719
            hash_done = 1;
×
720
        }
×
721
        if (ff->sha1_ctx) {
19,706✔
722
            SCSha1Update(ff->sha1_ctx, data, data_len);
×
723
            hash_done = 1;
×
724
        }
×
725
        if (ff->sha256_ctx) {
19,706✔
726
            SCLogDebug("file %p data %p data_len %u", ff, data, data_len);
2,700✔
727
            SCSha256Update(ff->sha256_ctx, data, data_len);
2,700✔
728
            hash_done = 1;
2,700✔
729
        }
2,700✔
730

731
        if (hash_done)
19,706✔
732
            SCReturnInt(0);
2,700✔
733

734
        if (g_file_force_tracking || (!(ff->flags & FILE_NOTRACK)))
17,006✔
735
            SCReturnInt(0);
17,006✔
736

737
        ff->state = FILE_STATE_TRUNCATED;
×
738
        SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED");
×
739
        SCReturnInt(-2);
×
740
    }
17,006✔
741

742
    SCLogDebug("appending %"PRIu32" bytes", data_len);
461,195✔
743

744
    int r = AppendData(sbcfg, ff, data, data_len);
461,195✔
745
    if (r != 0) {
461,195✔
746
        ff->state = FILE_STATE_ERROR;
×
747
        SCReturnInt(r);
×
748
    }
×
749

750
    SCReturnInt(0);
461,195✔
751
}
461,195✔
752

753
/**
754
 *  \brief Store/handle a chunk of file data in the File structure
755
 *         The last file in the FileContainer will be used.
756
 *
757
 *  \param ffc FileContainer used to append to
758
 *  \param data data chunk
759
 *  \param data_len data chunk len
760
 *
761
 *  \retval  0 ok
762
 *  \retval -1 error
763
 *  \retval -2 no store for this file
764
 */
765
int FileAppendData(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data,
766
        uint32_t data_len)
767
{
493,806✔
768
    SCEnter();
493,806✔
769

770
    if (ffc == NULL || ffc->tail == NULL || data_len == 0 || sbcfg == NULL) {
493,809✔
771
        SCReturnInt(-1);
33,662✔
772
    }
33,662✔
773
    int r = FileAppendDataDo(sbcfg, ffc->tail, data, data_len);
460,144✔
774
    SCReturnInt(r);
460,144✔
775
}
493,806✔
776

777
/**
778
 *  \brief Store/handle a chunk of file data in the File structure
779
 *         The file with 'track_id' in the FileContainer will be used.
780
 *
781
 *  \param ffc FileContainer used to append to
782
 *  \param track_id id to lookup the file
783
 *  \param data data chunk
784
 *  \param data_len data chunk len
785
 *
786
 *  \retval  0 ok
787
 *  \retval -1 error
788
 *  \retval -2 no store for this file
789
 */
790
int FileAppendDataById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id,
791
        const uint8_t *data, uint32_t data_len)
792
{
20,980✔
793
    SCEnter();
20,980✔
794

795
    if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) {
20,980✔
796
        SCReturnInt(-1);
×
797
    }
×
798
    File *ff = ffc->head;
20,980✔
799
    for ( ; ff != NULL; ff = ff->next) {
20,985✔
800
        if (track_id == ff->file_track_id) {
20,985✔
801
            int r = FileAppendDataDo(sbcfg, ff, data, data_len);
20,980✔
802
            SCReturnInt(r);
20,980✔
803
        }
20,980✔
804
    }
20,985✔
805
    SCReturnInt(-1);
20,980✔
806
}
20,980✔
807

808
/**
809
 *  \brief Store/handle a chunk of file data in the File structure
810
 *         The file with 'track_id' in the FileContainer will be used.
811
 *
812
 *  \param ffc FileContainer used to append to
813
 *  \param track_id id to lookup the file
814
 *  \param data data chunk
815
 *  \param data_len data chunk len
816
 *
817
 *  \retval  0 ok
818
 *  \retval -1 error
819
 *  \retval -2 no store for this file
820
 */
821
int FileAppendGAPById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id,
822
        const uint8_t *data, uint32_t data_len)
823
{
108✔
824
    SCEnter();
108✔
825

826
    if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) {
108✔
827
        SCReturnInt(-1);
19✔
828
    }
19✔
829
    File *ff = ffc->head;
89✔
830
    for ( ; ff != NULL; ff = ff->next) {
89✔
831
        if (track_id == ff->file_track_id) {
89✔
832
            FileFlagGap(ff);
89✔
833
            SCLogDebug("FILE_HAS_GAPS set");
89✔
834

835
            int r = FileAppendDataDo(sbcfg, ff, data, data_len);
89✔
836
            SCReturnInt(r);
89✔
837
        }
89✔
838
    }
89✔
839
    SCReturnInt(-1);
89✔
840
}
89✔
841

842
void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min)
843
{
35,797✔
844
    file->inspect_window = win;
35,797✔
845
    file->inspect_min_size = min;
35,797✔
846
}
35,797✔
847

848
/**
849
 *  \brief Sets the offset range for a file.
850
 *
851
 *  \param ffc the container
852
 *  \param start start offset
853
 *  \param end end offset
854
 *
855
 *  \retval  0 ok
856
 *  \retval -1 error
857
 */
858
int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end)
859
{
1,600✔
860
    SCEnter();
1,600✔
861

862
    if (ffc == NULL || ffc->tail == NULL) {
1,600✔
863
        SCReturnInt(-1);
×
864
    }
×
865
    ffc->tail->start = start;
1,600✔
866
    ffc->tail->end = end;
1,600✔
867
    SCReturnInt(0);
1,600✔
868
}
1,600✔
869

870
/**
871
 *  \brief Open a new File
872
 *
873
 *  \param ffc flow container
874
 *  \param sbcfg buffer config
875
 *  \param name filename character array
876
 *  \param name_len filename len
877
 *  \param data initial data
878
 *  \param data_len initial data len
879
 *  \param flags open flags
880
 *
881
 *  \retval ff flowfile object
882
 *
883
 *  \note filename is not a string, so it's not nul terminated.
884
 */
885
static File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg,
886
        const uint8_t *name, uint16_t name_len,
887
        const uint8_t *data, uint32_t data_len, uint16_t flags)
888
{
23,265✔
889
    SCEnter();
23,265✔
890

891
    //PrintRawDataFp(stdout, name, name_len);
892

893
    File *ff = FileAlloc(name, name_len);
23,265✔
894
    if (ff == NULL) {
23,265✔
895
        SCReturnPtr(NULL, "File");
×
896
    }
×
897

898
    ff->sb = StreamingBufferInit(sbcfg);
23,265✔
899
    if (ff->sb == NULL) {
23,265✔
900
        FileFree(ff, sbcfg);
×
901
        SCReturnPtr(NULL, "File");
×
902
    }
×
903
    SCLogDebug("ff->sb %p", ff->sb);
23,265✔
904

905
    if (flags & FILE_STORE || g_file_force_filestore) {
23,265✔
906
        FileStore(ff);
17,854✔
907
    } else if (flags & FILE_NOSTORE) {
23,213✔
908
        SCLogDebug("not storing this file");
5,170✔
909
        ff->flags |= FILE_NOSTORE;
5,170✔
910
    }
5,170✔
911
    if (flags & FILE_NOMAGIC) {
23,265✔
912
        SCLogDebug("not doing magic for this file");
20,303✔
913
        ff->flags |= FILE_NOMAGIC;
20,303✔
914
    }
20,303✔
915
    if (flags & FILE_NOMD5) {
23,265✔
916
        SCLogDebug("not doing md5 for this file");
22,861✔
917
        ff->flags |= FILE_NOMD5;
22,861✔
918
    }
22,861✔
919
    if (flags & FILE_NOSHA1) {
23,265✔
920
        SCLogDebug("not doing sha1 for this file");
22,883✔
921
        ff->flags |= FILE_NOSHA1;
22,883✔
922
    }
22,883✔
923
    if (flags & FILE_NOSHA256) {
23,265✔
924
        SCLogDebug("not doing sha256 for this file");
5,160✔
925
        ff->flags |= FILE_NOSHA256;
5,160✔
926
    }
5,160✔
927

928
    if (!(ff->flags & FILE_NOMD5) || g_file_force_md5) {
23,265✔
929
        ff->md5_ctx = SCMd5New();
403✔
930
    }
403✔
931
    if (!(ff->flags & FILE_NOSHA1) || g_file_force_sha1) {
23,265✔
932
        ff->sha1_ctx = SCSha1New();
382✔
933
    }
382✔
934
    if (!(ff->flags & FILE_NOSHA256) || g_file_force_sha256) {
23,265✔
935
        ff->sha256_ctx = SCSha256New();
18,103✔
936
        SCLogDebug("ff %p ff->sha256_ctx %p", ff, ff->sha256_ctx);
18,103✔
937
    }
18,103✔
938

939
    ff->state = FILE_STATE_OPENED;
23,265✔
940
    SCLogDebug("flowfile state transitioned to FILE_STATE_OPENED");
23,265✔
941

942
    ff->fd = -1;
23,265✔
943

944
    FileContainerAdd(ffc, ff);
23,265✔
945

946
    /* set default window and min inspection size */
947
    FileSetInspectSizes(ff, FILEDATA_CONTENT_INSPECT_WINDOW, FILEDATA_CONTENT_INSPECT_MIN_SIZE);
23,265✔
948

949
    ff->size += data_len;
23,265✔
950
    if (data != NULL) {
23,265✔
951
        if (AppendData(sbcfg, ff, data, data_len) != 0) {
12,193✔
952
            ff->state = FILE_STATE_ERROR;
×
953
            SCReturnPtr(NULL, "File");
×
954
        }
×
955
        SCLogDebug("file size is now %"PRIu64, FileTrackedSize(ff));
12,193✔
956
    } else if (data_len > 0) {
14,317✔
957
        FileFlagGap(ff);
53✔
958
    }
53✔
959

960
    SCReturnPtr(ff, "File");
23,265✔
961
}
23,265✔
962

963
/**
964
 *  \retval 0 ok
965
 *  \retval -1 failed */
966
int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg,
967
        uint32_t track_id, const uint8_t *name, uint16_t name_len,
968
        const uint8_t *data, uint32_t data_len, uint16_t flags)
969
{
23,265✔
970
    SCLogDebug("ffc %p track_id %u", ffc, track_id);
23,265✔
971
    File *ff = FileOpenFile(ffc, sbcfg, name, name_len, data, data_len, flags);
23,265✔
972
    if (ff == NULL)
23,265✔
973
        return -1;
×
974

975
    ff->file_track_id = track_id;
23,265✔
976
    return 0;
23,265✔
977
}
23,265✔
978

979
int FileCloseFilePtr(File *ff, const StreamingBufferConfig *sbcfg, const uint8_t *data,
980
        uint32_t data_len, uint16_t flags)
981
{
21,744✔
982
    SCEnter();
21,744✔
983

984
    if (ff == NULL) {
21,744✔
985
        SCReturnInt(-1);
×
986
    }
×
987

988
    if (ff->state != FILE_STATE_OPENED) {
21,744✔
989
        SCReturnInt(-1);
×
990
    }
×
991

992
    ff->size += data_len;
21,744✔
993
    if (data != NULL) {
21,744✔
994
        if (AppendData(sbcfg, ff, data, data_len) != 0) {
76✔
995
            ff->state = FILE_STATE_ERROR;
×
996
            SCReturnInt(-1);
×
997
        }
×
998
    }
76✔
999

1000
    if ((flags & FILE_TRUNCATED) || (ff->flags & FILE_HAS_GAPS)) {
21,744✔
1001
        SCLogDebug("flags FILE_TRUNCATED %s", (flags & FILE_TRUNCATED) ? "true" : "false");
802✔
1002
        SCLogDebug("ff->flags FILE_HAS_GAPS %s", (ff->flags & FILE_HAS_GAPS) ? "true" : "false");
802✔
1003

1004
        ff->state = FILE_STATE_TRUNCATED;
802✔
1005
        SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED");
802✔
1006

1007
        if (flags & FILE_NOSTORE) {
802✔
1008
            SCLogDebug("not storing this file");
6✔
1009
            ff->flags |= FILE_NOSTORE;
6✔
1010
        } else {
796✔
1011
            if (g_file_force_sha256 && ff->sha256_ctx) {
796✔
1012
                SCLogDebug("file %p data %p data_len %u", ff, data, data_len);
668✔
1013
                FileEndSha256(ff);
668✔
1014
            }
668✔
1015
        }
796✔
1016
    } else {
20,942✔
1017
        ff->state = FILE_STATE_CLOSED;
20,942✔
1018
        SCLogDebug("flowfile state transitioned to FILE_STATE_CLOSED");
20,942✔
1019

1020
        if (ff->md5_ctx) {
20,942✔
1021
            SCMd5Finalize(ff->md5_ctx, ff->md5, sizeof(ff->md5));
375✔
1022
            ff->md5_ctx = NULL;
375✔
1023
            ff->flags |= FILE_MD5;
375✔
1024
        }
375✔
1025
        if (ff->sha1_ctx) {
20,942✔
1026
            SCSha1Finalize(ff->sha1_ctx, ff->sha1, sizeof(ff->sha1));
354✔
1027
            ff->sha1_ctx = NULL;
354✔
1028
            ff->flags |= FILE_SHA1;
354✔
1029
        }
354✔
1030
        if (ff->sha256_ctx) {
20,942✔
1031
            SCLogDebug("file %p data %p data_len %u", ff, data, data_len);
15,958✔
1032
            FileEndSha256(ff);
15,958✔
1033
        }
15,958✔
1034
    }
20,942✔
1035

1036
    SCReturnInt(0);
21,744✔
1037
}
21,744✔
1038

1039
/**
1040
 *  \brief Close a File
1041
 *
1042
 *  \param ffc the container
1043
 *  \param data final data if any
1044
 *  \param data_len data len if any
1045
 *  \param flags flags
1046
 *
1047
 *  \retval 0 ok
1048
 *  \retval -1 error
1049
 */
1050
int FileCloseFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data,
1051
        uint32_t data_len, uint16_t flags)
1052
{
11,781✔
1053
    SCEnter();
11,781✔
1054

1055
    if (ffc == NULL || ffc->tail == NULL) {
11,781✔
1056
        SCReturnInt(-1);
×
1057
    }
×
1058

1059
    if (FileCloseFilePtr(ffc->tail, sbcfg, data, data_len, flags) == -1) {
11,781✔
1060
        SCReturnInt(-1);
×
1061
    }
×
1062

1063
    SCReturnInt(0);
11,781✔
1064
}
11,781✔
1065

1066
int FileCloseFileById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id,
1067
        const uint8_t *data, uint32_t data_len, uint16_t flags)
1068
{
9,470✔
1069
    SCEnter();
9,470✔
1070

1071
    if (ffc == NULL || ffc->tail == NULL) {
9,470✔
1072
        SCReturnInt(-1);
×
1073
    }
×
1074

1075
    File *ff = ffc->head;
9,470✔
1076
    for ( ; ff != NULL; ff = ff->next) {
9,475✔
1077
        if (track_id == ff->file_track_id) {
9,475✔
1078
            int r = FileCloseFilePtr(ff, sbcfg, data, data_len, flags);
9,470✔
1079
            SCReturnInt(r);
9,470✔
1080
        }
9,470✔
1081
    }
9,475✔
1082
    SCReturnInt(-1);
9,470✔
1083
}
9,470✔
1084

1085
/** \brief set a flow's file flags
1086
 *  \param set_file_flags flags in both directions that are requested to set
1087
 *
1088
 *  This function will ignore the flags for the irrelevant direction and
1089
 *  also mask the flags with the global settings.
1090
 */
1091
void FileUpdateFlowFileFlags(Flow *f, uint16_t set_file_flags, uint8_t direction)
1092
{
132,171✔
1093
    SCEnter();
132,171✔
1094
    DEBUG_ASSERT_FLOW_LOCKED(f);
132,171✔
1095

1096
    /* remove flags not in our direction and
1097
       don't disable what is globally enabled */
1098
    if (direction == STREAM_TOSERVER) {
132,171✔
1099
        set_file_flags &= ~(FLOWFILE_NONE_TC|g_file_flow_mask);
81,218✔
1100
    } else {
81,218✔
1101
        set_file_flags &= ~(FLOWFILE_NONE_TS|g_file_flow_mask);
50,953✔
1102
    }
50,953✔
1103
    f->file_flags |= set_file_flags;
132,171✔
1104

1105
    SCLogDebug("f->file_flags %04x set_file_flags %04x g_file_flow_mask %04x",
132,171✔
1106
            f->file_flags, set_file_flags, g_file_flow_mask);
132,171✔
1107

1108
    if (set_file_flags != 0 && f->alproto != ALPROTO_UNKNOWN && f->alstate != NULL) {
132,176✔
1109
        AppLayerStateData *sd = AppLayerParserGetStateData(f->proto, f->alproto, f->alstate);
23,908✔
1110
        if (sd != NULL) {
23,912✔
1111
            if ((sd->file_flags & f->file_flags) != f->file_flags) {
23,912✔
1112
                SCLogDebug("state data: updating file_flags %04x with flow file_flags %04x",
22,617✔
1113
                        sd->file_flags, f->file_flags);
22,617✔
1114
                sd->file_flags |= f->file_flags;
22,617✔
1115
            }
22,617✔
1116
        }
23,912✔
1117
    }
23,908✔
1118
}
132,171✔
1119

1120
/**
1121
 *  \brief disable file storing for files in a transaction
1122
 *
1123
 *  \param f *LOCKED* flow
1124
 *  \param direction flow direction
1125
 *  \param tx_id transaction id
1126
 */
1127
void FileDisableStoringForTransaction(Flow *f, const uint8_t direction, void *tx, uint64_t tx_id)
1128
{
31,771✔
1129
    if (g_file_force_filestore == 0) {
31,771✔
1130
        AppLayerTxData *txd = AppLayerParserGetTxData(f->proto, f->alproto, tx);
3,764✔
1131
        if (direction & STREAM_TOSERVER) {
3,764✔
1132
            txd->file_flags |= FLOWFILE_NO_STORE_TS;
2,669✔
1133
        } else {
2,685✔
1134
            txd->file_flags |= FLOWFILE_NO_STORE_TC;
1,095✔
1135
        }
1,095✔
1136
    }
3,764✔
1137
}
31,771✔
1138

1139
/**
1140
 *  \brief flag a file with id "file_id" to be stored.
1141
 *
1142
 *  \param fc file store
1143
 *  \param file_id the file's id
1144
 */
1145
void FileStoreFileById(FileContainer *fc, uint32_t file_id)
1146
{
750✔
1147
    File *ptr = NULL;
750✔
1148

1149
    SCEnter();
750✔
1150

1151
    if (fc != NULL) {
750✔
1152
        for (ptr = fc->head; ptr != NULL; ptr = ptr->next) {
1,506✔
1153
            if (ptr->file_track_id == file_id) {
756✔
1154
                FileStore(ptr);
750✔
1155
            }
750✔
1156
        }
756✔
1157
    }
750✔
1158
}
750✔
1159

1160
static void FileTruncateAllOpenFiles(FileContainer *fc, const StreamingBufferConfig *sbcfg)
1161
{
19,134✔
1162
    File *ptr = NULL;
19,134✔
1163

1164
    SCEnter();
19,134✔
1165

1166
    if (fc != NULL) {
19,134✔
1167
        for (ptr = fc->head; ptr != NULL; ptr = ptr->next) {
19,145✔
1168
            if (ptr->state == FILE_STATE_OPENED) {
11✔
1169
                FileCloseFilePtr(ptr, sbcfg, NULL, 0, FILE_TRUNCATED);
×
1170
            }
×
1171
        }
11✔
1172
    }
19,134✔
1173
}
19,134✔
1174

1175
void FilesPrune(FileContainer *fc, const StreamingBufferConfig *sbcfg, const bool trunc)
1176
{
264,815✔
1177
    if (trunc) {
264,815✔
1178
        FileTruncateAllOpenFiles(fc, sbcfg);
19,134✔
1179
    }
19,134✔
1180
    FilePrune(fc, sbcfg);
264,815✔
1181
}
264,815✔
1182

1183
/**
1184
 * \brief Finish the SHA256 calculation.
1185
 */
1186
static void FileEndSha256(File *ff)
1187
{
16,626✔
1188
    SCLogDebug("ff %p ff->size %" PRIu64, ff, ff->size);
16,626✔
1189
    if (!(ff->flags & FILE_SHA256) && ff->sha256_ctx) {
16,626✔
1190
        SCSha256Finalize(ff->sha256_ctx, ff->sha256, sizeof(ff->sha256));
16,626✔
1191
        ff->sha256_ctx = NULL;
16,626✔
1192
        ff->flags |= FILE_SHA256;
16,626✔
1193
    }
16,626✔
1194
}
16,626✔
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

© 2026 Coveralls, Inc