Coverage Report

Created: 2026-04-13 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sleuthkit/tsk/fs/fatfs_meta.cpp
Line
Count
Source
1
/*
2
** fatfs
3
** The Sleuth Kit
4
**
5
** Meta data layer support for the FAT file system.
6
**
7
** Brian Carrier [carrier <at> sleuthkit [dot] org]
8
** Copyright (c) 2006-2013 Brian Carrier, Basis Technology.  All Rights reserved
9
** Copyright (c) 2003-2005 Brian Carrier.  All rights reserved
10
**
11
** TASK
12
** Copyright (c) 2002 Brian Carrier, @stake Inc.  All rights reserved
13
**
14
**
15
** This software is distributed under the Common Public License 1.0
16
**
17
** Unicode added with support from I.D.E.A.L. Technology Corp (Aug '05)
18
**
19
*/
20
21
/**
22
 * \file fatfs_meta.c
23
 * Meta data layer support for FAT file systems.
24
 */
25
26
#include "tsk_fatfs.h"
27
#include "tsk_fatxxfs.h"
28
#include "tsk_exfatfs.h"
29
30
#include <memory>
31
32
TSK_FS_ATTR_TYPE_ENUM
33
fatfs_get_default_attr_type([[maybe_unused]] const TSK_FS_FILE * a_file)
34
7.49k
{
35
7.49k
    return TSK_FS_ATTR_TYPE_DEFAULT;
36
7.49k
}
37
38
/**
39
 * \internal
40
 * Create an TSK_FS_META structure for the root directory.  FAT does
41
 * not have a directory entry for the root directory, but this
42
 * function collects the data needed to make one.
43
 *
44
 * @param fatfs File system to analyze.
45
 * @param fs_meta Inode structure to copy root directory information into.
46
 * @return 1 on error and 0 on success
47
 */
48
static uint8_t
49
fatfs_make_root(FATFS_INFO *a_fatfs, TSK_FS_META *a_fs_meta)
50
173
{
51
173
    const char *func_name = "fatfs_make_root";
52
173
    TSK_DADDR_T *first_clust_addr_ptr = NULL;
53
54
173
    tsk_error_reset();
55
173
    if (fatfs_ptr_arg_is_null(a_fatfs, "a_fatfs", func_name) ||
56
173
        fatfs_ptr_arg_is_null(a_fs_meta, "a_fs_meta", func_name)) {
57
0
        return 1;
58
0
    }
59
60
    /* Manufacture some metadata. */
61
173
    a_fs_meta->type = TSK_FS_META_TYPE_DIR;
62
173
    a_fs_meta->mode = TSK_FS_META_MODE_UNSPECIFIED;
63
173
    a_fs_meta->nlink = 1;
64
173
    a_fs_meta->addr = FATFS_ROOTINO;
65
173
    a_fs_meta->flags = (TSK_FS_META_FLAG_ENUM)(TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_ALLOC);
66
173
    a_fs_meta->uid = a_fs_meta->gid = 0;
67
173
    a_fs_meta->mtime = a_fs_meta->atime = a_fs_meta->ctime = a_fs_meta->crtime = 0;
68
173
    a_fs_meta->mtime_nano = a_fs_meta->atime_nano = a_fs_meta->ctime_nano =
69
173
        a_fs_meta->crtime_nano = 0;
70
71
    /* Give the root directory an empty name. */
72
173
    if (a_fs_meta->name2 == NULL) {
73
173
        if ((a_fs_meta->name2 = (TSK_FS_META_NAME_LIST *)
74
173
                tsk_malloc(sizeof(TSK_FS_META_NAME_LIST))) == NULL) {
75
0
            return 1;
76
0
        }
77
173
        a_fs_meta->name2->next = NULL;
78
173
    }
79
173
    a_fs_meta->name2->name[0] = '\0';
80
81
    /* Mark the generic attribute list as not in use (in the generic file model
82
     * attributes are containers for data or metadata). Population of this
83
     * list is done by lazy look up. */
84
173
    a_fs_meta->attr_state = TSK_FS_META_ATTR_EMPTY;
85
173
    if (a_fs_meta->attr) {
86
0
        tsk_fs_attrlist_markunused(a_fs_meta->attr);
87
0
    }
88
89
    /* Determine the size of the root directory and the address of its
90
     * first cluster. */
91
173
    first_clust_addr_ptr = (TSK_DADDR_T*)a_fs_meta->content_ptr;
92
173
    if (a_fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32 ||
93
173
        a_fatfs->fs_info.ftype == TSK_FS_TYPE_EXFAT) {
94
30
        TSK_DADDR_T cnum = 0;
95
30
        TSK_DADDR_T clust = 0;
96
30
        TSK_LIST *list_seen = NULL;
97
98
        /* Convert the address of the first sector of the root directory into
99
         * the address of its first cluster. */
100
30
        clust = FATFS_SECT_2_CLUST(a_fatfs, a_fatfs->rootsect);
101
30
        first_clust_addr_ptr[0] = clust;
102
103
        /* Walk the FAT and count the clusters allocated to the root directory. */
104
30
        cnum = 0;
105
60
        while ((clust) && (0 == FATFS_ISEOF(clust, FATFS_32_MASK))) {
106
30
            TSK_DADDR_T nxt = 0;
107
108
            /* Make sure we do not get into an infinite loop */
109
30
            if (tsk_list_find(list_seen, clust)) {
110
0
                if (tsk_verbose) {
111
0
                    tsk_fprintf(stderr,
112
0
                        "Loop found while determining root directory size\n");
113
0
                }
114
0
                break;
115
0
            }
116
30
            if (tsk_list_add(&list_seen, clust)) {
117
0
                tsk_list_free(list_seen);
118
0
                list_seen = NULL;
119
0
                return 1;
120
0
            }
121
122
30
            cnum++;
123
30
            if (fatfs_getFAT(a_fatfs, clust, &nxt)) {
124
0
                break;
125
0
            }
126
30
            else {
127
30
                clust = nxt;
128
30
            }
129
30
        }
130
30
        tsk_list_free(list_seen);
131
30
        list_seen = NULL;
132
133
        /* Calculate the size of the root directory. */
134
30
        a_fs_meta->size = (cnum * a_fatfs->csize) << a_fatfs->ssize_sh;
135
30
    }
136
143
    else {
137
        /* FAT12 and FAT16 don't use the FAT for the root directory, so set
138
         * the first cluster address to a distinguished value that other code
139
         * will have to check as a special condition. */
140
143
        first_clust_addr_ptr[0] = 1;
141
142
        /* Set the size equal to the number of bytes between the end of the
143
         * FATs and the start of the clusters. */
144
143
        a_fs_meta->size = (a_fatfs->firstclustsect - a_fatfs->firstdatasect) << a_fatfs->ssize_sh;
145
143
    }
146
147
173
    return 0;
148
173
}
149
150
/**
151
* \internal
152
 * Create an TSK_FS_META structure for the master boot record.
153
 *
154
 * @param fatfs File system to analyze
155
 * @param fs_meta Inode structure to copy file information into.
156
 * @return 1 on error and 0 on success
157
 */
158
static uint8_t
159
fatfs_make_mbr(FATFS_INFO *fatfs, TSK_FS_META *fs_meta)
160
79
{
161
79
    TSK_DADDR_T *addr_ptr;
162
163
79
    fs_meta->type = TSK_FS_META_TYPE_VIRT;
164
79
    fs_meta->mode = TSK_FS_META_MODE_UNSPECIFIED;
165
79
    fs_meta->nlink = 1;
166
79
    fs_meta->addr = fatfs->mbr_virt_inum;
167
79
    fs_meta->flags = (TSK_FS_META_FLAG_ENUM)
168
79
        (TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_ALLOC);
169
79
    fs_meta->uid = fs_meta->gid = 0;
170
79
    fs_meta->mtime = fs_meta->atime = fs_meta->ctime = fs_meta->crtime = 0;
171
79
    fs_meta->mtime_nano = fs_meta->atime_nano = fs_meta->ctime_nano =
172
79
        fs_meta->crtime_nano = 0;
173
174
79
    if (fs_meta->name2 == NULL) {
175
79
        if ((fs_meta->name2 = (TSK_FS_META_NAME_LIST *)
176
79
                tsk_malloc(sizeof(TSK_FS_META_NAME_LIST))) == NULL) {
177
0
            return 1;
178
0
        }
179
79
        fs_meta->name2->next = NULL;
180
79
    }
181
79
    strncpy(fs_meta->name2->name, FATFS_MBRNAME,
182
79
        TSK_FS_META_NAME_LIST_NSIZE);
183
184
79
    fs_meta->attr_state = TSK_FS_META_ATTR_EMPTY;
185
79
    if (fs_meta->attr) {
186
0
        tsk_fs_attrlist_markunused(fs_meta->attr);
187
0
    }
188
189
79
    addr_ptr = (TSK_DADDR_T*)fs_meta->content_ptr;
190
79
    addr_ptr[0] = 0;
191
79
    fs_meta->size = 512;
192
193
79
    return 0;
194
79
}
195
196
/**
197
* \internal
198
 * Create an TSK_FS_META structure for the FAT tables.
199
 *
200
 * @param fatfs File system to analyze
201
 * @param a_which 1 or 2 to choose between defining FAT1 or FAT2
202
 * @param fs_meta Inode structure to copy file information into.
203
 * @return 1 on error and 0 on success
204
 */
