Coverage Report

Created: 2025-12-31 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/util-file.c
Line
Count
Source
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
4
{
94
4
    g_file_force_filestore = 1;
95
4
    g_file_flow_mask |= (FLOWFILE_NO_STORE_TS|FLOWFILE_NO_STORE_TC);
96
4
}
97
98
void FileForceMagicEnable(void)
99
0
{
100
0
    g_file_force_magic = 1;
101
0
    g_file_flow_mask |= (FLOWFILE_NO_MAGIC_TS|FLOWFILE_NO_MAGIC_TC);
102
0
}
103
104
void FileForceMd5Enable(void)
105
0
{
106
0
    g_file_force_md5 = 1;
107
0
    g_file_flow_mask |= (FLOWFILE_NO_MD5_TS|FLOWFILE_NO_MD5_TC);
108
0
}
109
110
void FileForceSha1Enable(void)
111
0
{
112
0
    g_file_force_sha1 = 1;
113
0
    g_file_flow_mask |= (FLOWFILE_NO_SHA1_TS|FLOWFILE_NO_SHA1_TC);
114
0
}
115
116
void FileForceSha256Enable(void)
117
4
{
118
4
    g_file_force_sha256 = 1;
119
4
    g_file_flow_mask |= (FLOWFILE_NO_SHA256_TS|FLOWFILE_NO_SHA256_TC);
120
4
}
121
122
int FileForceFilestore(void)
123
0
{
124
0
    return g_file_force_filestore;
125
0
}
126
127
void FileReassemblyDepthEnable(uint32_t size)
128
0
{
129
0
    g_file_store_enable = 1;
130
0
    g_file_store_reassembly_depth = size;
131
0
}
132
133
uint32_t FileReassemblyDepth(void)
134
5.21M
{
135
5.21M
    if (g_file_store_enable == 1)
136
0
        return g_file_store_reassembly_depth;
137
5.21M
    else
138
5.21M
        return stream_config.reassembly_depth;
139
5.21M
}
140
141
int FileForceMagic(void)
142
0
{
143
0
    return g_file_force_magic;
144
0
}
145
146
int FileForceMd5(void)
147
0
{
148
0
    return g_file_force_md5;
149
0
}
150
151
int FileForceSha1(void)
152
0
{
153
0
    return g_file_force_sha1;
154
0
}
155
156
int FileForceSha256(void)
157
0
{
158
0
    return g_file_force_sha256;
159
0
}
160
161
void FileForceTrackingEnable(void)
162
4
{
163
4
    g_file_force_tracking = 1;
164
4
    g_file_flow_mask |= (FLOWFILE_NO_SIZE_TS|FLOWFILE_NO_SIZE_TC);
165
4
}
166
167
/**
168
 * \brief Function to parse forced file hashing configuration.
169
 */
