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

jasonish / suricata / 23114797756

15 Mar 2026 04:48PM UTC coverage: 79.303% (-0.007%) from 79.31%
23114797756

push

github

jasonish
fixup

265901 of 335299 relevant lines covered (79.3%)

5138115.35 hits per line

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

87.33
/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,803✔
135
    if (g_file_store_enable == 1)
69,803✔
136
        return g_file_store_reassembly_depth;
101✔
137
    else
69,702✔
138
        return stream_config.reassembly_depth;
69,702✔
139
}
69,803✔
140

141
int FileForceMagic(void)
142
{
124,160✔
143
    return g_file_force_magic;
124,160✔
144
}
124,160✔
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
{
774,869✔
217
    uint16_t flags = 0;
774,869✔
218

219
    if (direction == STREAM_TOSERVER) {
774,869✔
220
        if ((flow_file_flags & (FLOWFILE_NO_STORE_TS | FLOWFILE_STORE_TS)) ==
522,366✔
221
                FLOWFILE_NO_STORE_TS) {
522,366✔
222
            flags |= FILE_NOSTORE;
190,261✔
223
        } else if (flow_file_flags & FLOWFILE_STORE_TS) {
519,671✔
224
            flags |= FILE_STORE;
×
225
        }
×
226

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

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

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

239
        if (flow_file_flags & FLOWFILE_NO_SHA256_TS) {
522,366✔
240
            flags |= FILE_NOSHA256;
187,222✔
241
        }
187,222✔
242
    } else {
522,451✔
243
        if ((flow_file_flags & (FLOWFILE_NO_STORE_TC | FLOWFILE_STORE_TC)) ==
252,503✔
244
                FLOWFILE_NO_STORE_TC) {
252,503✔
245
            flags |= FILE_NOSTORE;
22,862✔
246
        } else if (flow_file_flags & FLOWFILE_STORE_TC) {
248,807✔
247
            flags |= FILE_STORE;
×
248
        }
×
249

250
        if (flow_file_flags & FLOWFILE_NO_MAGIC_TC) {
252,503✔
251
            flags |= FILE_NOMAGIC;
146,699✔
252
        }
146,699✔
253

254
        if (flow_file_flags & FLOWFILE_NO_MD5_TC) {
252,503✔
255
            flags |= FILE_NOMD5;
248,227✔
256
        }
248,227✔
257

258
        if (flow_file_flags & FLOWFILE_NO_SHA1_TC) {
252,503✔
259
            flags |= FILE_NOSHA1;
248,681✔
260
        }
248,681✔
261

262
        if (flow_file_flags & FLOWFILE_NO_SHA256_TC) {
252,503✔
263
            flags |= FILE_NOSHA256;
22,827✔
264
        }
22,827✔
265
    }
252,503✔
266
    DEBUG_VALIDATE_BUG_ON((flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE));
774,869✔
267

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

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

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

288
    file->flags |= update_flags;
227,772✔
289
    SCLogDebug("file flags %04x STORE %s NOSTORE %s", file->flags,
227,772✔
290
            (file->flags & FILE_STORE) ? "true" : "false",
227,772✔
291
            (file->flags & FILE_NOSTORE) ? "true" : "false");
227,772✔
292
    DEBUG_VALIDATE_BUG_ON(
227,772✔
293
            (file->flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE));
227,772✔
294
}
227,772✔
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
{
331,132✔
310
    if (file != NULL && file->sb != NULL) {
331,132✔
311
        const uint64_t size = StreamingBufferGetConsecutiveDataRightEdge(file->sb);
331,130✔
312
        SCLogDebug("returning %" PRIu64, size);
331,130✔
313
        return size;
331,130✔
314
    }
331,130✔
315
    SCLogDebug("returning 0 (default)");
2✔
316
    return 0;
2✔
317
}
331,132✔
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,418✔
327
    if (file != NULL) {
23,418✔
328
        return file->size;
23,418✔
329
    }