205
static uint8_t
206
fatfs_make_fat(FATFS_INFO *fatfs, uint8_t a_which, TSK_FS_META *fs_meta)
207
99
{
208
99
    TSK_FS_INFO *fs = (TSK_FS_INFO*)fatfs;
209
99
    TSK_DADDR_T *addr_ptr = (TSK_DADDR_T *)fs_meta->content_ptr;
210
211
99
    if ((a_which != 1) && (a_which != 2)) {
212
0
        return 1;
213
0
    }
214
215
99
    if (a_which > fatfs->numfat) {
216
0
        return 1;
217
0
    }
218
219
99
    fs_meta->type = TSK_FS_META_TYPE_VIRT;
220
99
    fs_meta->mode = TSK_FS_META_MODE_UNSPECIFIED;
221
99
    fs_meta->nlink = 1;
222
223
99
    fs_meta->flags = (TSK_FS_META_FLAG_ENUM)
224
99
        (TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_ALLOC);
225
99
    fs_meta->uid = fs_meta->gid = 0;
226
99
    fs_meta->mtime = fs_meta->atime = fs_meta->ctime = fs_meta->crtime = 0;
227
99
    fs_meta->mtime_nano = fs_meta->atime_nano = fs_meta->ctime_nano =
228
99
        fs_meta->crtime_nano = 0;
229
230
99
    if (fs_meta->name2 == NULL) {
231
99
        if ((fs_meta->name2 = (TSK_FS_META_NAME_LIST *)
232
99
                tsk_malloc(sizeof(TSK_FS_META_NAME_LIST))) == NULL)
233
0
            return 1;
234
99
        fs_meta->name2->next = NULL;
235
99
    }
236
237
99
    if (a_which == 1) {
238
79
        fs_meta->addr = fatfs->fat1_virt_inum;
239
79
        strncpy(fs_meta->name2->name, FATFS_FAT1NAME,
240
79
            TSK_FS_META_NAME_LIST_NSIZE);
241
79
        addr_ptr[0] = fatfs->firstfatsect;
242
79
    }
243
20
    else {
244
20
        fs_meta->addr = fatfs->fat2_virt_inum;
245
20
        strncpy(fs_meta->name2->name, FATFS_FAT2NAME,
246
20
            TSK_FS_META_NAME_LIST_NSIZE);
247
20
        addr_ptr[0] = fatfs->firstfatsect + fatfs->sectperfat;
248
20
    }
249
250
99
    fs_meta->attr_state = TSK_FS_META_ATTR_EMPTY;
251
99
    if (fs_meta->attr) {
252
0
        tsk_fs_attrlist_markunused(fs_meta->attr);
253
0
    }
254
255
99
    fs_meta->size = fatfs->sectperfat * fs->block_size;
256
257
99
    return 0;
258
99
}
259
260
/**
261
 * \internal
262
 * Load a FATFS_DENTRY structure with the bytes at a given inode address.
263
 *
264
 * @param [in] a_fs The file system from which to read the bytes.
265
 * @param [out] a_de The FATFS_DENTRY.
266
 * @param [in] a_inum An inode address.
267
 * @return 0 on success, 1 on failure.
268
 */
269
uint8_t
270
fatfs_dentry_load(FATFS_INFO *a_fatfs, FATFS_DENTRY *a_dentry, TSK_INUM_T a_inum)
271
461k
{
272
461k
    const char *func_name = "fatfs_dentry_load";
273
461k
    TSK_FS_INFO *fs = (TSK_FS_INFO*)a_fatfs;
274
461k
    TSK_DADDR_T sect = 0;
275
461k
    size_t off = 0;
276
461k
    ssize_t cnt = 0;
277
278
461k
    tsk_error_reset();
279
461k
    if (fatfs_ptr_arg_is_null(a_fatfs, "a_fatfs", func_name) ||
280
461k
        fatfs_ptr_arg_is_null(a_dentry, "a_dentry", func_name) ||
281
461k
        !fatfs_inum_arg_is_in_range(a_fatfs, a_inum, func_name)) {
282
0
        return 1;
283
0
    }
284
285
    /* Map the inode address to a sector. */
286
461k
    sect = FATFS_INODE_2_SECT(a_fatfs, a_inum);
287
461k
    if (sect > fs->last_block) {
288
0
        tsk_error_reset();
289
0
        tsk_error_set_errno(TSK_ERR_FS_INODE_NUM);
290
0
        tsk_error_set_errstr("%s: Inode %" PRIuINUM
291
0
            " in sector too big for image: %" PRIuDADDR, func_name, a_inum, sect);
292
0
        return 1;
293
0
    }
294
295
    /* Get the byte offset of the inode address within the sector. */
296
461k
    off = FATFS_INODE_2_OFF(a_fatfs, a_inum);
297
298
    /* Read in the bytes. */
299
461k
    cnt = tsk_fs_read(fs, sect * fs->block_size + off, (char*)a_dentry, sizeof(FATFS_DENTRY));
300
461k
    if (cnt != sizeof(FATFS_DENTRY)) {
301
0
        if (cnt >= 0) {
302
0
            tsk_error_reset();
303
0
            tsk_error_set_errno(TSK_ERR_FS_READ);
304
0
        }
305
0
        tsk_error_set_errstr2("%s: block: %" PRIuDADDR,
306
0
            func_name, sect);
307
0
        return 1;
308
0
    }
309
310
461k
    return 0;
311
461k
}
312
313
/**
314
 * \internal
315
 * Populate the TSK_FS_META structure of a TSK_FS_FILE structure for a
316
 * given inode address.
317
 *
318
 * @param [in] a_fs File system that contains the inode.
319
 * @param [out] a_fs_file The file corresponding to the inode.
320
 * @param [in] a_inum The inode address.
321
 * @returns 1 if an error occurs or if the inode address is not
322
 * for a valid inode, 0 otherwise.
323
 */
324
uint8_t
325
fatfs_inode_lookup(TSK_FS_INFO *a_fs, TSK_FS_FILE *a_fs_file,
326
    TSK_INUM_T a_inum)
327
433k
{
328
433k
    const char *func_name = "fatfs_inode_lookup";
329
433k
    FATFS_INFO *fatfs = (FATFS_INFO*)a_fs;
330
331
433k
    tsk_error_reset();
332
433k
    if (fatfs_ptr_arg_is_null(a_fs, "a_fs", func_name) ||
333
433k
        fatfs_ptr_arg_is_null(a_fs_file, "a_fs_file", func_name) ||
334
433k
        !fatfs_inum_arg_is_in_range(fatfs, a_inum, func_name)) {
335
0
        return 1;
336
0
    }
337
338
    /* Allocate or reset the TSK_FS_META struct. */
339
433k
    if (a_fs_file->meta == NULL) {
340
433k
        if ((a_fs_file->meta =
341
433k
                tsk_fs_meta_alloc(FATFS_FILE_CONTENT_LEN)) == NULL) {
342
0
            return 1;
343
0
        }
344
433k
    }
345
0
    else {
346
0
        tsk_fs_meta_reset(a_fs_file->meta);
347
0
    }
348
349
    /* Manufacture an inode for the root directory or a FAT virtual file,
350
     * or do a look up. */
351
433k
    if (a_inum == a_fs->root_inum) {
352
143
        if (fatfs_make_root(fatfs, a_fs_file->meta))
353
0
            return 1;
354
143
        else
355
143
            return 0;
356
143
    }
357
433k
    else if (a_inum == fatfs->mbr_virt_inum) {
358
79
        if (fatfs_make_mbr(fatfs, a_fs_file->meta))
359
0
            return 1;
360
79
        else
361
79
            return 0;
362
79
    }
363
433k
    else if (a_inum == fatfs->fat1_virt_inum) {
364
79
        if (fatfs_make_fat(fatfs, 1, a_fs_file->meta))
365
0
            return 1;
366
79
        else
367
79
            return 0;
368
79
    }
369
433k
    else if (a_inum == fatfs->fat2_virt_inum && fatfs->numfat == 2) {
370
20
        if (fatfs_make_fat(fatfs, 2, a_fs_file->meta))
371
0
            return 1;
372
20
        else
373
20
            return 0;
374
20
    }
375
433k
    else if (a_inum == TSK_FS_ORPHANDIR_INUM(a_fs)) {
376
153
        if (tsk_fs_dir_make_orphan_dir_meta(a_fs, a_fs_file->meta))
377
0
            return 1;
378
153
        else
379
153
            return 0;
380
153
    }
381
433k
    else {
382
433k
        return fatfs->inode_lookup(fatfs, a_fs_file, a_inum);
383
433k
    }
384
433k
}
385
386
/** \internal
387
 * Make data runs out of the clusters allocated to a file represented by a
388
 * TSK_FS_FILE structure. Each data run will have a starting sector and a
389
 * length in sectors. The runs will be stored as a non-resident attribute in
390
 * the TSK_FS_ATTRLIST of the TSK_FS_META structure of the TSK_FS_FILE.
391
 *
392
 * @param a_fs_file A representation of a file.
393
 * @return 1 on error and 0 on success
394
 */