170
void FileForceHashParseCfg(ConfNode *conf)
171
2
{
172
2
    BUG_ON(conf == NULL);
173
174
2
    ConfNode *forcehash_node = NULL;
175
176
    /* legacy option */
177
2
    const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5");
178
2
    if (force_md5 != NULL) {
179
0
        SCLogWarning("deprecated 'force-md5' option "
180
0
                     "found. Please use 'force-hash: [md5]' instead");
181
182
0
        if (ConfValIsTrue(force_md5)) {
183
0
            if (g_disable_hashing) {
184
0
                SCLogInfo(
185
0
                        "not forcing md5 calculation for logged files: hashing globally disabled");
186
0
            } else {
187
0
                FileForceMd5Enable();
188
0
                SCLogInfo("forcing md5 calculation for logged files");
189
0
            }
190
0
        }
191
0
    }
192
193
2
    if (conf != NULL)
194
2
        forcehash_node = ConfNodeLookupChild(conf, "force-hash");
195
196
2
    if (forcehash_node != NULL) {
197
0
        ConfNode *field = NULL;
198
199
0
        TAILQ_FOREACH(field, &forcehash_node->head, next) {
200
0
            if (strcasecmp("md5", field->val) == 0) {
201
0
                if (g_disable_hashing) {
202
0
                    SCLogInfo("not forcing md5 calculation for logged files: hashing globally "
203
0
                              "disabled");
204
0
                } else {
205
0
                    FileForceMd5Enable();
206
0
                    SCLogConfig("forcing md5 calculation for logged or stored files");
207
0
                }
208
0
            }
209
210
0
            if (strcasecmp("sha1", field->val) == 0) {
211
0
                if (g_disable_hashing) {
212
0
                    SCLogInfo("not forcing sha1 calculation for logged files: hashing globally "
213
0
                              "disabled");
214
0
                } else {
215
0
                    FileForceSha1Enable();
216
0
                    SCLogConfig("forcing sha1 calculation for logged or stored files");
217
0
                }
218
0
            }
219
220
0
            if (strcasecmp("sha256", field->val) == 0) {
221
0
                if (g_disable_hashing) {
222
0
                    SCLogInfo("not forcing sha256 calculation for logged files: hashing globally "
223
0
                              "disabled");
224
0
                } else {
225
0
                    FileForceSha256Enable();
226
0
                    SCLogConfig("forcing sha256 calculation for logged or stored files");
227
0
                }
228
0
            }
229
0
        }
230
0
    }
231
2
}
232
233
uint16_t FileFlowFlagsToFlags(const uint16_t flow_file_flags, uint8_t direction)
234
8.96M
{
235
8.96M
    uint16_t flags = 0;
236
237
8.96M
    if (direction == STREAM_TOSERVER) {
238
6.42M
        if ((flow_file_flags & (FLOWFILE_NO_STORE_TS | FLOWFILE_STORE_TS)) ==
239
6.42M
                FLOWFILE_NO_STORE_TS) {
240
0
            flags |= FILE_NOSTORE;
241
6.42M
        } else if (flow_file_flags & FLOWFILE_STORE_TS) {
242
0
            flags |= FILE_STORE;
243
0
        }
244
245
6.42M
        if (flow_file_flags & FLOWFILE_NO_MAGIC_TS) {
246
159k
            flags |= FILE_NOMAGIC;
247
159k
        }
248
249
6.42M
        if (flow_file_flags & FLOWFILE_NO_MD5_TS) {
250
368k
            flags |= FILE_NOMD5;
251
368k
        }
252
253
6.42M
        if (flow_file_flags & FLOWFILE_NO_SHA1_TS) {
254
368k
            flags |= FILE_NOSHA1;
255
368k
        }
256
257
6.42M
        if (flow_file_flags & FLOWFILE_NO_SHA256_TS) {
258
0
            flags |= FILE_NOSHA256;
259
0
        }
260
6.42M
    } else {
261
2.53M
        if ((flow_file_flags & (FLOWFILE_NO_STORE_TC | FLOWFILE_STORE_TC)) ==
262
2.53M
                FLOWFILE_NO_STORE_TC) {
263
0
            flags |= FILE_NOSTORE;
264
2.53M
        } else if (flow_file_flags & FLOWFILE_STORE_TC) {
265
0
            flags |= FILE_STORE;
266
0
        }
267
268
2.53M
        if (flow_file_flags & FLOWFILE_NO_MAGIC_TC) {
269
370k
            flags |= FILE_NOMAGIC;
270
370k
        }
271
272
2.53M
        if (flow_file_flags & FLOWFILE_NO_MD5_TC) {
273
787k
            flags |= FILE_NOMD5;
274
787k
        }
275
276
2.53M
        if (flow_file_flags & FLOWFILE_NO_SHA1_TC) {
277
787k
            flags |= FILE_NOSHA1;
278
787k
        }
279
280
2.53M
        if (flow_file_flags & FLOWFILE_NO_SHA256_TC) {
281
0
            flags |= FILE_NOSHA256;
282
0
        }
283
2.53M
    }
284
8.96M
    DEBUG_VALIDATE_BUG_ON((flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE));
285
286
8.96M
    SCLogDebug("direction %02x flags %02x", direction, flags);
287
8.96M
    return flags;
288
8.96M
}
289
290
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
291
26.4M
{
292
26.4M
    return FileFlowFlagsToFlags(flow->file_flags, direction);
293
26.4M
}
294
295
void FileApplyTxFlags(const AppLayerTxData *txd, const uint8_t direction, File *file)
296
4.44M
{
297
4.44M
    SCLogDebug("file flags %04x STORE %s NOSTORE %s", file->flags,
298
4.44M
            (file->flags & FILE_STORE) ? "true" : "false",
299
4.44M
            (file->flags & FILE_NOSTORE) ? "true" : "false");
300
4.44M
    uint16_t update_flags = FileFlowFlagsToFlags(txd->file_flags, direction);
301
4.44M
    DEBUG_VALIDATE_BUG_ON(
302
4.44M
            (file->flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE));
303
4.44M
    if (file->flags & FILE_STORE)
304
4.44M
        update_flags &= ~FILE_NOSTORE;
305
306
4.44M
    file->flags |= update_flags;
307
4.44M
    SCLogDebug("file flags %04x STORE %s NOSTORE %s", file->flags,
308
4.44M
            (file->flags & FILE_STORE) ? "true" : "false",
309
4.44M
            (file->flags & FILE_NOSTORE) ? "true" : "false");
310
4.44M
    DEBUG_VALIDATE_BUG_ON(
311
4.44M
            (file->flags & (FILE_STORE | FILE_NOSTORE)) == (FILE_STORE | FILE_NOSTORE));
312
4.44M
}
313
314
static int FileMagicSize(void)
315
0
{
316
    /** \todo make this size configurable */
317
0
    return 512;
318
0
}
319
320
/**
321
 *  \brief get the size of the file data
322
 *
323
 *  This doesn't reflect how much of the file we have in memory, just the
324
 *  total size of filedata so far.
325
 */
326
uint64_t FileDataSize(const File *file)
327
80.8M
{
328
80.8M
    if (file != NULL && file->sb != NULL) {
329
80.8M
        const uint64_t size = StreamingBufferGetConsecutiveDataRightEdge(file->sb);
330
80.8M
        SCLogDebug("returning %" PRIu64, size);
331
80.8M
        return size;
332
80.8M
    }
333
0
    SCLogDebug("returning 0 (default)");
334
0
    return 0;
335
80.8M
}
336
337
/**
338
 *  \brief get the size of the file
339
 *
340
 *  This doesn't reflect how much of the file we have in memory, just the
341
 *  total size of file so far.
342
 */
343
uint64_t FileTrackedSize(const File *file)
344
222k
{
345
222k
    if (file != NULL) {
346
222k
        return file->size;
347
222k
    }
348
0
    return 0;
349
222k
}
350
351
/** \brief test if file is ready to be pruned
352
 *
353
 *  If a file is in the 'CLOSED' state, it means it has been processed
354
 *  completely by the pipeline in the correct direction. So we can
355
 *  prune it then.
356
 *
357
 *  For other states, as well as for files we may not need to track
358
 *  until the close state, more specific checks are done.
359
 *
360
 *  Also does house keeping within the file: move streaming buffer
361
 *  forward if possible.
362
 *
363
 *  \retval 1 prune (free) this file
364
 *  \retval 0 file not ready to be freed
365
 */