23,418✔
330
    return 0;
×
331
}
23,418✔
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
{
122,456✔
350
    SCEnter();
122,456✔
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",
122,456✔
354
            file->state, (file->state >= FILE_STATE_CLOSED) ? "yes" : "no");
122,456✔
355
    if (file->state >= FILE_STATE_CLOSED) {
122,456✔
356
        SCReturnInt(1);
19,502✔
357
    }
19,502✔
358

359
#ifdef HAVE_MAGIC
102,954✔
360
    if (!(file->flags & FILE_NOMAGIC)) {
102,954✔
361
        /* need magic but haven't set it yet, bail out */
362
        if (file->magic == NULL)
47,881✔
363
            SCReturnInt(0);
10,982✔
364
        else
36,899✔
365
            SCLogDebug("file->magic %s", file->magic);
36,899✔
366
    } else {
61,844✔
367
        SCLogDebug("file->flags & FILE_NOMAGIC == true");
55,073✔
368
    }
55,073✔
369
#endif
91,972✔
370
    uint64_t left_edge = FileDataSize(file);
91,972✔
371
    if (file->flags & FILE_STORE) {
91,972✔
372
        left_edge = MIN(left_edge,file->content_stored);
78,197✔
373
    }
78,197✔
374

375
    if (!g_detect_disabled) {
91,973✔
376
        left_edge = MIN(left_edge, file->content_inspected);
90,355✔
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) {
90,355✔
380
            const uint64_t file_offset = StreamingBufferGetOffset(file->sb);
90,354✔
381
            uint32_t window = file->inspect_window;
90,354✔
382
            if (file_offset == 0)
90,354✔
383
                window = MAX(window, file->inspect_min_size);
82,242✔
384

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

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

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

396
            if (left_edge > window)
90,354✔
397
                left_edge -= window;
8,456✔
398
            else
81,898✔
399
                left_edge = 0;
81,898✔
400
        }
90,354✔
401
    }
90,355✔
402

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

408
    SCReturnInt(0);
91,972✔
409
}
102,954✔
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
{
266,392✔
440
    SCEnter();
266,392✔
441
    SCLogDebug("ffc %p head %p", ffc, ffc->head);
266,392✔
442
    File *file = ffc->head;
266,392✔
443
    File *prev = NULL;
266,392✔
444

445
    while (file) {
388,848✔
446
#ifdef DEBUG
447
        FilePrintFlags(file);
448
#endif
449
        if (FilePruneFile(file, cfg) == 0) {
122,456✔
450
            prev = file;
102,953✔
451
            file = file->next;
102,953✔
452
            continue;
102,953✔
453
        }
102,953✔
454

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

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

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

467
        FileFree(file, cfg);
19,503✔
468
        file = file_next;
19,503✔
469
    }
19,503✔
470
    SCReturn;
266,392✔
471
}
266,392✔
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,384✔
481
    FileContainer *new = SCCalloc(1, sizeof(FileContainer));
5,384✔
482
    if (unlikely(new == NULL)) {
5,384✔
483
        SCLogError("Error allocating mem");
×
484
        return NULL;
×
485
    }
×
486
    new->head = new->tail = NULL;
5,384✔
487
    return new;
5,384✔
488
}
5,384✔
489

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

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

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

521
    File *ptr = ffc->head;
5,357✔
522
    File *next = NULL;
5,357✔
523
    for (;ptr != NULL; ptr = next) {
5,411✔
524
        next = ptr->next;
54✔
525
        FileFree(ptr, cfg);
54✔
526
    }
54✔
527
    ffc->head = ffc->tail = NULL;
5,357✔
528
    SCFree(ffc);
5,357✔
529
}
5,357✔
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,271✔
541
    File *new = SCCalloc(1, sizeof(File));
23,271✔
542
    if (unlikely(new == NULL)) {
23,271✔
543
        SCLogError("Error allocating mem");
×
544
        return NULL;
×
545
    }
×
546

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

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