395
uint8_t
396
fatfs_make_data_runs(TSK_FS_FILE * a_fs_file)
397
8.36k
{
398
8.36k
    const char *func_name = "fatfs_make_data_runs";
399
8.36k
    TSK_FS_INFO *fs = NULL;
400
8.36k
    TSK_FS_META *fs_meta = NULL;
401
8.36k
    FATFS_INFO *fatfs = NULL;
402
8.36k
    TSK_DADDR_T clust = 0;
403
8.36k
    TSK_OFF_T size_remain = 0;
404
8.36k
    TSK_FS_ATTR *fs_attr = NULL;
405
406
8.36k
    if ((fatfs_ptr_arg_is_null(a_fs_file, "a_fs_file", func_name)) ||
407
8.36k
        (fatfs_ptr_arg_is_null(a_fs_file->meta, "a_fs_file->meta", func_name)) ||
408
8.36k
        (fatfs_ptr_arg_is_null(a_fs_file->fs_info, "a_fs_file->fs_info", func_name))) {
409
0
        return TSK_ERR;
410
0
    }
411
412
8.36k
    fs_meta = a_fs_file->meta;
413
8.36k
    fs = a_fs_file->fs_info;
414
8.36k
    fatfs = (FATFS_INFO*)fs;
415
416
    /* Check for an already populated attribute list, since a lazy strategy
417
     * is used to fill in attributes. If the attribute list is not yet
418
     * allocated, do so now. */
419
8.36k
    if ((fs_meta->attr != NULL)
420
0
        && (fs_meta->attr_state == TSK_FS_META_ATTR_STUDIED)) {
421
0
        return 0;
422
0
    }
423
8.36k
    else if (fs_meta->attr_state == TSK_FS_META_ATTR_ERROR) {
424
0
        return 1;
425
0
    }
426
427
8.36k
    if (fs_meta->attr != NULL) {
428
0
        tsk_fs_attrlist_markunused(fs_meta->attr);
429
0
    }
430
8.36k
    else  {
431
8.36k
        fs_meta->attr = tsk_fs_attrlist_alloc();
432
8.36k
    }
433
434
    /* Get the stashed first cluster address of the file. */
435
8.36k
    clust = ((TSK_DADDR_T*)fs_meta->content_ptr)[0];
436
8.36k
    if ((clust > (fatfs->lastclust)) &&
437
876
        (FATFS_ISEOF(clust, fatfs->mask) == 0)) {
438
849
        fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
439
849
        tsk_error_reset();
440
849
        if (a_fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC) {
441
122
            tsk_error_set_errno(TSK_ERR_FS_RECOVER);
442
122
        }
443
727
        else {
444
727
            tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
445
727
        }
446
849
        tsk_error_set_errstr
447
849
            ("%s: Starting cluster address too large: %"
448
849
            PRIuDADDR, func_name, clust);
449
849
        return 1;
450
849
    }
451
452
    /* Figure out the allocated length of the file in bytes. Because the
453
     * allocation unit for FAT file systems is the cluster, round the
454
     * size up to a multiple of cluster size. */
455
7.51k
    size_remain = roundup(fs_meta->size, fatfs->csize * fs->block_size);
456
457
7.51k
    if ((a_fs_file->meta->addr == fs->root_inum) &&
458
157
        (fs->ftype != TSK_FS_TYPE_FAT32) &&
459
157
        (fs->ftype != TSK_FS_TYPE_EXFAT) &&
460
127
        (clust == 1)) {
461
        /* Make a single contiguous data run for a FAT12 or FAT16 root
462
         * directory. The root directory for these file systems is not
463
         * tracked in the FAT. */
464
127
        TSK_FS_ATTR_RUN *data_run;
465
466
127
        if (tsk_verbose) {
467
0
            tsk_fprintf(stderr,
468
0
                "%s: Loading root directory\n", func_name);
469
0
        }
470
471
        /* Allocate the run. */
472
127
        data_run = tsk_fs_attr_run_alloc();
473
127
        if (data_run == NULL) {
474
0
            return 1;
475
0
        }
476
477
        /* Set the starting sector address and run length. The run begins with
478
         * the first sector of the data area. */
479
127
        data_run->addr = fatfs->rootsect;
480
127
        data_run->len = fatfs->firstclustsect - fatfs->firstdatasect;
481
482
        /* Allocate a non-resident attribute to hold the run and add it
483
         to the attribute list. */
484
127
        if ((fs_attr =
485
127
                tsk_fs_attrlist_getnew(fs_meta->attr,
486
127
                    TSK_FS_ATTR_NONRES)) == NULL) {
487
0
            return 1;
488
0
        }
489
490
        /* Tie everything together. */
491
127
        if (tsk_fs_attr_set_run(a_fs_file, fs_attr, data_run, NULL,
492
127
                TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
493
127
                data_run->len * fs->block_size,
494
127
                data_run->len * fs->block_size,
495
127
                data_run->len * fs->block_size, TSK_FS_ATTR_FLAG_NONE, 0)) {
496
0
            return 1;
497
0
        }
498
499
127
        fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED;
500
501
127
        return 0;
502
127
    }
503
7.38k
    else if ((a_fs_file->meta->addr >= fatfs->mbr_virt_inum) &&
504
30
             (a_fs_file->meta->addr <= fatfs->mbr_virt_inum + fatfs->numfat)) {
505
        /* Make a single contiguous data run for a virtual file (MBR, FAT). */
506
0
        TSK_FS_ATTR_RUN *data_run;
507
508
0
        if (tsk_verbose) {
509
0
            tsk_fprintf(stderr,
510
0
                "%s: Loading virtual file: %" PRIuINUM
511
0
                "\n", func_name, a_fs_file->meta->addr);
512
0
        }
513
514
        /* Allocate the run. */
515
0
        data_run = tsk_fs_attr_run_alloc();
516
0
        if (data_run == NULL) {
517
0
            return 1;
518
0
        }
519
520
        /* Set the starting sector address and run length. */
521
0
        data_run->addr = clust;
522
0
        data_run->len = a_fs_file->meta->size / fs->block_size;
523
524
        /* Allocate a non-resident attribute to hold the run and add it
525
         to the attribute list. */
526
0
        if ((fs_attr =
527
0
                tsk_fs_attrlist_getnew(fs_meta->attr,
528
0
                    TSK_FS_ATTR_NONRES)) == NULL) {
529
0
            return 1;
530
0
        }
531
532
        /* Tie everything together. */
533
0
        if (tsk_fs_attr_set_run(a_fs_file, fs_attr, data_run, NULL,
534
0
                TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
535
0
                data_run->len * fs->block_size,
536
0
                data_run->len * fs->block_size,
537
0
                data_run->len * fs->block_size, TSK_FS_ATTR_FLAG_NONE, 0)) {
538
0
            return 1;
539
0
        }
540
541
0
        fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED;
542
0
        return 0;
543
0
    }
544
7.38k
    else if (fs_meta->flags & TSK_FS_META_FLAG_UNALLOC) {
545
        /* Make data runs for a deleted file that we want to recover.
546
         * In this case, we could get a lot of errors because of inconsistent
547
         * data.  To make it clear that these are from a recovery, we set most
548
         * error codes to _RECOVER so that they can be more easily suppressed.
549
         */
550
1.18k
        TSK_DADDR_T sbase;
551
1.18k
        TSK_DADDR_T startclust = clust;
552
1.18k
        TSK_OFF_T recoversize = fs_meta->size;
553
1.18k
        TSK_FS_ATTR_RUN *data_run = NULL;
554
1.18k
        TSK_FS_ATTR_RUN *data_run_tmp = NULL;
555
1.18k
        TSK_FS_ATTR_RUN *data_run_head = NULL;
556
1.18k
        uint8_t canRecover = 1; // set to 0 if recovery is not possible
557
558
1.18k
        if (tsk_verbose)
559
0
            tsk_fprintf(stderr,
560
0
                "%s: Processing deleted file %" PRIuINUM
561
0
                " in recovery mode\n", func_name, fs_meta->addr);
562
563
        /* We know the size and the starting cluster
564
         *
565
         * We are going to take the clusters from the starting cluster
566
         * onwards and skip the clusters that are current allocated
567
         */
568
569
    /* Quick check for exFAT only
570
     * Empty deleted files have a starting cluster of zero, which
571
     * causes problems in the exFAT functions since the first data
572
     * cluster should be 2. Since a starting cluster of zero indicates
573
     * no data, make an empty data run and skip any further processing
574
     */
575
1.18k
    if((fs->ftype == TSK_FS_TYPE_EXFAT) && (startclust == 0)){
576
            // initialize the data run
577
0
      fs_attr = tsk_fs_attrlist_getnew(a_fs_file->meta->attr, TSK_FS_ATTR_NONRES);
578
0
      if (fs_attr == NULL) {
579
0
        a_fs_file->meta->attr_state = TSK_FS_META_ATTR_ERROR;
580
0
        return 1;
581
0
      }
582
583
      // Add the empty data run
584
0
            if (tsk_fs_attr_set_run(a_fs_file, fs_attr, NULL, NULL,
585
0
                    TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
586
0
                    0, 0, 0, (TSK_FS_ATTR_FLAG_ENUM)0, 0)) {
587
0
                fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
588
0
                return 1;
589
0
            }
590
0
      fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED;
591
0
      return 0;
592
0
    }
593
594
        /* Sanity checks on the starting cluster */
595
        /* Convert the cluster addr to a sector addr */
596
1.18k
        sbase = FATFS_CLUST_2_SECT(fatfs, startclust);
597
598
1.18k
        if (sbase > fs->last_block) {
599
23
            tsk_error_reset();
600
23
            tsk_error_set_errno(TSK_ERR_FS_RECOVER);
601
23
            tsk_error_set_errstr
602
23
                ("%s: Starting cluster address too large (recovery): %"
603
23
                PRIuDADDR, func_name, sbase);
604
23
            fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
605
23
            return 1;
606
23
        }
607
1.16k
        else {
608
1.16k
            int retval;
609
610
            /* If the starting cluster is already allocated then we can't
611
             * recover it */
612
1.16k
            retval = fatfs->is_cluster_alloc(fatfs, startclust);
613
1.16k
            if (retval != 0) {
614
217
                canRecover = 0;
615
217
            }
616
1.16k
        }
617
618
        /* Part 1 is to make sure there are enough unallocated clusters
619
         * for the size of the file
620
         */
621
1.16k
        clust = startclust;
622
1.16k
        size_remain = recoversize;
623
624
        // we could make this negative so sign it for the comparison
625
1.53M
        while (((int64_t) size_remain > 0) && (canRecover)) {
626
1.53M
            int retval;
627
1.53M
            sbase = FATFS_CLUST_2_SECT(fatfs, clust);
628
629
            /* Are we past the end of the FS?
630
             * that means we could not find enough unallocated clusters
631
             * for the file size */
632
1.53M
            if (sbase + fatfs->csize - 1 > fs->last_block) {
633
0
                canRecover = 0;
634
635
0
                if (tsk_verbose)
636
0
                    tsk_fprintf(stderr,
637
0
                        "%s: Could not find enough unallocated sectors to recover with - aborting\n", func_name);
638
0
                break;
639
0
            }
640
641
            /* Skip allocated clusters */
642
1.53M
            retval = fatfs->is_cluster_alloc(fatfs, clust);
643
1.53M
            if (retval == -1) {
644
0
                canRecover = 0;
645
0
                break;
646
0
            }
647
1.53M
            else if (retval == 1) {
648
406k
                clust++;
649
406k
                continue;
650
406k
            }
651
652
            /* We can use this sector */
653
            // see if we need a new run
654
1.13M
            if ((data_run == NULL)
655
1.13M
                || (data_run->addr + data_run->len != sbase)) {
656
657
211k
                TSK_FS_ATTR_RUN *data_run_tmp = tsk_fs_attr_run_alloc();
658
211k
                if (data_run_tmp == NULL) {
659
0
                    fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
660
0
                    tsk_fs_attr_run_free(data_run_head);
661
0
                    return 1;
662
0
                }
663
664
211k
                if (data_run_head == NULL) {
665
948
                    data_run_head = data_run_tmp;
666
948
                    data_run_tmp->offset = 0;
667
948
                }
668
211k
                else if (data_run != NULL) {
669
211k
                    data_run->next = data_run_tmp;
670
211k
                    data_run_tmp->offset =
671
211k
                        data_run->offset + data_run->len;
672
211k
                }
673
211k
                data_run = data_run_tmp;
674
211k
                data_run->len = 0;
675
211k
                data_run->addr = sbase;
676
211k
            }
677
1.13M
            data_run->len += fatfs->csize;
678
679
1.13M
            size_remain -= (fatfs->csize << fatfs->ssize_sh);
680
1.13M
            clust++;
681
1.13M
        }
682
683
        // Get a FS_DATA structure and add the runlist to it
684
1.16k
        if ((fs_attr =
685
1.16k
                tsk_fs_attrlist_getnew(fs_meta->attr,
686
1.16k
                    TSK_FS_ATTR_NONRES)) == NULL) {
687
0
            fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
688
0
            tsk_fs_attr_run_free(data_run_head);
689
0
            return 1;
690
0
        }
691
692
1.16k
        if (canRecover) {
693
            /* We can recover the file */
694
695
            // initialize the data run
696
948
            if (tsk_fs_attr_set_run(a_fs_file, fs_attr, data_run_head,
697
948
                    NULL, TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
698
948
                    fs_meta->size, fs_meta->size, roundup(fs_meta->size,
699
948
                        fatfs->csize * fs->block_size), TSK_FS_ATTR_FLAG_NONE, 0)) {
700
0
                fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
701
0
                return 1;
702
0
            }
703
704
948
            fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED;
705
948
        }
706
        // create a one cluster run
707
217
        else {
708
217
            tsk_fs_attr_run_free(data_run_head);
709
710
217
            data_run_tmp = tsk_fs_attr_run_alloc();
711
217
            if (data_run_tmp == NULL) {
712
0
                fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
713
0
                return 1;
714
0
            }
715
217
            data_run_tmp->addr = sbase;
716
217
            data_run_tmp->len = fatfs->csize;
717
718
            // initialize the data run
719
217
            if (tsk_fs_attr_set_run(a_fs_file, fs_attr, data_run_tmp, NULL,
720
217
                    TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
721
217
                    fs_meta->size, fs_meta->size, roundup(fs_meta->size,
722
217
                        fatfs->csize * fs->block_size), TSK_FS_ATTR_FLAG_NONE, 0)) {
723
0
                fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
724
0
                return 1;
725
0
            }
726
727
217
            fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED;
728
217
        }
729
730
1.16k
        return 0;
731
1.16k
    }
732
6.19k
    else {
733
6.19k
        TSK_LIST *list_seen = NULL;
734
6.19k
        TSK_FS_ATTR_RUN *data_run = NULL;
735
6.19k
        TSK_FS_ATTR_RUN *data_run_head = NULL;
736
6.19k
        TSK_DADDR_T sbase;
737
        /* Do normal cluster chain walking for a file or directory, including
738
         * FAT32 and exFAT root directories. */
739
740
6.19k
        if (tsk_verbose) {
741
0
            tsk_fprintf(stderr,
742
0
                "%s: Processing file %" PRIuINUM
743
0
                " in normal mode\n", func_name, fs_meta->addr);
744
0
        }
745
746
        /* Cycle through the cluster chain */
747
7.44k
        while ((clust & fatfs->mask) > 0 && (int64_t) size_remain > 0 &&
748
1.24k
            (0 == FATFS_ISEOF(clust, fatfs->mask))) {
749
750
            /* Convert the cluster addr to a sector addr */
751
1.24k
            sbase = FATFS_CLUST_2_SECT(fatfs, clust);
752
753
1.24k
            if (sbase + fatfs->csize - 1 > fs->last_block) {
754
0
                fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
755
0
                tsk_error_reset();
756
757
0
                tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
758
0
                tsk_error_set_errstr
759
0
                    ("%s: Invalid sector address in FAT (too large): %"
760
0
                    PRIuDADDR " (plus %d sectors)", func_name, sbase, fatfs->csize);
761
0
                tsk_fs_attr_run_free(data_run_head);
762
0
                if (list_seen != NULL) {
763
0
                    tsk_list_free(list_seen);
764
0
                    list_seen = NULL;
765
0
                }
766
0
                return 1;
767
0
            }
768
769
            // see if we need a new run
770
1.24k
            if ((data_run == NULL)
771
1.24k
                || (data_run->addr + data_run->len != sbase)) {
772
773
1.24k
                TSK_FS_ATTR_RUN *data_run_tmp = tsk_fs_attr_run_alloc();
774
1.24k
                if (data_run_tmp == NULL) {
775
0
                    tsk_fs_attr_run_free(data_run_head);
776
0
                    fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
777
0
                    if (list_seen != NULL) {
778
0
                        tsk_list_free(list_seen);
779
0
                        list_seen = NULL;
780
0
                    }
781
0
                    return 1;
782
0
                }
783
784
1.24k
                if (data_run_head == NULL) {
785
685
                    data_run_head = data_run_tmp;
786
685
                    data_run_tmp->offset = 0;
787
685
                }
788
564
                else if (data_run != NULL) {
789
564
                    data_run->next = data_run_tmp;
790
564
                    data_run_tmp->offset =
791
564
                        data_run->offset + data_run->len;
792
564
                }
793
1.24k
                data_run = data_run_tmp;
794
1.24k
                data_run->len = 0;
795
1.24k
                data_run->addr = sbase;
796
1.24k
            }
797
798
1.24k
            data_run->len += fatfs->csize;
799
1.24k
            size_remain -= (fatfs->csize * fs->block_size);
800
801
1.24k
            if ((int64_t) size_remain > 0) {
802
564
                TSK_DADDR_T nxt;
803
564
                if (fatfs_getFAT(fatfs, clust, &nxt)) {
804
0
                    tsk_error_set_errstr2("%s: Inode: %" PRIuINUM
805
0
                        "  cluster: %" PRIuDADDR, func_name, fs_meta->addr, clust);
806
0
                    fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
807
0
                    tsk_fs_attr_run_free(data_run_head);
808
0
                    if (list_seen != NULL) {
809
0
                        tsk_list_free(list_seen);
810
0
                        list_seen = NULL;
811
0
                    }
812
0
                    return 1;
813
0
                }
814
564
                clust = nxt;
815
816
                /* Make sure we do not get into an infinite loop */
817
564
                if (tsk_list_find(list_seen, clust)) {
818
0
                    if (tsk_verbose)
819
0
                        tsk_fprintf(stderr,
820
0
                            "Loop found while processing file\n");
821
0
                    if (data_run_head != NULL ) {
822
0
                      tsk_fs_attr_run_free(data_run_head);
823
                      // Make sure to set data_run_head to NULL to prevent a use-after-free
824
0
                      data_run_head = NULL;
825
0
                    }
826
0
                    if (list_seen != NULL) {
827
0
                        tsk_list_free(list_seen);
828
0
                        list_seen = NULL;
829
0
                    }
830
0
                    break;
831
0
                }
832
833
564
                if (tsk_list_add(&list_seen, clust)) {
834
0
                    fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
835
0
                    tsk_fs_attr_run_free(data_run_head);
836
0
                    if (list_seen != NULL) {
837
0
                        tsk_list_free(list_seen);
838
0
                        list_seen = NULL;
839
0
                    }
840
0
                    return 1;
841
0
                }
842
564
            }
843
1.24k
        }
844
845
        // add the run list to the inode structure
846
6.19k
        if ((fs_attr =
847
6.19k
                tsk_fs_attrlist_getnew(fs_meta->attr,
848
6.19k
                    TSK_FS_ATTR_NONRES)) == NULL) {
849
0
            fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
850
0
            if (list_seen != NULL) {
851
0
                tsk_list_free(list_seen);
852
0
                list_seen = NULL;
853
0
            }
854
0
            return 1;
855
0
        }
856
857
        // initialize the data run
858
6.19k
        if (tsk_fs_attr_set_run(a_fs_file, fs_attr, data_run_head, NULL,
859
6.19k
                TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
860
6.19k
                fs_meta->size, fs_meta->size, roundup(fs_meta->size,
861
6.19k
                    fatfs->csize * fs->block_size), TSK_FS_ATTR_FLAG_NONE, 0)) {
862
0
            fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
863
0
            tsk_fs_attr_run_free(data_run_head);
864
0
            if (list_seen != NULL) {
865
0
                tsk_list_free(list_seen);
866
0
                list_seen = NULL;
867
0
            }
868
0
            return 1;
869
0
        }
870
871
6.19k
        tsk_list_free(list_seen);
872
6.19k
        list_seen = NULL;
873
874
6.19k
        fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED;
875
876
6.19k
        return 0;
877
6.19k
    }
878
7.51k
}
879
880
/* Used for istat callback */
881
typedef struct {
882
    FILE *hFile;
883
    int idx;
884
    int istat_seen;
885
} FATFS_PRINT_ADDR;
886
887
/* Callback a_action for file_walk to print the sector addresses
888
 * of a file, used for istat
889
 */