366
static int FilePruneFile(File *file, const StreamingBufferConfig *cfg)
367
40.3M
{
368
40.3M
    SCEnter();
369
370
    /* file is done when state is closed+, logging/storing is done (if any) */
371
40.3M
    SCLogDebug("file->state %d. Is >= FILE_STATE_CLOSED: %s",
372
40.3M
            file->state, (file->state >= FILE_STATE_CLOSED) ? "yes" : "no");
373
40.3M
    if (file->state >= FILE_STATE_CLOSED) {
374
1.10M
        SCReturnInt(1);
375
1.10M
    }
376
377
#ifdef HAVE_MAGIC
378
    if (!(file->flags & FILE_NOMAGIC)) {
379
        /* need magic but haven't set it yet, bail out */
380
        if (file->magic == NULL)
381
            SCReturnInt(0);
382
        else
383
            SCLogDebug("file->magic %s", file->magic);
384
    } else {
385
        SCLogDebug("file->flags & FILE_NOMAGIC == true");
386
    }
387
#endif
388
39.2M
    uint64_t left_edge = FileDataSize(file);
389
39.2M
    if (file->flags & FILE_STORE) {
390
1.86M
        left_edge = MIN(left_edge,file->content_stored);
391
1.86M
    }
392
393
39.2M
    if (!g_detect_disabled) {
394
39.2M
        left_edge = MIN(left_edge, file->content_inspected);
395
        /* if file has inspect window and min size set, we
396
         * do some house keeping here */
397
39.2M
        if (file->inspect_window != 0 && file->inspect_min_size != 0) {
398
39.2M
            const uint64_t file_offset = StreamingBufferGetOffset(file->sb);
399
39.2M
            uint32_t window = file->inspect_window;
400
39.2M
            if (file_offset == 0)
401
39.0M
                window = MAX(window, file->inspect_min_size);
402
403
39.2M
            uint64_t file_size = FileDataSize(file);
404
39.2M
            uint64_t data_size = file_size - file_offset;
405
406
39.2M
            SCLogDebug("window %"PRIu32", file_size %"PRIu64", data_size %"PRIu64,
407
39.2M
                    window, file_size, data_size);
408
409
39.2M
            if (data_size > (window * 3)) {
410
30.1k
                file->content_inspected = MAX(file->content_inspected, file->size - window);
411
30.1k
                SCLogDebug("file->content_inspected now %" PRIu64, file->content_inspected);
412
30.1k
            }
413
414
39.2M
            if (left_edge > window)
415
209k
                left_edge -= window;
416
39.0M
            else
417
39.0M
                left_edge = 0;
418
39.2M
        }
419
39.2M
    }
420
421
39.2M
    if (left_edge) {
422
209k
        SCLogDebug("sliding to %" PRIu64, left_edge);
423
209k
        StreamingBufferSlideToOffset(file->sb, cfg, left_edge);
424
209k
    }
425
426
39.2M
    SCReturnInt(0);
427
40.3M
}
428
429
#ifdef DEBUG
430
#define P(file, flag) ((file)->flags & (flag)) ? "true" : "false"
431
void FilePrintFlags(const File *file)
432
{
433
    SCLogDebug("file %p flags %04x "
434
               "FILE_TRUNCATED %s "
435
               "FILE_NOMAGIC %s "
436
               "FILE_NOMD5 %s "
437
               "FILE_MD5 %s "
438
               "FILE_NOSHA1 %s "
439
               "FILE_SHA1 %s "
440
               "FILE_NOSHA256 %s "
441
               "FILE_SHA256 %s "
442
               "FILE_LOGGED %s "
443
               "FILE_NOSTORE %s "
444
               "FILE_STORE %s "
445
               "FILE_STORED %s "
446
               "FILE_NOTRACK %s "
447
               "FILE_HAS_GAPS %s",
448
            file, file->flags, P(file, FILE_TRUNCATED), P(file, FILE_NOMAGIC), P(file, FILE_NOMD5),
449
            P(file, FILE_MD5), P(file, FILE_NOSHA1), P(file, FILE_SHA1), P(file, FILE_NOSHA256),
450
            P(file, FILE_SHA256), P(file, FILE_LOGGED), P(file, FILE_NOSTORE), P(file, FILE_STORE),
451
            P(file, FILE_STORED), P(file, FILE_NOTRACK), P(file, FILE_HAS_GAPS));
452
}
453
#undef P
454
#endif
455
456
static void FilePrune(FileContainer *ffc, const StreamingBufferConfig *cfg)
457
111M
{
458
111M
    SCEnter();
459
111M
    SCLogDebug("ffc %p head %p", ffc, ffc->head);
460
111M
    File *file = ffc->head;
461
111M
    File *prev = NULL;
462
463
152M
    while (file) {
464
#ifdef DEBUG
465
        FilePrintFlags(file);
466
#endif
467
40.3M
        if (FilePruneFile(file, cfg) == 0) {
468
39.2M
            prev = file;
469
39.2M
            file = file->next;
470
39.2M
            continue;
471
39.2M
        }
472
473
1.10M
        SCLogDebug("removing file %p", file);
474
475
1.10M
        File *file_next = file->next;
476
477
1.10M
        if (prev)
478
1.60k
            prev->next = file_next;
479
        /* update head and tail */
480
1.10M
        if (file == ffc->head)
481
1.10M
            ffc->head = file_next;
482
1.10M
        if (file == ffc->tail)
483
824k
            ffc->tail = prev;
484
485
1.10M
        FileFree(file, cfg);
486
1.10M
        file = file_next;
487
1.10M
    }
488
111M
    SCReturn;
489
111M
}
490
491
/**
492
 *  \brief allocate a FileContainer
493
 *
494
 *  \retval new newly allocated FileContainer
495
 *  \retval NULL error
496
 */
497
FileContainer *FileContainerAlloc(void)
498
8.10k
{
499
8.10k
    FileContainer *new = SCMalloc(sizeof(FileContainer));
500
8.10k
    if (unlikely(new == NULL)) {
501
0
        SCLogError("Error allocating mem");
502
0
        return NULL;
503
0
    }
504
8.10k
    memset(new, 0, sizeof(FileContainer));
505
8.10k
    new->head = new->tail = NULL;
506
8.10k
    return new;
507
8.10k
}
508
509
/**
510
 *  \brief Recycle a FileContainer
511
 *
512
 *  \param ffc FileContainer
513
 */