556
    new->sid_cnt = 0;
23,271✔
557
    new->sid_max = 8;
23,271✔
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,271✔
560
    if (new->sid == NULL)
23,271✔
561
        new->sid_max = 0;
×
562

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

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

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

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

594
void FileContainerAdd(FileContainer *ffc, File *ff)
595
{
23,280✔
596
    SCLogDebug("ffc %p ff %p", ffc, ff);
23,280✔
597
    if (ffc->head == NULL || ffc->tail == NULL) {
23,280✔
598
        ffc->head = ffc->tail = ff;
23,252✔
599
    } else {
23,252✔
600
        ffc->tail->next = ff;
28✔
601
        ffc->tail = ff;
28✔
602
    }
28✔
603
}
23,280✔
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,608✔
612
    SCLogDebug("ff %p", ff);
18,608✔
613
    ff->flags |= FILE_STORE;
18,608✔
614
    SCReturnInt(0);
18,608✔
615
}
18,608✔
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
{
474,259✔
647
    DEBUG_VALIDATE_BUG_ON(
474,259✔
648
            data_len > BIT_U32(26)); // 64MiB as a limit per chunk seems already excessive
474,259✔
649

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

656
    if (file->md5_ctx) {
474,259✔
657
        SCMd5Update(file->md5_ctx, data, data_len);
1,787✔
658
    }
1,787✔
659
    if (file->sha1_ctx) {
474,259✔
660
        SCSha1Update(file->sha1_ctx, data, data_len);
1,764✔
661
    }
1,764✔
662
    if (file->sha256_ctx) {
474,259✔
663
        SCLogDebug("SHA256 file %p data %p data_len %u", file, data, data_len);
293,413✔
664
        SCSha256Update(file->sha256_ctx, data, data_len);
293,413✔
665
    } else {
470,237✔
666
        SCLogDebug("NO SHA256 file %p data %p data_len %u", file, data, data_len);
180,846✔
667
    }
180,846✔
668
    SCReturnInt(0);
474,259✔
669
}
474,259✔
670

671
/** \internal
672
 *  \brief Flags a file as having gaps
673
 *
674
 *  \param ff the file
675
 */
676
static void FileFlagGap(File *ff) {
451✔
677
    ff->flags |= FILE_HAS_GAPS;
451✔
678
    ff->flags |= (FILE_NOMD5|FILE_NOSHA1|FILE_NOSHA256);
451✔
679
    ff->flags &= ~(FILE_MD5|FILE_SHA1|FILE_SHA256);
451✔
680
}
451✔
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
{
482,017✔
696
    SCEnter();
482,017✔
697
#ifdef DEBUG_VALIDATION
698
    BUG_ON(ff == NULL);
699
#endif
700

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

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

714
    if (g_detect_disabled && FileStoreNoStoreCheck(ff) == 1) {
481,707✔
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);
462,001✔
743

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

750
    SCReturnInt(0);
462,001✔
751
}
462,001✔
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
{
487,017✔
768
    SCEnter();
487,017✔
769

770
    if (ffc == NULL || ffc->tail == NULL || data_len == 0 || sbcfg == NULL) {
487,017✔
771
        SCReturnInt(-1);
26,066✔
772
    }
26,066✔
773
    int r = FileAppendDataDo(sbcfg, ffc->tail, data, data_len);
460,951✔
774
    SCReturnInt(r);
460,951✔
775
}
487,017✔
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,979✔
793
    SCEnter();
20,979✔
794

795
    if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) {
20,979✔
796
        SCReturnInt(-1);
×
797
    }
×
798
    File *ff = ffc->head;
20,979✔
799
    for ( ; ff != NULL; ff = ff->next) {
20,981✔
800
        if (track_id == ff->file_track_id) {
20,981✔
801
            int r = FileAppendDataDo(sbcfg, ff, data, data_len);
20,979✔
802
            SCReturnInt(r);
20,979✔
803
        }
20,979✔
804
    }