890
static TSK_WALK_RET_ENUM
891
print_addr_act(
892
  [[maybe_unused]] TSK_FS_FILE * fs_file,
893
  [[maybe_unused]] TSK_OFF_T a_off,
894
  TSK_DADDR_T addr,
895
  [[maybe_unused]] char *buf,
896
  [[maybe_unused]] size_t size,
897
  [[maybe_unused]] TSK_FS_BLOCK_FLAG_ENUM a_flags,
898
  void *a_ptr)
899
0
{
900
0
    FATFS_PRINT_ADDR *print = (FATFS_PRINT_ADDR *) a_ptr;
901
902
0
    tsk_fprintf(print->hFile, "%" PRIuDADDR " ", addr);
903
904
0
    if (++(print->idx) == 8) {
905
0
        tsk_fprintf(print->hFile, "\n");
906
0
        print->idx = 0;
907
0
    }
908
0
    print->istat_seen = 1;
909
910
0
    return TSK_WALK_CONT;
911
0
}
912
913
/**
914
 * Print details on a specific file to a file handle.
915
 *
916
 * @param a_fs File system file is located in.
917
 * @param a_hFile File handle to print text to.
918
 * @param a_inum Address of file in file system.
919
 * @param a_numblock The number of blocks in file to force print (can go beyond file size).
920
 * @param a_sec_skew Clock skew in seconds to also print times in.
921
 *
922
 * @returns 1 on error and 0 on success.
923
 */