514
void FileContainerRecycle(FileContainer *ffc, const StreamingBufferConfig *cfg)
515
8.46M
{
516
8.46M
    SCLogDebug("ffc %p", ffc);
517
8.46M
    if (ffc == NULL)
518
0
        return;
519
520
8.46M
    File *cur = ffc->head;
521
8.46M
    File *next = NULL;
522
8.73M
    for (;cur != NULL; cur = next) {
523
274k
        next = cur->next;
524
274k
        FileFree(cur, cfg);
525
274k
    }
526
8.46M
    ffc->head = ffc->tail = NULL;
527
8.46M
}
528
529
/**
530
 *  \brief Free a FileContainer
531
 *
532
 *  \param ffc FileContainer
533
 */
534
void FileContainerFree(FileContainer *ffc, const StreamingBufferConfig *cfg)
535
5.80k
{
536
5.80k
    SCLogDebug("ffc %p", ffc);
537
5.80k
    if (ffc == NULL)
538
67
        return;
539
540
5.74k
    File *ptr = ffc->head;
541
5.74k
    File *next = NULL;
542
5.84k
    for (;ptr != NULL; ptr = next) {
543
105
        next = ptr->next;
544
105
        FileFree(ptr, cfg);
545
105
    }
546
5.74k
    ffc->head = ffc->tail = NULL;
547
5.74k
    SCFree(ffc);
548
5.74k
}
549
550
/**
551
 *  \brief Alloc a new File
552
 *
553
 *  \param name character array containing the name (not a string)
554
 *  \param name_len length in bytes of the name
555
 *
556
 *  \retval new File object or NULL on error
557
 */
558
static File *FileAlloc(const uint8_t *name, uint16_t name_len)
559
1.38M
{
560
1.38M
    File *new = SCMalloc(sizeof(File));
561
1.38M
    if (unlikely(new == NULL)) {
562
0
        SCLogError("Error allocating mem");
563
0
        return NULL;
564
0
    }
565
1.38M
    memset(new, 0, sizeof(File));
566
567
1.38M
    new->name = SCMalloc(name_len);
568
1.38M
    if (new->name == NULL) {
569
0
        SCFree(new);
570
0
        return NULL;
571
0
    }
572
573
1.38M
    new->name_len = name_len;
574
1.38M
    memcpy(new->name, name, name_len);
575
576
1.38M
    new->sid_cnt = 0;
577
1.38M
    new->sid_max = 8;
578
    /* SCMalloc() is allowed to fail here because sid well be checked later on */
579
1.38M
    new->sid = SCMalloc(sizeof(uint32_t) * new->sid_max);
580
1.38M
    if (new->sid == NULL)
581
0
        new->sid_max = 0;
582
583
1.38M
    return new;
584
1.38M
}
585
586
static void FileFree(File *ff, const StreamingBufferConfig *sbcfg)
587
1.37M
{
588
1.37M
    SCLogDebug("ff %p", ff);
589
1.37M
    if (ff == NULL)
590
0
        return;
591
592
1.37M
    if (ff->name != NULL)
593
1.37M
        SCFree(ff->name);
594
1.37M
    if (ff->sid != NULL)
595
1.37M
        SCFree(ff->sid);
596
#ifdef HAVE_MAGIC
597
    /* magic returned by libmagic is strdup'd by MagicLookup. */
598
    if (ff->magic != NULL)
599
        SCFree(ff->magic);
600
#endif
601
1.37M
    if (ff->sb != NULL) {
602
1.37M
        StreamingBufferFree(ff->sb, sbcfg);
603
1.37M
    }
604
605
1.37M
    if (ff->md5_ctx)
606
195k
        SCMd5Free(ff->md5_ctx);
607
1.37M
    if (ff->sha1_ctx)
608
195k
        SCSha1Free(ff->sha1_ctx);
609
1.37M
    if (ff->sha256_ctx)
610
209k
        SCSha256Free(ff->sha256_ctx);
611
1.37M
    SCFree(ff);
612
1.37M
}
613
614
void FileContainerAdd(FileContainer *ffc, File *ff)
615
1.38M
{
616
1.38M
    SCLogDebug("ffc %p ff %p", ffc, ff);
617
1.38M
    if (ffc->head == NULL || ffc->tail == NULL) {
618
1.09M
        ffc->head = ffc->tail = ff;
619
1.09M
    } else {
620
290k
        ffc->tail->next = ff;
621
290k
        ffc->tail = ff;
622
290k
    }
623
1.38M
}
624
625
/**
626
 *  \brief Tag a file for storing
627
 *
628
 *  \param ff The file to store
629
 */
630
int FileStore(File *ff)
631
220k
{
632
220k
    SCLogDebug("ff %p", ff);
633
220k
    ff->flags |= FILE_STORE;
634
220k
    SCReturnInt(0);
635
220k
}
636
637
/**
638
 *  \brief check if we have stored enough
639
 *
640
 *  \param ff file
641
 *
642
 *  \retval 0 limit not reached yet
643
 *  \retval 1 limit reached
644
 */
645
static int FileStoreNoStoreCheck(File *ff)
646
0
{
647
0
    SCEnter();
648
649
0
    if (ff == NULL) {
650
0
        SCReturnInt(0);
651
0
    }
652
653
0
    if (ff->flags & FILE_NOSTORE) {
654
0
        if (ff->state == FILE_STATE_OPENED &&
655
0
            FileDataSize(ff) >= (uint64_t)FileMagicSize())
656
0
        {
657
0
            SCReturnInt(1);
658
0
        }
659
0
    }
660
661
0
    SCReturnInt(0);
662
0
}
663
664
static int AppendData(
665
        const StreamingBufferConfig *sbcfg, File *file, const uint8_t *data, uint32_t data_len)