20,981✔
805
    SCReturnInt(-1);
20,979✔
806
}
20,979✔
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,806✔
844
    file->inspect_window = win;
35,806✔
845
    file->inspect_min_size = min;
35,806✔
846
}
35,806✔
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,597✔
860
    SCEnter();
1,597✔
861

862
    if (ffc == NULL || ffc->tail == NULL) {
1,597✔
863
        SCReturnInt(-1);
×
864
    }
×
865
    ffc->tail->start = start;
1,597✔
866
    ffc->tail->end = end;
1,597✔
867
    SCReturnInt(0);
1,597✔
868
}
1,597✔
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,271✔
889
    SCEnter();
23,271✔
890

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

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

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

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

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

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

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

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

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

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

960
    SCReturnPtr(ff, "File");
23,271✔
961
}
23,271✔
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,272✔
970
    SCLogDebug("ffc %p track_id %u", ffc, track_id);
23,272✔
971
    File *ff = FileOpenFile(ffc, sbcfg, name, name_len, data, data_len, flags);
23,272✔
972
    if (ff == NULL)
23,272✔
973
        return -1;
×
974

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

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

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

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

992
    ff->size += data_len;
21,746✔
993
    if (data != NULL) {
21,746✔
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,746✔
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,944✔
1017
        ff->state = FILE_STATE_CLOSED;
20,944✔
1018
        SCLogDebug("flowfile state transitioned to FILE_STATE_CLOSED");
20,944✔
1019

1020
        if (ff->md5_ctx) {
20,944✔
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,944✔
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,944✔
1031
            SCLogDebug("file %p data %p data_len %u", ff, data, data_len);
15,961✔
1032
            FileEndSha256(ff);
15,961✔
1033
        }
15,961✔
1034
    }
20,944✔
1035

1036
    SCReturnInt(0);
21,746✔
1037
}
21,746✔
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,784✔
1053
    SCEnter();
11,784✔
1054

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

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

1063
    SCReturnInt(0);
11,784✔
1064
}
11,784✔
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,469✔
1069
    SCEnter();
9,469✔
1070

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

1075
    File *ff = ffc->head;
9,469✔
1076
    for ( ; ff != NULL; ff = ff->next) {
9,471✔
1077
        if (track_id == ff->file_track_id) {
9,471✔
1078
            int r = FileCloseFilePtr(ff, sbcfg, data, data_len, flags);
9,469✔
1079
            SCReturnInt(r);
9,469✔
1080
        }
9,469✔
1081
    }
9,471✔
1082
    SCReturnInt(-1);
9,469✔
1083
}
9,469✔
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
{
131,967✔
1093
    SCEnter();
131,967✔
1094
    DEBUG_ASSERT_FLOW_LOCKED(f);
131,967✔
1095

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

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

1108
    if (set_file_flags != 0 && f->alproto != ALPROTO_UNKNOWN && f->alstate != NULL) {
131,967✔
1109
        AppLayerStateData *sd = AppLayerParserGetStateData(f->proto, f->alproto, f->alstate);
23,830✔
1110
        if (sd != NULL) {
23,839✔
1111
            if ((sd->file_flags & f->file_flags) != f->file_flags) {
23,839✔
1112
                SCLogDebug("state data: updating file_flags %04x with flow file_flags %04x",
22,542✔
1113
                        sd->file_flags, f->file_flags);
22,542✔
1114
                sd->file_flags |= f->file_flags;
22,542✔
1115
            }
22,542✔
1116
        }
23,839✔
1117
    }
23,830✔
1118
}
131,967✔
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,766✔
1129
    if (g_file_force_filestore == 0) {
31,766✔
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,766✔
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
{
266,393✔
1177
    if (trunc) {
266,393✔
1178
        FileTruncateAllOpenFiles(fc, sbcfg);
19,134✔
1179
    }
19,134✔
1180
    FilePrune(fc, sbcfg);
266,393✔
1181
}
266,393✔
1182

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