924
uint8_t
925
fatfs_istat(TSK_FS_INFO *a_fs, TSK_FS_ISTAT_FLAG_ENUM istat_flags, FILE *a_hFile, TSK_INUM_T a_inum,
926
    TSK_DADDR_T a_numblock, int32_t a_sec_skew)
927
0
{
928
0
    const char* func_name = "fatfs_istat";
929
0
    FATFS_INFO *fatfs = (FATFS_INFO*)a_fs;
930
0
    TSK_FS_META *fs_meta = NULL;
931
0
    TSK_FS_META_NAME_LIST *fs_name_list = NULL;
932
0
    FATFS_PRINT_ADDR print;
933
0
    char timeBuf[128];
934
935
0
    tsk_error_reset();
936
0
    if (fatfs_ptr_arg_is_null(a_fs, "a_fs", func_name) ||
937
0
        fatfs_ptr_arg_is_null(a_hFile, "a_hFile", func_name) ||
938
0
        !fatfs_inum_arg_is_in_range(fatfs, a_inum, func_name)) {
939
0
        return 1;
940
0
    }
941
942
    /* Create a TSK_FS_FILE corresponding to the specified inode. */
943
0
    std::unique_ptr<TSK_FS_FILE, decltype(&tsk_fs_file_close)> fs_file{
944
0
        tsk_fs_file_open_meta(a_fs, NULL, a_inum),
945
0
        tsk_fs_file_close
946
0
    };
947
948
0
    if (!fs_file) {
949
0
        return 1;
950
0
    }
951
0
    fs_meta = fs_file->meta;
952
953
    /* Print the inode address. */
954
0
    tsk_fprintf(a_hFile, "Directory Entry: %" PRIuINUM "\n", a_inum);
955
956
    /* Print the allocation status. */
957
0
    tsk_fprintf(a_hFile, "%sAllocated\n",
958
0
        (fs_meta->flags & TSK_FS_META_FLAG_UNALLOC) ? "Not " : "");
959
960
    /* Print the attributes. */
961
0
    tsk_fprintf(a_hFile, "File Attributes: ");
962
963
0
    if (a_inum == a_fs->root_inum) {
964
0
        tsk_fprintf(a_hFile, "Root Directory\n");
965
0
    }
966
0
    else if (fs_meta->type == TSK_FS_META_TYPE_VIRT) {
967
0
        tsk_fprintf(a_hFile, "Virtual File\n");
968
0
    }
969
0
    else if (fs_meta->addr == TSK_FS_ORPHANDIR_INUM(a_fs)) {
970
0
        tsk_fprintf(a_hFile, "Virtual Directory\n");
971
0
    }
972
0
    else {
973
0
        if (fatfs->istat_attr_flags(fatfs, a_inum, a_hFile)) {
974
0
            return 1;
975
0
        }
976
0
    }
977
978
    /* Print the file size. */
979
0
    tsk_fprintf(a_hFile, "Size: %" PRIdOFF "\n", fs_meta->size);
980
981
    /* Print the name. */
982
0
    if (fs_meta->name2) {
983
0
        fs_name_list = fs_meta->name2;
984
0
        tsk_fprintf(a_hFile, "Name: %s\n", fs_name_list->name);
985
0
    }
986
987
    /* Print the times. */
988
0
    if (a_sec_skew != 0) {
989
0
        tsk_fprintf(a_hFile, "\nAdjusted Directory Entry Times:\n");
990
991
0
        if (fs_meta->mtime)
992
0
            fs_meta->mtime -= a_sec_skew;
993
0
        if (fs_meta->atime)
994
0
            fs_meta->atime -= a_sec_skew;
995
0
        if (fs_meta->crtime)
996
0
            fs_meta->crtime -= a_sec_skew;
997
998
0
        tsk_fprintf(a_hFile, "Written:\t%s\n",
999
0
            tsk_fs_time_to_str(fs_meta->mtime, timeBuf));
1000
0
        tsk_fprintf(a_hFile, "Accessed:\t%s\n",
1001
0
            tsk_fs_time_to_str(fs_meta->atime, timeBuf));
1002
0
        tsk_fprintf(a_hFile, "Created:\t%s\n",
1003
0
            tsk_fs_time_to_str(fs_meta->crtime, timeBuf));
1004
1005
0
        if (fs_meta->mtime)
1006
0
            fs_meta->mtime += a_sec_skew;
1007
0
        if (fs_meta->atime)
1008
0
            fs_meta->atime += a_sec_skew;
1009
0
        if (fs_meta->crtime)
1010
0
            fs_meta->crtime += a_sec_skew;
1011
1012
0
        tsk_fprintf(a_hFile, "\nOriginal Directory Entry Times:\n");
1013
0
    }
1014
0
    else {
1015
0
        tsk_fprintf(a_hFile, "\nDirectory Entry Times:\n");
1016
0
    }
1017
1018
0
    tsk_fprintf(a_hFile, "Written:\t%s\n", tsk_fs_time_to_str(fs_meta->mtime,
1019
0
        timeBuf));
1020
0
    tsk_fprintf(a_hFile, "Accessed:\t%s\n",
1021
0
        tsk_fs_time_to_str(fs_meta->atime, timeBuf));
1022
0
    tsk_fprintf(a_hFile, "Created:\t%s\n",
1023
0
        tsk_fs_time_to_str(fs_meta->crtime, timeBuf));
1024
1025
    /* Print the specified number of sector addresses. */
1026
0
    tsk_fprintf(a_hFile, "\nSectors:\n");
1027
0
    if (istat_flags & TSK_FS_ISTAT_RUNLIST) {
1028
0
        const TSK_FS_ATTR *fs_attr_default =
1029
0
            tsk_fs_file_attr_get_type(fs_file.get(),
1030
0
                TSK_FS_ATTR_TYPE_DEFAULT, 0, 0);
1031
0
        if (fs_attr_default && (fs_attr_default->flags & TSK_FS_ATTR_NONRES)) {
1032
0
            if (tsk_fs_attr_print(fs_attr_default, a_hFile)) {
1033
0
                tsk_fprintf(a_hFile, "\nError creating run lists\n");
1034
0
                tsk_error_print(a_hFile);
1035
0
                tsk_error_reset();
1036
0
            }
1037
0
        }
1038
0
    }
1039
0
    else {
1040
1041
0
        if (a_numblock > 0) {
1042
            /* A bad hack to force a specified number of blocks */
1043
0
            fs_meta->size = a_numblock * a_fs->block_size;
1044
0
        }
1045
0
        print.istat_seen = 0;
1046
0
        print.idx = 0;
1047
0
        print.hFile = a_hFile;
1048
0
        if (tsk_fs_file_walk(fs_file.get(),
1049
0
            (TSK_FS_FILE_WALK_FLAG_ENUM)(TSK_FS_FILE_WALK_FLAG_AONLY | TSK_FS_FILE_WALK_FLAG_SLACK),
1050
0
            print_addr_act, (void *)&print)) {
1051
0
            tsk_fprintf(a_hFile, "\nError reading file\n");
1052
0
            tsk_error_print(a_hFile);
1053
0
            tsk_error_reset();
1054
0
        }
1055
0
        else if (print.idx != 0) {
1056
0
            tsk_fprintf(a_hFile, "\n");
1057
0
        }
1058
0
    }
1059
1060
0
    return 0;
1061
0
}
1062
1063
/* Mark the sector used in the bitmap */
1064
static TSK_WALK_RET_ENUM
1065
inode_walk_file_act(
1066
  [[maybe_unused]] TSK_FS_FILE * fs_file,
1067
  [[maybe_unused]] TSK_OFF_T a_off,
1068
  TSK_DADDR_T addr,
1069
  [[maybe_unused]] char *buf,
1070
  [[maybe_unused]] size_t size,
1071
  [[maybe_unused]] TSK_FS_BLOCK_FLAG_ENUM a_flags,
1072
  void *a_ptr)