666
3.67M
{
667
3.67M
    SCLogDebug("file %p data_len %u", file, data_len);
668
3.67M
    if (StreamingBufferAppendNoTrack(file->sb, sbcfg, data, data_len) != 0) {
669
0
        SCLogDebug("file %p StreamingBufferAppendNoTrack failed", file);
670
0
        SCReturnInt(-1);
671
0
    }
672
673
3.67M
    if (file->md5_ctx) {
674
3.23M
        SCMd5Update(file->md5_ctx, data, data_len);
675
3.23M
    }
676
3.67M
    if (file->sha1_ctx) {
677
3.23M
        SCSha1Update(file->sha1_ctx, data, data_len);
678
3.23M
    }
679
3.67M
    if (file->sha256_ctx) {
680
3.67M
        SCLogDebug("SHA256 file %p data %p data_len %u", file, data, data_len);
681
3.67M
        SCSha256Update(file->sha256_ctx, data, data_len);
682
3.67M
    } else {
683
0
        SCLogDebug("NO SHA256 file %p data %p data_len %u", file, data, data_len);
684
0
    }
685
3.67M
    SCReturnInt(0);
686
3.67M
}
687
688
/** \internal
689
 *  \brief Flags a file as having gaps
690
 *
691
 *  \param ff the file
692
 */
693
1.52k
static void FileFlagGap(File *ff) {
694
1.52k
    ff->flags |= FILE_HAS_GAPS;
695
1.52k
    ff->flags |= (FILE_NOMD5|FILE_NOSHA1|FILE_NOSHA256);
696
1.52k
    ff->flags &= ~(FILE_MD5|FILE_SHA1|FILE_SHA256);
697
1.52k
}
698
699
/** \internal
700
 *  \brief Store/handle a chunk of file data in the File structure
701
 *
702
 *  \param ff the file
703
 *  \param data data chunk
704
 *  \param data_len data chunk len
705
 *
706
 *  \retval  0 ok
707
 *  \retval -1 error
708
 *  \retval -2 no store for this file
709
 */
710
static int FileAppendDataDo(
711
        const StreamingBufferConfig *sbcfg, File *ff, const uint8_t *data, uint32_t data_len)
712
22.2M
{
713
22.2M
    SCEnter();
714
22.2M
#ifdef DEBUG_VALIDATION
715
22.2M
    BUG_ON(ff == NULL);
716
22.2M
#endif
717
718
22.2M
    ff->size += data_len;
719
22.2M
    if (data == NULL) {
720
818
        FileFlagGap(ff);
721
818
        SCReturnInt(0);
722
818
    }
723
724
22.2M
    if (ff->state != FILE_STATE_OPENED) {
725
1.09k
        if (ff->flags & FILE_NOSTORE) {
726
0
            SCReturnInt(-2);
727
0
        }
728
1.09k
        SCReturnInt(-1);
729
1.09k
    }
730
731
22.2M
    if (g_detect_disabled && FileStoreNoStoreCheck(ff) == 1) {
732
0
        int hash_done = 0;
733
        /* no storage but forced hashing */
734
0
        if (ff->md5_ctx) {
735
0
            SCMd5Update(ff->md5_ctx, data, data_len);
736
0
            hash_done = 1;
737
0
        }
738
0
        if (ff->sha1_ctx) {
739
0
            SCSha1Update(ff->sha1_ctx, data, data_len);
740
0
            hash_done = 1;
741
0
        }
742
0
        if (ff->sha256_ctx) {
743
0
            SCLogDebug("file %p data %p data_len %u", ff, data, data_len);
744
0
            SCSha256Update(ff->sha256_ctx, data, data_len);
745
0
            hash_done = 1;
746
0
        }
747
748
0
        if (hash_done)
749
0
            SCReturnInt(0);
750
751
0
        if (g_file_force_tracking || (!(ff->flags & FILE_NOTRACK)))
752
0
            SCReturnInt(0);
753
754
0
        ff->state = FILE_STATE_TRUNCATED;
755
0
        SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED");
756
0
        SCReturnInt(-2);
757
0
    }
758
759
22.2M
    SCLogDebug("appending %"PRIu32" bytes", data_len);
760
761
22.2M
    int r = AppendData(sbcfg, ff, data, data_len);
762
22.2M
    if (r != 0) {
763
0
        ff->state = FILE_STATE_ERROR;
764
0
        SCReturnInt(r);
765
0
    }
766
767
22.2M
    SCReturnInt(0);
768
22.2M
}
769
770
/**
771
 *  \brief Store/handle a chunk of file data in the File structure
772
 *         The last file in the FileContainer will be used.
773
 *
774
 *  \param ffc FileContainer used to append to
775
 *  \param data data chunk
776
 *  \param data_len data chunk len
777
 *
778
 *  \retval  0 ok
779
 *  \retval -1 error
780
 *  \retval -2 no store for this file
781
 */
782
int FileAppendData(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data,
783
        uint32_t data_len)
784
36.7M
{
785
36.7M
    SCEnter();
786
787
36.7M
    if (ffc == NULL || ffc->tail == NULL || data_len == 0 || sbcfg == NULL) {
788
15.2M
        SCReturnInt(-1);
789
15.2M
    }
790
21.4M
    int r = FileAppendDataDo(sbcfg, ffc->tail, data, data_len);
791
21.4M
    SCReturnInt(r);
792
36.7M
}
793
794
/**
795
 *  \brief Store/handle a chunk of file data in the File structure
796
 *         The file with 'track_id' in the FileContainer will be used.
797
 *
798
 *  \param ffc FileContainer used to append to
799
 *  \param track_id id to lookup the file
800
 *  \param data data chunk
801
 *  \param data_len data chunk len
802
 *
803
 *  \retval  0 ok
804
 *  \retval -1 error
805
 *  \retval -2 no store for this file
806
 */
807
int FileAppendDataById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id,
808
        const uint8_t *data, uint32_t data_len)
809
845k
{
810
845k
    SCEnter();
811
812
845k
    if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) {
813
1.50k
        SCReturnInt(-1);
814
1.50k
    }
