Coverage Report

Created: 2025-08-26 06:11

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