1073
18.4k
{
1074
18.4k
    setbit((uint8_t *) a_ptr, addr);
1075
18.4k
    return TSK_WALK_CONT;
1076
18.4k
}
1077
1078
/* The inode_walk call back for each file.  we want only the directories */
1079
static TSK_WALK_RET_ENUM
1080
inode_walk_dent_act(
1081
  TSK_FS_FILE * fs_file,
1082
  [[maybe_unused]] const char *a_path,
1083
  void *a_ptr)
1084
58.9k
{
1085
58.9k
    unsigned int flags = TSK_FS_FILE_WALK_FLAG_SLACK | TSK_FS_FILE_WALK_FLAG_AONLY;
1086
1087
58.9k
    if ((fs_file->meta == NULL)
1088
58.9k
        || ( ! TSK_FS_IS_DIR_META(fs_file->meta->type)))
1089
52.5k
        return TSK_WALK_CONT;
1090
1091
    /* Get the sector addresses & ignore any errors */
1092
6.41k
    if (tsk_fs_file_walk(fs_file,
1093
6.41k
            (TSK_FS_FILE_WALK_FLAG_ENUM)flags,
1094
6.41k
            inode_walk_file_act, a_ptr)) {
1095
728
        tsk_error_reset();
1096
728
    }
1097
1098
6.41k
    return TSK_WALK_CONT;
1099
58.9k
}
1100
1101
/**
1102
 * Walk the inodes in a specified range and do a TSK_FS_META_WALK_CB callback
1103
 * for each inode that satisfies criteria specified by a set of
1104
 * TSK_FS_META_FLAG_ENUM flags. The following flags are supported:
1105
 * TSK_FS_META_FLAG_ALLOC, TSK_FS_META_FLAG_UNALLOC, TSK_FS_META_FLAG_ORPHAN,
1106
 * TSK_FS_META_FLAG_USED (FATXX only), and TSK_FS_META_FLAG_UNUSED
1107
 * (FATXX only).
1108
 *
1109
 * @param [in] a_fs File system that contains the inodes.
1110
 * @param [in] a_start_inum Inclusive lower bound of inode range.
1111
 * @param [in] a_end_inum Inclusive upper bound of inode range.
1112
 * @param [in] a_selection_flags Inode selection criteria.
1113
 * @param [in] a_action Callback function for selected inodes.
1114
 * @param [in] a_ptr Private data pointer passed through to callback function.
1115
 * @return 0 on success, 1 on failure, per TSK convention
1116
 */
1117
uint8_t
1118
fatfs_inode_walk(TSK_FS_INFO *a_fs, TSK_INUM_T a_start_inum,
1119
    TSK_INUM_T a_end_inum, TSK_FS_META_FLAG_ENUM a_selection_flags,
1120
    TSK_FS_META_WALK_CB a_action, void *a_ptr)