815
843k
    File *ff = ffc->head;
816
843k
    for ( ; ff != NULL; ff = ff->next) {
817
843k
        if (track_id == ff->file_track_id) {
818
843k
            int r = FileAppendDataDo(sbcfg, ff, data, data_len);
819
843k
            SCReturnInt(r);
820
843k
        }
821
843k
    }
822
843k
    SCReturnInt(-1);
823
843k
}
824
825
/**
826
 *  \brief Store/handle a chunk of file data in the File structure
827
 *         The file with 'track_id' in the FileContainer will be used.
828
 *
829
 *  \param ffc FileContainer used to append to
830
 *  \param track_id id to lookup the file
831
 *  \param data data chunk
832
 *  \param data_len data chunk len
833
 *
834
 *  \retval  0 ok
835
 *  \retval -1 error
836
 *  \retval -2 no store for this file
837
 */
838
int FileAppendGAPById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id,
839
        const uint8_t *data, uint32_t data_len)
840
588
{
841
588
    SCEnter();
842
843
588
    if (ffc == NULL || ffc->tail == NULL || data == NULL || data_len == 0) {
844
25
        SCReturnInt(-1);
845
25
    }
846
563
    File *ff = ffc->head;
847
563
    for ( ; ff != NULL; ff = ff->next) {
848
563
        if (track_id == ff->file_track_id) {
849
563
            FileFlagGap(ff);
850
563
            SCLogDebug("FILE_HAS_GAPS set");
851
852
563
            int r = FileAppendDataDo(sbcfg, ff, data, data_len);
853
563
            SCReturnInt(r);
854
563
        }
855
563
    }
856
563
    SCReturnInt(-1);
857
563
}
858
859
void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min)
860
2.03M
{
861
2.03M
    file->inspect_window = win;
862
2.03M
    file->inspect_min_size = min;
863
2.03M
}
864
865
/**
866
 *  \brief Sets the offset range for a file.
867
 *
868
 *  \param ffc the container
869
 *  \param start start offset
870
 *  \param end end offset
871
 *
872
 *  \retval  0 ok
873
 *  \retval -1 error
874
 */
875
int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end)
876
19.3k
{
877
19.3k
    SCEnter();
878
879
19.3k
    if (ffc == NULL || ffc->tail == NULL) {
880
0
        SCReturnInt(-1);
881
0
    }
882
19.3k
    ffc->tail->start = start;
883
19.3k
    ffc->tail->end = end;
884
19.3k
    SCReturnInt(0);
885
19.3k
}
886
887
/**
888
 *  \brief Open a new File
889
 *
890
 *  \param ffc flow container
891
 *  \param sbcfg buffer config
892
 *  \param name filename character array
893
 *  \param name_len filename len
894
 *  \param data initial data
895
 *  \param data_len initial data len
896
 *  \param flags open flags
897
 *
898
 *  \retval ff flowfile object
899
 *
900
 *  \note filename is not a string, so it's not nul terminated.
901
 */
902
static File *FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg,
903
        const uint8_t *name, uint16_t name_len,
904
        const uint8_t *data, uint32_t data_len, uint16_t flags)
905
1.38M
{
906
1.38M
    SCEnter();
907
908
    //PrintRawDataFp(stdout, name, name_len);
909
910
1.38M
    File *ff = FileAlloc(name, name_len);
911
1.38M
    if (ff == NULL) {
912
0
        SCReturnPtr(NULL, "File");
913
0
    }
914
915
1.38M
    ff->sb = StreamingBufferInit(sbcfg);
916
1.38M
    if (ff->sb == NULL) {
917
0
        FileFree(ff, sbcfg);
918
0
        SCReturnPtr(NULL, "File");
919
0
    }
920
1.38M
    SCLogDebug("ff->sb %p", ff->sb);
921
922
1.38M
    if (flags & FILE_STORE || g_file_force_filestore) {
923
180k
        FileStore(ff);
924
1.20M
    } else if (flags & FILE_NOSTORE) {
925
0
        SCLogDebug("not storing this file");
926
0
        ff->flags |= FILE_NOSTORE;
927
0
    }
928
1.38M
    if (flags & FILE_NOMAGIC) {
929
84.2k
        SCLogDebug("not doing magic for this file");
930
84.2k
        ff->flags |= FILE_NOMAGIC;
931
84.2k
    }
932
1.38M
    if (flags & FILE_NOMD5) {
933
177k
        SCLogDebug("not doing md5 for this file");
934
177k
        ff->flags |= FILE_NOMD5;
935
177k
    }
936
1.38M
    if (flags & FILE_NOSHA1) {
937
177k
        SCLogDebug("not doing sha1 for this file");
938
177k
        ff->flags |= FILE_NOSHA1;
939
177k
    }
940
1.38M
    if (flags & FILE_NOSHA256) {
941
0
        SCLogDebug("not doing sha256 for this file");
942
0
        ff->flags |= FILE_NOSHA256;
943
0
    }
944
945
1.38M
    if (!(ff->flags & FILE_NOMD5) || g_file_force_md5) {
946
1.20M
        ff->md5_ctx = SCMd5New();
947
1.20M
    }
948
1.38M
    if (!(ff->flags & FILE_NOSHA1) || g_file_force_sha1) {
949
1.20M
        ff->sha1_ctx = SCSha1New();
950
1.20M
    }
951
1.38M
    if (!(ff->flags & FILE_NOSHA256) || g_file_force_sha256) {
952
1.38M
        ff->sha256_ctx = SCSha256New();
953
1.38M
        SCLogDebug("ff %p ff->sha256_ctx %p", ff, ff->sha256_ctx);
954
1.38M
    }
955
956
1.38M
    ff->state = FILE_STATE_OPENED;
957
1.38M
    SCLogDebug("flowfile state transitioned to FILE_STATE_OPENED");
958
959
1.38M
    ff->fd = -1;
960
961
1.38M
    FileContainerAdd(ffc, ff);
962
963
    /* set default window and min inspection size */
964
1.38M
    FileSetInspectSizes(ff, FILEDATA_CONTENT_INSPECT_WINDOW, FILEDATA_CONTENT_INSPECT_MIN_SIZE);
965
966
1.38M
    ff->size += data_len;
967
1.38M
    if (data != NULL) {
968
471k
        if (AppendData(sbcfg, ff, data, data_len) != 0) {
969
0
            ff->state = FILE_STATE_ERROR;
970
0
            SCReturnPtr(NULL, "File");
971
0
        }
972
471k
        SCLogDebug("file size is now %"PRIu64, FileTrackedSize(ff));
973
909k
    } else if (data_len > 0) {
974
146
        FileFlagGap(ff);
975
146
    }
976
977
1.38M
    SCReturnPtr(ff, "File");
978
1.38M
}
979
980
/**
981
 *  \retval 0 ok
982
 *  \retval -1 failed */
983
int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg,
984
        uint32_t track_id, const uint8_t *name, uint16_t name_len,
985
        const uint8_t *data, uint32_t data_len, uint16_t flags)
986
1.38M
{
987
1.38M
    SCLogDebug("ffc %p track_id %u", ffc, track_id);
988
1.38M
    File *ff = FileOpenFile(ffc, sbcfg, name, name_len, data, data_len, flags);
989
1.38M
    if (ff == NULL)
990
0
        return -1;
991
992
1.38M
    ff->file_track_id = track_id;
993
1.38M
    return 0;
994
1.38M
}
995
996
int FileCloseFilePtr(File *ff, const StreamingBufferConfig *sbcfg, const uint8_t *data,
997
        uint32_t data_len, uint16_t flags)
998
1.18M
{
999
1.18M
    SCEnter();
1000
1001
1.18M
    if (ff == NULL) {
1002
0
        SCReturnInt(-1);
1003
0
    }
1004
1005
1.18M
    if (ff->state != FILE_STATE_OPENED) {
1006
450
        SCReturnInt(-1);
1007
450
    }
1008
1009
1.18M
    ff->size += data_len;
1010
1.18M
    if (data != NULL) {
1011
125k
        if (AppendData(sbcfg, ff, data, data_len) != 0) {
1012
0
            ff->state = FILE_STATE_ERROR;
1013
0
            SCReturnInt(-1);
1014
0
        }
1015
125k
    }
1016
1017
1.18M
    if ((flags & FILE_TRUNCATED) || (ff->flags & FILE_HAS_GAPS)) {
1018
21.3k
        SCLogDebug("flags FILE_TRUNCATED %s", (flags & FILE_TRUNCATED) ? "true" : "false");
1019
21.3k
        SCLogDebug("ff->flags FILE_HAS_GAPS %s", (ff->flags & FILE_HAS_GAPS) ? "true" : "false");
1020
1021
21.3k
        ff->state = FILE_STATE_TRUNCATED;
1022
21.3k
        SCLogDebug("flowfile state transitioned to FILE_STATE_TRUNCATED");
1023
1024
21.3k
        if (flags & FILE_NOSTORE) {
1025
0
            SCLogDebug("not storing this file");
1026
0
            ff->flags |= FILE_NOSTORE;
1027
21.3k
        } else {
1028
21.3k
            if (g_file_force_sha256 && ff->sha256_ctx) {
1029
4.80k
                SCLogDebug("file %p data %p data_len %u", ff, data, data_len);
1030
4.80k
                FileEndSha256(ff);
1031
4.80k
            }
1032
21.3k
        }
1033
1.16M
    } else {
1034
1.16M
        ff->state = FILE_STATE_CLOSED;
1035
1.16M
        SCLogDebug("flowfile state transitioned to FILE_STATE_CLOSED");
1036
1037
1.16M
        if (ff->md5_ctx) {
1038
1.00M
            SCMd5Finalize(ff->md5_ctx, ff->md5, sizeof(ff->md5));
1039
1.00M
            ff->md5_ctx = NULL;
1040
1.00M
            ff->flags |= FILE_MD5;
1041
1.00M
        }
1042
1.16M
        if (ff->sha1_ctx) {
1043
1.00M
            SCSha1Finalize(ff->sha1_ctx, ff->sha1, sizeof(ff->sha1));
1044
1.00M
            ff->sha1_ctx = NULL;
1045
1.00M
            ff->flags |= FILE_SHA1;
1046
1.00M
        }
1047
1.16M
        if (ff->sha256_ctx) {
1048
1.16M
            SCLogDebug("file %p data %p data_len %u", ff, data, data_len);
1049
1.16M
            FileEndSha256(ff);
1050
1.16M
        }
1051
1.16M
    }
1052
1053
1.18M
    SCReturnInt(0);
1054
1.18M
}
1055
1056
/**
1057
 *  \brief Close a File
1058
 *
1059
 *  \param ffc the container
1060
 *  \param data final data if any
1061
 *  \param data_len data len if any
1062
 *  \param flags flags
1063
 *
1064
 *  \retval 0 ok
1065
 *  \retval -1 error
1066
 */
1067
int FileCloseFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data,
1068
        uint32_t data_len, uint16_t flags)
1069
640k
{
1070
640k
    SCEnter();
1071
1072
640k
    if (ffc == NULL || ffc->tail == NULL) {
1073
126
        SCReturnInt(-1);
1074
126
    }
1075
1076
640k
    if (FileCloseFilePtr(ffc->tail, sbcfg, data, data_len, flags) == -1) {
1077
5
        SCReturnInt(-1);
1078
5
    }
1079
1080
640k
    SCReturnInt(0);
1081
640k
}
1082
1083
int FileCloseFileById(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id,
1084
        const uint8_t *data, uint32_t data_len, uint16_t flags)