1121
32
{
1122
32
    const char *func_name = "fatfs_inode_walk";
1123
32
    FATFS_INFO *fatfs = (FATFS_INFO*)a_fs;
1124
32
    unsigned int flags = a_selection_flags;
1125
32
    TSK_INUM_T end_inum_tmp = 0;
1126
32
    TSK_DADDR_T ssect = 0;
1127
32
    TSK_DADDR_T lsect = 0;
1128
32
    TSK_DADDR_T sect = 0;
1129
32
    char *dino_buf = NULL;
1130
32
    FATFS_DENTRY *dep = NULL;
1131
32
    unsigned int dentry_idx = 0;
1132
32
    uint8_t *dir_sectors_bitmap = NULL;
1133
32
    ssize_t cnt = 0;
1134
32
    uint8_t done = 0;
1135
1136
32
    tsk_error_reset();
1137
32
    if (fatfs_ptr_arg_is_null(a_fs, "a_fs", func_name) ||
1138
32
        fatfs_ptr_arg_is_null(*(void **) &a_action, "a_action", func_name)) {
1139
0
        return 1;
1140
0
    }
1141
1142
32
    if (a_start_inum < a_fs->first_inum || a_start_inum > a_fs->last_inum) {
1143
0
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
1144
0
        tsk_error_set_errstr("%s: Begin inode out of range:  %" PRIuINUM "",
1145
0
            func_name, a_start_inum);
1146
0
        return 1;
1147
0
    }
1148
32
    else if (a_end_inum < a_fs->first_inum ||
1149
32
             a_end_inum > a_fs->last_inum ||
1150
32
             a_end_inum < a_start_inum) {
1151
0
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
1152
0
        tsk_error_set_errstr("%s: End inode out of range: %" PRIuINUM "",
1153
0
            func_name, a_end_inum);
1154
0
        return 1;
1155
0
    }
1156
1157
    /* FAT file systems do not really have the concept of unused inodes. */
1158
32
    if ((flags & TSK_FS_META_FLAG_UNUSED) && !(flags & TSK_FS_META_FLAG_USED)) {
1159
0
        return 0;
1160
0
    }
1161
32
    flags |= TSK_FS_META_FLAG_USED;
1162
32
    flags &= ~TSK_FS_META_FLAG_UNUSED;
1163
1164
    /* Make sure the inode selection flags are set correctly. */
1165
32
    if (flags & TSK_FS_META_FLAG_ORPHAN) {
1166
        /* If ORPHAN file inodes are wanted, make sure that the UNALLOC
1167
         * selection flag is set. */
1168
0
        flags |= TSK_FS_META_FLAG_UNALLOC;
1169
0
        flags &= ~TSK_FS_META_FLAG_ALLOC;
1170
0
    }
1171
32
    else {
1172
        /* If neither of the ALLOC or UNALLOC inode selection flags are set,
1173
        *  then set them both. */
1174
32
        if (((flags & TSK_FS_META_FLAG_ALLOC) == 0) &&
1175
32
            ((flags & TSK_FS_META_FLAG_UNALLOC) == 0)) {
1176
0
            flags |= (TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_UNALLOC);
1177
0
        }
1178
32
    }
1179
1180
32
    if (tsk_verbose) {
1181
0
        tsk_fprintf(stderr,
1182
0
            "%s: Inode walking %" PRIuINUM " to %"
1183
0
            PRIuINUM "\n", func_name, a_start_inum, a_end_inum);
1184
0
    }
1185
1186
    /* If we are looking for orphan files and have not yet populated
1187
     * the list of files reachable by name for this file system, do so now.
1188
     */
1189
32
    if ((flags & TSK_FS_META_FLAG_ORPHAN)) {
1190
0
        if (tsk_fs_dir_load_inum_named(a_fs) != TSK_OK) {
1191
0
            tsk_error_errstr2_concat(
1192
0
                "%s: Identifying orphan inodes", func_name);
1193
0
            return 1;
1194
0
        }
1195
0
    }
1196
1197
    /* Allocate a TSK_FS_FILE object with a TSK_FS_META object to populate and
1198
     * pass to the callback function when an inode that fits the inode
1199
     * selection criteria is found. */
1200
32
    std::unique_ptr<TSK_FS_FILE, decltype(&tsk_fs_file_close)> fs_file{
1201
32
        tsk_fs_file_alloc(a_fs),
1202
32
        tsk_fs_file_close
1203
32
    };
1204
32
    if (!fs_file) {
1205
0
        return 1;
1206
0
    }
1207
1208
32
    if ((fs_file->meta =
1209
32
            tsk_fs_meta_alloc(FATFS_FILE_CONTENT_LEN)) == NULL) {
1210
0
        return 1;
1211
0
    }
1212
1213
    /* Process the root directory inode, if it's included in the walk. */
1214
32
    if (a_start_inum == a_fs->root_inum) {
1215
32
        if (((TSK_FS_META_FLAG_ALLOC & flags) == TSK_FS_META_FLAG_ALLOC)
1216
0
            && ((TSK_FS_META_FLAG_ORPHAN & flags) == 0)) {
1217
0
            TSK_WALK_RET_ENUM retval = TSK_WALK_CONT;
1218
1219
0
            if (fatfs_make_root(fatfs, fs_file->meta)) {
1220
0
                return 1;
1221
0
            }
1222
1223
0
            retval = a_action(fs_file.get(), a_ptr);
1224
0
            if (retval == TSK_WALK_STOP) {
1225
0
                return 0;
1226
0
            }
1227
0
            else if (retval == TSK_WALK_ERROR) {
1228
0
                return 1;
1229
0
            }
1230
0
        }
1231
1232
32
        a_start_inum++;
1233
32
        if (a_start_inum == a_end_inum) {
1234
0
            return 0;
1235
0
        }
1236
32
    }
1237
32
    size_t bitmap_len = (a_fs->block_count + 7) / 8;
1238
1239
    // Taking 128 MiB as an arbitrary upper bound
1240
32
    if ((bitmap_len == 0) || (bitmap_len > (128 * 1024 * 1024))) {
1241
2
        return 1;
1242
2
    }
1243
1244
    /* Allocate a bitmap to keep track of which sectors are allocated to
1245
     * directories. */
1246
30
    if ((dir_sectors_bitmap = (uint8_t*)tsk_malloc(bitmap_len)) == NULL) {
1247
0
        return 1;
1248
0
    }
1249
1250
    /* If not doing an orphan files search, populate the directory sectors
1251
     * bitmap. The bitmap will be used to make sure that no sector marked as
1252
     * allocated to a directory is skipped when searching for directory
1253
     * entries to map to inodes. */
1254
30
    if ((flags & TSK_FS_META_FLAG_ORPHAN) == 0) {
1255
30
        if (tsk_verbose) {
1256
0
            tsk_fprintf(stderr,
1257
0
                "fatfs_inode_walk: Walking directories to collect sector info\n");
1258
0
        }
1259
1260
        /* Manufacture an inode for the root directory. */
1261
30
        if (fatfs_make_root(fatfs, fs_file->meta)) {
1262
0
            free(dir_sectors_bitmap);
1263
0
            return 1;
1264
0
        }
1265
1266
        /* Do a file_walk on the root directory to set the bits in the
1267
         * directory sectors bitmap for each sector allocated to the root
1268
         * directory. */
1269
30
        if (tsk_fs_file_walk(fs_file.get(),
1270
30
                (TSK_FS_FILE_WALK_FLAG_ENUM)(TSK_FS_FILE_WALK_FLAG_SLACK | TSK_FS_FILE_WALK_FLAG_AONLY),
1271
30
                inode_walk_file_act, (void*)dir_sectors_bitmap)) {
1272
0
            free(dir_sectors_bitmap);
1273
0
            return 1;
1274
0
        }
1275
1276
        /* Now walk recursively through the entire directory tree to set the
1277
         * bits in the directory sectors bitmap for each sector allocated to
1278
         * the children of the root directory. */
1279
30
        if (tsk_fs_dir_walk(a_fs, a_fs->root_inum,
1280
30
                (TSK_FS_DIR_WALK_FLAG_ENUM)(TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE |
1281
30
                TSK_FS_DIR_WALK_FLAG_NOORPHAN), inode_walk_dent_act,
1282
30
                (void *) dir_sectors_bitmap)) {
1283
0
            tsk_error_errstr2_concat
1284
0
                ("- fatfs_inode_walk: mapping directories");
1285
0
            free(dir_sectors_bitmap);
1286
0
            return 1;
1287
0
        }
1288
30
    }
1289
1290
    /* If the end inode is the one of the virtual virtual FAT files or the
1291
     * virtual orphan files directory, adjust the end inum and handle the
1292
     * virtual inodes after the main inode walking loop below completes. */
1293
30
    if (a_end_inum > a_fs->last_inum - FATFS_NUM_VIRT_FILES(fatfs)) {
1294
30
        end_inum_tmp = a_fs->last_inum - FATFS_NUM_VIRT_FILES(fatfs);
1295
30
    }
1296
0
    else {
1297
0
        end_inum_tmp = a_end_inum;
1298
0
    }
1299
1300
    /* Map the begin and end inodes to the sectors that contain them.
1301
     * This sets the image level boundaries for the inode walking loop. */
1302
30
    ssect = FATFS_INODE_2_SECT(fatfs, a_start_inum);
1303
30
    if (ssect > a_fs->last_block) {
1304
0
        tsk_error_reset();
1305
0
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
1306
0
        tsk_error_set_errstr
1307
0
            ("%s: Begin inode in sector too big for image: %"
1308
0
            PRIuDADDR, func_name, ssect);
1309
0
        free(dir_sectors_bitmap);
1310
0
        return 1;
1311
0
    }
1312
1313
30
    lsect = FATFS_INODE_2_SECT(fatfs, end_inum_tmp);
1314
30
    if (lsect > a_fs->last_block) {
1315
0
        tsk_error_reset();
1316
0
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
1317
0
        tsk_error_set_errstr
1318
0
            ("%s: End inode in sector too big for image: %"
1319
0
            PRIuDADDR, func_name, lsect);
1320
0
        free(dir_sectors_bitmap);
1321
0
        return 1;
1322
0
    }
1323
1324
    /* Allocate a buffer big enough to read in a cluster at a time. */
1325
30
    if ((dino_buf = (char*)tsk_malloc(fatfs->csize << fatfs->ssize_sh)) ==
1326
30
        NULL) {
1327
0
        free(dir_sectors_bitmap);
1328
0
        return 1;
1329
0
    }
1330
1331
    /* Walk the inodes. */
1332
30
    sect = ssect;
1333
17.5k
    while (sect <= lsect) {
1334
17.5k
        int cluster_is_alloc = 0;
1335
17.5k
        size_t num_sectors_to_process = 0;
1336
17.5k
        size_t sector_idx = 0;
1337
17.5k
        uint8_t do_basic_dentry_test = 0;
1338
1339
        /* Read in a chunk of the image to process on this iteration of the inode
1340
         * walk. The actual size of the read will depend on whether or not it is
1341
         * coming from the root directory of a FAT12 or FAT16 file system. As
1342
         * indicated by the size of the buffer, the data area (exFAT cluster
1343
         * heap) will for the most part be read in a cluster at a time.
1344
         * However, the root directory for a FAT12/FAT16 file system precedes
1345
         * the data area and the read size for it should be a sector, not a
1346
         * cluster. */
1347
17.5k
        if (sect < fatfs->firstclustsect) {
1348
1349
4.75k
            if ((flags & TSK_FS_META_FLAG_ORPHAN) != 0) {
1350
                /* If orphan file hunting, there are no orphans in the root
1351
                 * directory, so skip ahead to the data area. */
1352
0
                sect = fatfs->firstclustsect;
1353
0
                continue;
1354
0
            }
1355
1356
            /* Read in a FAT12/FAT16 root directory sector. */
1357
4.75k
            cnt = tsk_fs_read_block(a_fs, sect, dino_buf, fatfs->ssize);
1358
4.75k
            if (cnt != fatfs->ssize) {
1359
0
                if (cnt >= 0) {
1360
0
                    tsk_error_reset();
1361
0
                    tsk_error_set_errno(TSK_ERR_FS_READ);
1362
0
                }
1363
0
                tsk_error_set_errstr2
1364
0
                    ("%s (root dir): sector: %" PRIuDADDR,
1365
0
                    func_name, sect);
1366
0
                free(dir_sectors_bitmap);
1367
0
                free(dino_buf);
1368
0
                return 1;
1369
0
            }
1370
1371
4.75k
            cluster_is_alloc = 1;
1372
4.75k
            num_sectors_to_process = 1;
1373
4.75k
        }
1374
12.7k
        else {
1375
            /* The walk has proceeded into the data area (exFAT cluster heap).
1376
             * It's time to read in a cluster at a time. Get the base sector
1377
             * for the cluster that contains the current sector. */
1378
12.7k
            sect =
1379
12.7k
                FATFS_CLUST_2_SECT(fatfs, (FATFS_SECT_2_CLUST(fatfs,
1380
12.7k
                        sect)));
1381
1382
            /* Determine whether the cluster is allocated. Skip it if it is
1383
             * not allocated and the UNALLOCATED inode selection flag is not
1384
             * set. */
1385
12.7k
            cluster_is_alloc = fatfs_is_sectalloc(fatfs, sect);
1386
12.7k
            if ((cluster_is_alloc == 0)
1387
9.27k
                && ((flags & TSK_FS_META_FLAG_UNALLOC) == 0)) {
1388
0
                sect += fatfs->csize;
1389
0
                continue;
1390
0
            }
1391
12.7k
            else if (cluster_is_alloc == -1) {
1392
0
                free(dir_sectors_bitmap);
1393
0
                free(dino_buf);
1394
0
                return 1;
1395
0
            }
1396
1397
            /* If the cluster is allocated but is not allocated to a
1398
             * directory, then skip it.  NOTE: This will miss orphan file
1399
             * entries in the slack space of files.
1400
             */
1401
12.7k
            if ((cluster_is_alloc == 1) && (isset(dir_sectors_bitmap, sect) == 0)) {
1402
3.46k
                sect += fatfs->csize;
1403
3.46k
                continue;
1404
3.46k
            }
1405
1406
            /* The final cluster may not be full. */
1407
9.29k
            if (lsect - sect + 1 < fatfs->csize) {
1408
16
                num_sectors_to_process = (size_t) (lsect - sect + 1);
1409
16
            }
1410
9.27k
            else {
1411
9.27k
                num_sectors_to_process = fatfs->csize;
1412
9.27k
            }
1413
1414
            /* Read in a cluster. */
1415
9.29k
            cnt = tsk_fs_read_block
1416
9.29k
                (a_fs, sect, dino_buf, num_sectors_to_process << fatfs->ssize_sh);
1417
9.29k
            if (cnt != (ssize_t)(num_sectors_to_process << fatfs->ssize_sh)) {
1418
0
                if (cnt >= 0) {
1419
0
                    tsk_error_reset();
1420
0
                    tsk_error_set_errno(TSK_ERR_FS_READ);
1421
0
                }
1422
0
                tsk_error_set_errstr2("%s: sector: %"
1423
0
                    PRIuDADDR, func_name, sect);
1424
0
                free(dir_sectors_bitmap);
1425
0
                free(dino_buf);
1426
0
                return 1;
1427
0
            }
1428
9.29k
        }
1429
1430
        /* Now that the sectors are read in, prepare to step through them in
1431
         * directory entry size chunks. Only do a basic test to confirm the
1432
         * contents of each chunk is a directory entry unless the sector that
1433
         * contains it is not allocated to a directory or is unallocated.*/
1434
14.0k
        do_basic_dentry_test = 1;
1435
14.0k
        if ((isset(dir_sectors_bitmap, sect) == 0) || (cluster_is_alloc == 0)) {
1436
9.27k
            do_basic_dentry_test = 0;
1437
9.27k
        }
1438
1439
        /* Walk through the sectors read in. */
1440
52.3k
        for (sector_idx = 0; sector_idx < num_sectors_to_process; sector_idx++) {
1441
38.2k
            TSK_INUM_T inum = 0;
1442
1443
            /* If the last inode in this sector is before the start
1444
             * inode, skip the sector. */
1445
38.2k
            if (FATFS_SECT_2_INODE(fatfs, sect + 1) < a_start_inum) {
1446
0
                sect++;
1447
0
                continue;
1448
0
            }
1449
1450
            /* Advance the directory entry pointer to the start of the
1451
             * sector. */
1452
38.2k
            dep = (FATFS_DENTRY*)(&dino_buf[sector_idx << fatfs->ssize_sh]);
1453
1454
            /* If the sector is not allocated to a directory and the first
1455
             * chunk is not a directory entry, skip the sector. */
1456
38.2k
            if (!isset(dir_sectors_bitmap, sect) &&
1457
33.0k
                !fatfs->is_dentry(fatfs, dep, (FATFS_DATA_UNIT_ALLOC_STATUS_ENUM)cluster_is_alloc, do_basic_dentry_test)) {
1458
24.3k
                sect++;
1459
24.3k
                continue;
1460
24.3k
            }
1461
1462
            /* Get the base inode address of this sector. */
1463
13.9k
            inum = FATFS_SECT_2_INODE(fatfs, sect);
1464
13.9k
            if (tsk_verbose) {
1465
0
                tsk_fprintf(stderr,
1466
0
                    "%s: Processing sector %" PRIuDADDR
1467
0
                    " starting at inode %" PRIuINUM "\n", func_name, sect, inum);
1468
0
            }
1469
1470
            /* Walk through the potential directory entries in the sector. */
1471
304k
            for (dentry_idx = 0; dentry_idx < fatfs->dentry_cnt_se;
1472
290k
                dentry_idx++, inum++, dep++) {
1473
290k
                int retval;
1474
290k
                TSK_RETVAL_ENUM retval2 = TSK_OK;
1475
1476
                /* If the inode address of the potential entry is less than
1477
                 * the beginning inode address for the inode walk, skip it. */
1478
290k
                if (inum < a_start_inum) {
1479
0
                    continue;
1480
0
                }
1481
1482
                /* If inode address of the potential entry is greater than the
1483
                 * ending inode address for the walk, terminate the inode walk. */
1484
290k
                if (inum > end_inum_tmp) {
1485
0
                    done = 1;
1486
0
                    break;
1487
0
                }
1488
1489
                /* If the potential entry is likely not an entry, or it is an
1490
                 * entry that is not reported in an inode walk, or it does not
1491
                 * satisfy the inode selection flags, then skip it. */
1492
290k
                if (!fatfs->is_dentry(fatfs, dep, (FATFS_DATA_UNIT_ALLOC_STATUS_ENUM)cluster_is_alloc, do_basic_dentry_test) ||
1493
173k
                    fatfs->inode_walk_should_skip_dentry(fatfs, inum, dep, flags, cluster_is_alloc)) {
1494
142k
                    continue;
1495
142k
                }
1496
1497
148k
                retval2 = fatfs->dinode_copy(fatfs, inum, dep, cluster_is_alloc, fs_file.get());
1498
1499
148k
                if (retval2 != TSK_OK) {
1500
0
                    if (retval2 == TSK_COR) {
1501
                        /* Corrupted, move on to the next chunk. */
1502
0
                        if (tsk_verbose) {
1503
0
                            tsk_error_print(stderr);
1504
0
                        }
1505
0
                        tsk_error_reset();
1506
0
                        continue;
1507
0
                    }
1508
0
                    else {
1509
0
                        free(dir_sectors_bitmap);
1510
0
                        free(dino_buf);
1511
0
                        return 1;
1512
0
                    }
1513
0
                }
1514
1515
148k
                if (tsk_verbose) {
1516
0
                    tsk_fprintf(stderr,
1517
0
                        "%s: Directory Entry %" PRIuINUM
1518
0
                        " (%u) at sector %" PRIuDADDR "\n", func_name, inum, dentry_idx,
1519
0
                        sect);
1520
0
                }
1521
1522
                /* Do the callback. */
1523
148k
                retval = a_action(fs_file.get(), a_ptr);
1524
148k
                if (retval == TSK_WALK_STOP) {
1525
0
                    free(dir_sectors_bitmap);
1526
0
                    free(dino_buf);
1527
0
                    return 0;
1528
0
                }
1529
148k
                else if (retval == TSK_WALK_ERROR) {
1530
0
                    free(dir_sectors_bitmap);
1531
0
                    free(dino_buf);
1532
0
                    return 1;
1533
0
                }
1534
148k
            }
1535
13.9k
            sect++;
1536
13.9k
            if (done) {
1537
0
                break;
1538
0
            }
1539
13.9k
        }
1540
14.0k
        if (done) {
1541
0
            break;
1542
0
        }
1543
14.0k
    }
1544
1545
30
    free(dir_sectors_bitmap);
1546
30
    free(dino_buf);
1547
1548
    // handle the virtual orphans folder and FAT files if they asked for them
1549
30
    if ((a_end_inum > a_fs->last_inum - FATFS_NUM_VIRT_FILES(fatfs))
1550
30
        && (flags & TSK_FS_META_FLAG_ALLOC)
1551
0
        && ((flags & TSK_FS_META_FLAG_ORPHAN) == 0)) {
1552
0
        TSK_INUM_T inum;
1553
1554
        // cycle through the special files
1555
0
        for (inum = a_fs->last_inum - FATFS_NUM_VIRT_FILES(fatfs) + 1;
1556
0
            inum <= a_end_inum; inum++) {
1557
0
            int retval;
1558
1559
0
            tsk_fs_meta_reset(fs_file->meta);
1560
1561
0
            if (inum == fatfs->mbr_virt_inum) {
1562
0
                if (fatfs_make_mbr(fatfs, fs_file->meta)) {
1563
0
                    return 1;
1564
0
                }
1565
0
            }
1566
0
            else if (inum == fatfs->fat1_virt_inum) {
1567
0
                if (fatfs_make_fat(fatfs, 1, fs_file->meta)) {
1568
0
                    return 1;
1569
0
                }
1570
0
            }
1571
0
            else if (inum == fatfs->fat2_virt_inum && fatfs->numfat == 2) {
1572
0
                if (fatfs_make_fat(fatfs, 2, fs_file->meta)) {
1573
0
                    return 1;
1574
0
                }
1575
0
            }
1576
0
            else if (inum == TSK_FS_ORPHANDIR_INUM(a_fs)) {
1577
0
                if (tsk_fs_dir_make_orphan_dir_meta(a_fs, fs_file->meta)) {
1578
0
                    return 1;
1579
0
                }
1580
0
            }
1581
1582
0
            retval = a_action(fs_file.get(), a_ptr);
1583
0
            if (retval == TSK_WALK_STOP) {
1584
0
                return 0;
1585
0
            }
1586
0
            else if (retval == TSK_WALK_ERROR) {
1587
0
                return 1;
1588
0
            }
1589
0
        }
1590
0
    }
1591
1592
30
    return 0;
1593
30
}