1085
544k
{
1086
544k
    SCEnter();
1087
1088
544k
    if (ffc == NULL || ffc->tail == NULL) {
1089
664
        SCReturnInt(-1);
1090
664
    }
1091
1092
543k
    File *ff = ffc->head;
1093
543k
    for ( ; ff != NULL; ff = ff->next) {
1094
543k
        if (track_id == ff->file_track_id) {
1095
543k
            int r = FileCloseFilePtr(ff, sbcfg, data, data_len, flags);
1096
543k
            SCReturnInt(r);
1097
543k
        }
1098
543k
    }
1099
543k
    SCReturnInt(-1);
1100
543k
}
1101
1102
/** \brief set a flow's file flags
1103
 *  \param set_file_flags flags in both directions that are requested to set
1104
 *
1105
 *  This function will ignore the flags for the irrelevant direction and
1106
 *  also mask the flags with the global settings.
1107
 */
1108
void FileUpdateFlowFileFlags(Flow *f, uint16_t set_file_flags, uint8_t direction)
1109
823k
{
1110
823k
    SCEnter();
1111
823k
    DEBUG_ASSERT_FLOW_LOCKED(f);
1112
1113
    /* remove flags not in our direction and
1114
       don't disable what is globally enabled */
1115
823k
    if (direction == STREAM_TOSERVER) {
1116
487k
        set_file_flags &= ~(FLOWFILE_NONE_TC|g_file_flow_mask);
1117
487k
    } else {
1118
335k
        set_file_flags &= ~(FLOWFILE_NONE_TS|g_file_flow_mask);
1119
335k
    }
1120
823k
    f->file_flags |= set_file_flags;
1121
1122
823k
    SCLogDebug("f->file_flags %04x set_file_flags %04x g_file_flow_mask %04x",
1123
823k
            f->file_flags, set_file_flags, g_file_flow_mask);
1124
1125
823k
    if (set_file_flags != 0 && f->alproto != ALPROTO_UNKNOWN && f->alstate != NULL) {
1126
141k
        AppLayerStateData *sd = AppLayerParserGetStateData(f->proto, f->alproto, f->alstate);
1127
141k
        if (sd != NULL) {
1128
141k
            if ((sd->file_flags & f->file_flags) != f->file_flags) {
1129
112k
                SCLogDebug("state data: updating file_flags %04x with flow file_flags %04x",
1130
112k
                        sd->file_flags, f->file_flags);
1131
112k
                sd->file_flags |= f->file_flags;
1132
112k
            }
1133
141k
        }
1134
141k
    }
1135
823k
}
1136
1137
/**
1138
 *  \brief disable file storing for files in a transaction
1139
 *
1140
 *  \param f *LOCKED* flow
1141
 *  \param direction flow direction
1142
 *  \param tx_id transaction id
1143
 */
1144
void FileDisableStoringForTransaction(Flow *f, const uint8_t direction, void *tx, uint64_t tx_id)
1145
20.5k
{
1146
20.5k
    if (g_file_force_filestore == 0) {
1147
0
        AppLayerTxData *txd = AppLayerParserGetTxData(f->proto, f->alproto, tx);
1148
0
        if (txd != NULL) {
1149
0
            if (direction & STREAM_TOSERVER) {
1150
0
                txd->file_flags |= FLOWFILE_NO_STORE_TS;
1151
0
            } else {
1152
0
                txd->file_flags |= FLOWFILE_NO_STORE_TC;
1153
0
            }
1154
0
        }
1155
0
    }
1156
20.5k
}
1157
1158
/**
1159
 *  \brief flag a file with id "file_id" to be stored.
1160
 *
1161
 *  \param fc file store
1162
 *  \param file_id the file's id
1163
 */
1164
void FileStoreFileById(FileContainer *fc, uint32_t file_id)
1165
40.3k
{
1166
40.3k
    File *ptr = NULL;
1167
1168
40.3k
    SCEnter();
1169
1170
40.3k
    if (fc != NULL) {
1171
80.6k
        for (ptr = fc->head; ptr != NULL; ptr = ptr->next) {
1172
40.3k
            if (ptr->file_track_id == file_id) {
1173
40.3k
                FileStore(ptr);
1174
40.3k
            }
1175
40.3k
        }
1176
40.3k
    }
1177
40.3k
}
1178
1179
static void FileTruncateAllOpenFiles(FileContainer *fc, const StreamingBufferConfig *sbcfg)
1180
394
{
1181
394
    File *ptr = NULL;
1182
1183
394
    SCEnter();
1184
1185
394
    if (fc != NULL) {
1186
535
        for (ptr = fc->head; ptr != NULL; ptr = ptr->next) {
1187
141
            if (ptr->state == FILE_STATE_OPENED) {
1188
0
                FileCloseFilePtr(ptr, sbcfg, NULL, 0, FILE_TRUNCATED);
1189
0
            }
1190
141
        }
1191
394
    }
1192
394
}
1193
1194
void FilesPrune(FileContainer *fc, const StreamingBufferConfig *sbcfg, const bool trunc)
1195
111M
{
1196
111M
    if (trunc) {
1197
394
        FileTruncateAllOpenFiles(fc, sbcfg);
1198
394
    }
1199
111M
    FilePrune(fc, sbcfg);
1200
111M
}
1201
1202
/**
1203
 * \brief Finish the SHA256 calculation.
1204
 */
1205
static void FileEndSha256(File *ff)
1206
1.16M
{
1207
1.16M
    SCLogDebug("ff %p ff->size %" PRIu64, ff, ff->size);
1208
1.16M
    if (!(ff->flags & FILE_SHA256) && ff->sha256_ctx) {
1209
1.16M
        SCSha256Finalize(ff->sha256_ctx, ff->sha256, sizeof(ff->sha256));
1210
1.16M
        ff->sha256_ctx = NULL;
1211
1.16M
        ff->flags |= FILE_SHA256;
1212
1.16M
    }
1213
1.16M
}