Coverage Report

Created: 2025-07-01 06:58

/src/sleuthkit/tsk/fs/xfs.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
** The Sleuth Kit
3
**
4
** Brian Carrier [carrier <at> sleuthkit [dot] org]
5
** Copyright (c) 2003-2011 Brian Carrier.  All rights reserved
6
**
7
** ICS Laboratory [515lab.ics <at> gmail [dot] com]
8
** Copyright (c) 2019 ICS Laboratory.  All rights reserved.
9
**
10
** This software is distributed under the Common Public License 1.0
11
*/
12
13
#include "tsk_fs_i.h"
14
#include "tsk_xfs.h"
15
16
/** \internal
17
 * Add a single extent -- that is, a single data ran -- to the file data attribute.
18
 * @return 0 on success, 1 on error.
19
 */
20
static TSK_OFF_T
21
xfs_make_data_run_extent(TSK_FS_INFO * fs_info, TSK_FS_ATTR * fs_attr,
22
    xfs_bmbt_rec_t* extent)
23
0
{
24
0
    TSK_FS_ATTR_RUN *data_run;
25
0
    XFS_INFO * xfs = (XFS_INFO *)fs_info;
26
27
0
    if ((data_run = tsk_fs_attr_run_alloc()) == NULL)
28
0
        return 1;
29
    
30
0
    xfs_bmbt_irec_t *irec = (xfs_bmbt_irec_t*)tsk_malloc(sizeof(xfs_bmbt_irec_t));
31
0
    xfs_bmbt_disk_get_all(xfs, extent, irec);
32
    
33
0
    uint32_t agno =  XFS_FSB_TO_AGNO(xfs, irec->br_startblock);
34
0
    uint32_t blkno = XFS_FSB_TO_AGBNO(xfs, irec->br_startblock);
35
36
0
    data_run->offset = 0;
37
0
    data_run->addr = agno * tsk_getu32(fs_info->endian, xfs->fs->sb_agblocks) + blkno;
38
0
    data_run->len = irec->br_blockcount;
39
    
40
0
    if (tsk_fs_attr_add_run(fs_info, fs_attr, data_run)) {
41
0
        return 1;
42
0
    }
43
44
0
    free(irec);
45
46
0
    return 0;
47
0
}
48
49
/**
50
 * \internal
51
 * Loads attribute for XFS Extents-based storage method.
52
 * @param fs_file File system to analyze
53
 * @returns 0 on success, 1 otherwise
54
 */
55
static uint8_t
56
xfs_load_attrs_block(TSK_FS_FILE *fs_file)
57
0
{
58
0
    TSK_FS_META *fs_meta = fs_file->meta;
59
0
    TSK_FS_INFO *fs_info = fs_file->fs_info;
60
0
    TSK_OFF_T length = 0;
61
0
    TSK_FS_ATTR * fs_attr;
62
0
    xfs_bmbt_rec_t *rec;
63
64
0
    rec = (xfs_bmbt_rec_t*)fs_meta->content_ptr;    
65
    
66
0
    if ((fs_meta->attr != NULL)
67
0
        && (fs_meta->attr_state == TSK_FS_META_ATTR_STUDIED)) {
68
0
        fprintf(stderr, "[i] xfs_load_attr_block: xfs.cpp: %d - already studied, exiting load_attr_blk\n", __LINE__);
69
0
        return 0;
70
0
    }else if (fs_meta->attr_state == TSK_FS_META_ATTR_ERROR) {
71
0
        fprintf(stderr, "[i] xfs_load_attr_block: xfs.cpp: %d - error on attr, exiting load_attr_blk\n", __LINE__);
72
0
        return 1;
73
0
    }
74
75
0
    if (fs_meta->attr != NULL) {
76
0
        tsk_fs_attrlist_markunused(fs_meta->attr);
77
0
    }
78
0
    else {
79
0
        fs_meta->attr = tsk_fs_attrlist_alloc();
80
0
    }
81
82
0
    if (TSK_FS_TYPE_ISXFS(fs_info->ftype) == 0) {
83
0
        tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
84
0
        tsk_error_set_errstr
85
0
        ("xfs_load_attr: Called with non-xfs file system: %x",
86
0
         fs_info->ftype);
87
0
        return 1;
88
0
    }
89
90
0
    length = roundup(fs_meta->size, fs_info->block_size);
91
    
92
0
    if ((fs_attr =
93
0
         tsk_fs_attrlist_getnew(fs_meta->attr,
94
0
                                TSK_FS_ATTR_NONRES)) == NULL) {
95
0
        return 1;
96
0
    }
97
98
0
    if (tsk_fs_attr_set_run(fs_file, fs_attr, NULL, NULL,
99
0
                            TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
100
0
                            fs_meta->size, fs_meta->size, length, TSK_FS_ATTR_FLAG_NONE, 0)) {
101
0
        return 1;
102
0
    }
103
104
0
    while (true)
105
0
    {
106
0
        if (tsk_getu64(fs_info->endian, rec->l0) == 0 && tsk_getu64(fs_info->endian, rec->l1) == 0)
107
0
            break;
108
           
109
0
        if (xfs_make_data_run_extent(fs_info, fs_attr, rec)) {
110
0
            fprintf(stderr, "[i] xfs_load_attr_block: xfs.cpp: %d - xfs_make_data_run_extent failed.\n",
111
0
                __LINE__);
112
0
            return 1;
113
0
        }
114
115
0
        rec = (xfs_bmbt_rec_t*)xfs_dir2_data_nextentry((xfs_dir2_data_entry*)rec);
116
0
    }
117
    
118
0
    fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED;
119
    
120
0
    return 0;
121
0
}
122
123
/** \internal
124
 * Add the data runs and extents to the file attributes.
125
 *
126
 * @param fs_file File system to analyze
127
 * @returns 0 on success, 1 otherwise
128
 */
129
static uint8_t
130
xfs_load_attrs(TSK_FS_FILE * fs_file)
131
0
{
132
    // not needed to implement about shortform data fork. shortform does not have location of real file.
133
0
    if (fs_file->meta->content_type == TSK_FS_META_CONTENT_TYPE_XFS_DATA_FORK_EXTENTS) {
134
0
        xfs_load_attrs_block(fs_file);
135
0
    }
136
0
    else if (fs_file->meta->content_type == TSK_FS_META_CONTENT_TYPE_XFS_DATA_FORK_BTREE) {
137
0
        printf("We are devleoping this\n");
138
0
        return 1;
139
0
    }
140
0
    else if (fs_file->meta->content_type == TSK_FS_META_CONTENT_TYPE_XFS_DATA_FORK_SHORTFORM) {
141
0
        printf("We are devleoping this\n");
142
0
        return 1;
143
0
    }
144
0
    else {
145
0
        fprintf(stderr, "contenttype = unknown content type\n");
146
0
        return 1;
147
0
    }
148
149
0
    return 0;
150
0
}
151
152
153
static uint8_t
154
xfs_dinode_load(XFS_INFO * xfs, TSK_INUM_T dino_inum,
155
    xfs_dinode * dino_buf)
156
0
{
157
0
    TSK_OFF_T addr;
158
0
    ssize_t cnt;
159
0
    TSK_FS_INFO *fs = (TSK_FS_INFO *) & xfs->fs_info;
160
161
    /*
162
     * Sanity check.
163
     * Use last_num-1 to account for virtual Orphan directory in last_inum.
164
     */
165
0
    if ((dino_inum < fs->first_inum) || (dino_inum > fs->last_inum - 1)) {
166
0
        tsk_error_reset();
167
0
        tsk_error_set_errno(TSK_ERR_FS_INODE_NUM);
168
0
        tsk_error_set_errstr("xfs_dinode_load: address: %" PRIuINUM,
169
0
            dino_inum);
170
0
        return 1;
171
0
    }
172
173
0
    if (dino_buf == NULL) {
174
0
        tsk_error_reset();
175
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
176
0
        tsk_error_set_errstr("xfs_dinode_load: dino_buf is NULL");
177
0
        return 1;
178
0
    }
179
180
0
    addr = xfs_inode_get_offset(xfs, dino_inum);
181
0
    cnt = tsk_fs_read(fs, addr, (char *)dino_buf, xfs->inode_size);
182
    
183
0
    if (cnt != xfs->inode_size) {
184
0
        if (cnt >= 0) {
185
0
            tsk_error_reset();
186
0
            tsk_error_set_errno(TSK_ERR_FS_READ);
187
0
        }
188
189
0
        tsk_error_set_errstr2("xfs_dinode_load: Inode %" PRIuINUM
190
0
            " from %" PRIu64, dino_inum, addr);
191
192
0
        return 1;
193
0
    }
194
195
0
    return 0;
196
0
}
197
198
static uint8_t
199
xfs_dinode_copy(XFS_INFO * xfs, TSK_FS_META * fs_meta,
200
    TSK_INUM_T inum, const xfs_dinode * dino_buf)
201
0
{
202
0
    TSK_FS_INFO *fs = (TSK_FS_INFO *) & xfs->fs_info;
203
204
0
    if (dino_buf == NULL) {
205
0
        tsk_error_reset();
206
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
207
0
        tsk_error_set_errstr("xfs_dinode_copy: dino_buf is NULL");
208
0
        return 1;
209
0
    }
210
211
0
    fs_meta->attr_state = TSK_FS_META_ATTR_EMPTY;
212
0
    if (fs_meta->attr) {
213
0
        tsk_fs_attrlist_markunused(fs_meta->attr);
214
0
    }
215
216
    // set the type
217
0
    switch (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_FMT) {
218
0
        case XFS_IN_REG:
219
0
            fs_meta->type = TSK_FS_META_TYPE_REG;
220
0
            break;
221
0
        case XFS_IN_DIR:
222
0
            fs_meta->type = TSK_FS_META_TYPE_DIR;
223
0
            break;
224
0
        case XFS_IN_SOCK:
225
0
            fs_meta->type = TSK_FS_META_TYPE_SOCK;
226
0
            break;
227
0
        case XFS_IN_LNK:
228
0
            fs_meta->type = TSK_FS_META_TYPE_LNK;
229
0
            break;
230
0
        case XFS_IN_BLK:
231
0
            fs_meta->type = TSK_FS_META_TYPE_BLK;
232
0
            break;
233
0
        case XFS_IN_CHR:
234
0
            fs_meta->type = TSK_FS_META_TYPE_CHR;
235
0
            break;
236
0
        case XFS_IN_FIFO:
237
0
            fs_meta->type = TSK_FS_META_TYPE_FIFO;
238
0
            break;
239
0
        default:
240
0
            fs_meta->type = TSK_FS_META_TYPE_UNDEF;
241
0
            break;
242
0
    }
243
244
    // set the mode
245
0
    fs_meta->mode = TSK_FS_META_MODE_ENUM(0);
246
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_ISUID)
247
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_ISUID);
248
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_ISGID)
249
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_ISGID);
250
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_ISVTX)
251
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_ISVTX);
252
253
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_IRUSR)
254
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_IRUSR);
255
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_IWUSR)
256
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_IWUSR);
257
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_IXUSR)
258
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_IXUSR);
259
260
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_IRGRP)
261
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_IRGRP);
262
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_IWGRP)
263
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_IWGRP);
264
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_IXGRP)
265
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_IXGRP);
266
267
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_IROTH)
268
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_IROTH);
269
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_IWOTH)
270
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_IWOTH);
271
0
    if (tsk_getu16(fs->endian, dino_buf->di_mode) & XFS_IN_IXOTH)
272
0
        fs_meta->mode = TSK_FS_META_MODE_ENUM(fs_meta->mode | TSK_FS_META_MODE_IXOTH);
273
274
0
    fs_meta->nlink = tsk_getu32(fs->endian, dino_buf->di_nlink);
275
0
    fs_meta->size = tsk_getu64(fs->endian, dino_buf->di_size);
276
0
    fs_meta->addr = inum;
277
278
279
    /* the general size value in the inode is only 32-bits,
280
     * but the i_dir_acl value is used for regular files to
281
     * hold the upper 32-bits
282
     *
283
     * The RO_COMPAT_LARGE_FILE flag in the super block will identify
284
     * if there are any large files in the file system
285
     */
286
0
    fs_meta->uid = tsk_getu32(fs->endian, dino_buf->di_uid);
287
0
    fs_meta->gid = tsk_getu32(fs->endian, dino_buf->di_gid);
288
289
0
    fs_meta->mtime = dino_buf->di_mtime.t_sec;
290
0
    fs_meta->atime = dino_buf->di_atime.t_sec;
291
0
    fs_meta->ctime = dino_buf->di_ctime.t_sec;
292
293
0
    fs_meta->mtime_nano = dino_buf->di_mtime.t_nsec;            
294
0
    fs_meta->atime_nano = dino_buf->di_atime.t_nsec;
295
0
    fs_meta->ctime_nano = dino_buf->di_ctime.t_nsec;
296
0
    fs_meta->seq = 0;
297
298
0
    if (fs_meta->link) {
299
0
         free(fs_meta->link);
300
0
         fs_meta->link = NULL;
301
0
    }
302
303
0
    if (fs_meta->content_len != (size_t)XFS_CONTENT_LEN_V5(xfs)) {
304
0
         if (tsk_verbose) {
305
0
            fprintf(stderr, "xfs.cpp: content_len is not XFS_CONTENT_LEN_V5\n");
306
0
         }
307
308
0
         if ((fs_meta =
309
0
                 tsk_fs_meta_realloc(fs_meta,
310
0
                     XFS_CONTENT_LEN_V5(xfs))) == NULL) {
311
0
             return 1;
312
0
         }
313
0
    }
314
    
315
    // Allocating datafork area in content_ptr
316
    // Contents after inode core must be copied to content ptr
317
0
    TSK_OFF_T dfork_offset = xfs_inode_get_offset(xfs, inum) + sizeof(xfs_dinode);
318
    
319
0
    ssize_t cnt = tsk_fs_read(fs, dfork_offset, (char*)fs_meta->content_ptr, XFS_CONTENT_LEN_V5(xfs));
320
321
0
    if (cnt != XFS_CONTENT_LEN_V5(xfs)){
322
0
        if (tsk_verbose) {
323
0
            fprintf(stderr, "invalid datafork read size, cnt: %ld\n", cnt);
324
0
        }
325
0
        return -1;
326
0
    }
327
  
328
0
    if (dino_buf->di_format == XFS_DINODE_FMT_LOCAL){
329
0
        fs_meta->content_type = TSK_FS_META_CONTENT_TYPE_XFS_DATA_FORK_SHORTFORM;  
330
0
    }
331
0
    else if (dino_buf->di_format == XFS_DINODE_FMT_EXTENTS){
332
0
        fs_meta->content_type = TSK_FS_META_CONTENT_TYPE_XFS_DATA_FORK_EXTENTS;
333
0
    }
334
0
    else if (dino_buf->di_format == XFS_DINODE_FMT_BTREE){
335
0
        fs_meta->content_type = TSK_FS_META_CONTENT_TYPE_XFS_DATA_FORK_BTREE;
336
0
    }
337
0
    else{
338
0
        fprintf(stderr, "xfs : inode core format not supported : inode format %d\n", dino_buf->di_format);
339
0
    } 
340
0
    return 0;
341
0
}    
342
343
uint8_t xfs_inode_walk(TSK_FS_INFO * fs, TSK_INUM_T start_inum, TSK_INUM_T end_inum,
344
    TSK_FS_META_FLAG_ENUM flags,[[maybe_unused]] TSK_FS_META_WALK_CB a_action, [[maybe_unused]]void *a_ptr)
345
0
{
346
0
    const char *myname = "xfs_inode_walk";
347
0
    TSK_FS_FILE * fs_file;
348
349
0
    tsk_error_reset();
350
351
0
    if(start_inum < fs->first_inum || start_inum > fs->last_inum){
352
0
        tsk_error_reset();
353
0
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
354
0
        tsk_error_set_errstr("%s: start inode: %" PRIu64 "", myname, start_inum);
355
0
        return 1;
356
0
    }
357
0
    if(end_inum < fs->first_inum || end_inum > fs->last_inum || end_inum < start_inum){
358
0
        tsk_error_reset();
359
0
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
360
0
        tsk_error_set_errstr("%s: end inode: %" PRIu64 "", myname, end_inum);
361
0
        return 1;
362
0
    }
363
364
0
    if (flags & TSK_FS_META_FLAG_ORPHAN) {
365
0
        flags = TSK_FS_META_FLAG_ENUM(flags | TSK_FS_META_FLAG_UNALLOC);
366
0
        flags = TSK_FS_META_FLAG_ENUM(flags & ~TSK_FS_META_FLAG_ALLOC);
367
0
        flags = TSK_FS_META_FLAG_ENUM(flags | TSK_FS_META_FLAG_USED);
368
0
        flags = TSK_FS_META_FLAG_ENUM(flags & ~TSK_FS_META_FLAG_UNUSED);
369
0
    }
370
0
    else {
371
0
        if (((flags & TSK_FS_META_FLAG_ALLOC) == 0) &&
372
0
            ((flags & TSK_FS_META_FLAG_UNALLOC) == 0)) {
373
0
             flags = TSK_FS_META_FLAG_ENUM(flags | TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_UNALLOC);
374
0
        }
375
376
        /* If neither of the USED or UNUSED flags are set, then set them
377
         * both
378
         */
379
0
        if (((flags & TSK_FS_META_FLAG_USED) == 0) &&
380
0
            ((flags & TSK_FS_META_FLAG_UNUSED) == 0)) {
381
0
            flags = TSK_FS_META_FLAG_ENUM(flags | TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_UNUSED);
382
0
        }
383
0
    }
384
    /* If we are looking for orphan files and have not yet filled
385
     * in the list of unalloc inodes that are pointed to, then fill
386
     * in the list
387
     */
388
0
    if ((flags & TSK_FS_META_FLAG_ORPHAN)) {
389
0
        if (tsk_fs_dir_load_inum_named(fs) != TSK_OK) {
390
0
            tsk_error_errstr2_concat
391
0
                ("- ext2fs_inode_walk: identifying inodes allocated by file names");
392
0
            return 1;
393
0
        }
394
0
    }
395
0
    if ((fs_file = tsk_fs_file_alloc(fs)) == NULL)
396
0
        return 1;
397
398
0
    return -1;
399
0
}
400
401
//block walk
402
uint8_t xfs_block_walk([[maybe_unused]] TSK_FS_INFO * fs, [[maybe_unused]] TSK_DADDR_T start, [[maybe_unused]]TSK_DADDR_T end, 
403
    [[maybe_unused]]TSK_FS_BLOCK_WALK_FLAG_ENUM flags,[[maybe_unused]] TSK_FS_BLOCK_WALK_CB cb, [[maybe_unused]]void *ptr)
404
0
{
405
0
    return -1;
406
0
}
407
408
//block_getflags
409
TSK_FS_BLOCK_FLAG_ENUM xfs_block_getflags([[maybe_unused]]TSK_FS_INFO * a_fs, [[maybe_unused]]TSK_DADDR_T a_addr)
410
0
{
411
0
    return TSK_FS_BLOCK_FLAG_UNUSED;
412
0
}
413
414
static uint8_t 
415
xfs_inode_lookup(TSK_FS_INFO * fs, TSK_FS_FILE * a_fs_file,  // = file_add_meta
416
    TSK_INUM_T inum)
417
0
{
418
0
    XFS_INFO * xfs = (XFS_INFO *) fs;
419
0
    xfs_dinode * dino_buf = NULL;
420
0
    unsigned int size = 0;
421
422
0
    if (a_fs_file == NULL) {
423
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
424
0
        tsk_error_set_errstr("ext2fs_inode_lookup: fs_file is NULL");
425
0
        return 1;
426
0
    }
427
428
0
    if (a_fs_file->meta == NULL) {
429
0
        if ((a_fs_file->meta =      
430
0
                tsk_fs_meta_alloc(XFS_CONTENT_LEN_V5(xfs))) == NULL) // #define XFS_CONTENT_LEN 
431
0
            return 1;
432
0
    }
433
0
    else {
434
0
        tsk_fs_meta_reset(a_fs_file->meta);
435
0
    }
436
    
437
    // see if they are looking for the special "orphans" directory
438
0
    if (inum == TSK_FS_ORPHANDIR_INUM(fs)) {
439
0
        if (tsk_fs_dir_make_orphan_dir_meta(fs, a_fs_file->meta))
440
0
            return 1;
441
0
        else
442
0
            return 0;
443
0
    }
444
445
0
    size =
446
0
        xfs->inode_size > 
447
0
        sizeof(xfs_dinode) ? xfs->inode_size : sizeof(xfs_dinode);
448
449
0
    if((dino_buf = (xfs_dinode *)tsk_malloc(size)) == NULL){
450
0
        return 1;
451
0
    }
452
   
453
0
    if (xfs_dinode_load(xfs, inum, dino_buf)){
454
0
        free(dino_buf);
455
0
        return 1;
456
0
    }
457
0
    if (xfs_dinode_copy(xfs, a_fs_file->meta, inum, dino_buf)){
458
0
        free(dino_buf);
459
0
        return 1;
460
0
    }
461
462
    // Trick to walk unalloc file and dent
463
0
    if (a_fs_file->name != NULL){
464
0
        if ((TSK_FS_IS_DIR_META(a_fs_file->meta->type) == 0) && (TSK_FS_IS_DIR_NAME(a_fs_file->name->type) == 0) 
465
0
            && ((a_fs_file->name->type == TSK_FS_NAME_TYPE_UNDEF) == 0) && (a_fs_file->meta->size == 0)) 
466
0
        {
467
0
            xfs_bmbt_irec_t *irec = (xfs_bmbt_irec_t*)tsk_malloc(sizeof(xfs_bmbt_irec_t));
468
0
            xfs_bmbt_disk_get_all(xfs, (xfs_bmbt_rec*) a_fs_file->meta->content_ptr, irec);
469
0
            a_fs_file->meta->size = irec->br_blockcount * fs->block_size;
470
471
0
        }  
472
0
        else if(a_fs_file->meta->type == TSK_FS_META_TYPE_UNDEF) {
473
0
            tsk_fs_meta_reset(a_fs_file->meta);
474
            // if ((a_fs_file->meta = tsk_fs_meta_alloc(XFS_CONTENT_LEN_V5(xfs))) == NULL) // #define XFS_CONTENT_LEN 
475
            //     return 1;        
476
477
0
            dino_buf->di_mode[0] = 0x41;
478
0
            dino_buf->di_mode[1] = 0xED;
479
480
0
            if(xfs_dinode_copy(xfs, a_fs_file->meta, inum, dino_buf)){
481
0
                free(dino_buf);
482
0
                return 1;
483
0
            }
484
0
            a_fs_file->meta->flags = TSK_FS_META_FLAG_UNALLOC;
485
0
            a_fs_file->name->flags = TSK_FS_NAME_FLAG_UNALLOC;
486
0
        }
487
0
    }
488
489
0
    free(dino_buf);
490
0
    return 0;
491
0
}
492
493
//fsstat
494
uint8_t xfs_fsstat(TSK_FS_INFO * fs, FILE * hFile)
495
0
{
496
0
    XFS_INFO * xfs = (XFS_INFO *) fs;
497
0
    xfs_sb *sb = xfs->fs;
498
    
499
0
    const char *tmptypename;
500
    
501
0
    tsk_error_reset();
502
0
    tsk_fprintf(hFile, "FILE SYSTEM INFORMATION\n");
503
0
    tsk_fprintf(hFile, "--------------------------------------------\n");
504
    
505
0
    if (tsk_getu32(fs->endian, sb->sb_magicnum) == XFS_FS_MAGIC)
506
0
        tmptypename = "XFS";
507
    
508
0
    tsk_fprintf(hFile, "File System Type : %s\n", tmptypename);
509
0
    tsk_fprintf(hFile, "Volume Name : %s\n", sb->sb_fname);
510
0
    tsk_fprintf(hFile, "\n");
511
    
512
    
513
0
    if(tsk_getu32(fs->endian, sb->sb_features_incompat)) {
514
0
        tsk_fprintf(hFile, "InCompat Features: ");
515
        
516
0
        if (tsk_getu32(fs->endian, sb->sb_features_incompat) &
517
0
            XFS_SB_FEAT_INCOMPAT_FTYPE)
518
0
            tsk_fprintf(hFile, "Directory file type, ");
519
0
        if (tsk_getu32(fs->endian, sb->sb_features_incompat) &
520
0
            XFS_SB_FEAT_INCOMPAT_SPINODES)
521
0
            tsk_fprintf(hFile, "Sparse inodes, ");
522
0
        if (tsk_getu32(fs->endian, sb->sb_features_incompat) &
523
0
            XFS_SB_FEAT_INCOMPAT_META_UUID)
524
0
            tsk_fprintf(hFile, "Metadata UUID");
525
        
526
0
        tsk_fprintf(hFile, "\n");
527
0
    }
528
    
529
0
    if(tsk_getu32(fs->endian, sb->sb_features_ro_compat)) {
530
0
        tsk_fprintf(hFile, "Read Only Compat Features : " );
531
        
532
0
        if (tsk_getu32(fs->endian, sb->sb_features_ro_compat) &
533
0
            XFS_SB_FEAT_RO_COMPAT_FINOBT)
534
0
            tsk_fprintf(hFile, "Free inode B+tree, ");
535
0
        if (tsk_getu32(fs->endian, sb->sb_features_ro_compat) &
536
0
            XFS_SB_FEAT_RO_COMPAT_RMAPBT)
537
0
            tsk_fprintf(hFile, "Reverse mapping B+tree, ");
538
0
        if (tsk_getu32(fs->endian, sb->sb_features_ro_compat) &
539
0
            XFS_SB_FEAT_RO_COMPAT_REFLINK)
540
0
            tsk_fprintf(hFile, "Reference count B+tree");
541
        
542
0
        tsk_fprintf(hFile, "\n");
543
0
    }
544
    
545
0
    tsk_fprintf(hFile, "\nMETADATA INFORMATION\n");
546
0
    tsk_fprintf(hFile, "--------------------------------------------\n");
547
0
    tsk_fprintf(hFile, "Root Inode : %" PRIu64 "\n", tsk_getu64(fs->endian, sb->sb_rootino));
548
0
    tsk_fprintf(hFile, "Inode Count : %" PRIu64 "\n", tsk_getu64(fs->endian, sb->sb_icount));
549
0
    tsk_fprintf(hFile, "Free Inode Count : %" PRIu64 "\n", tsk_getu64(fs->endian, sb->sb_ifree));
550
0
    tsk_fprintf(hFile, "Inode Size : %" PRIu16 "\n", tsk_getu16(fs->endian, sb->sb_inodesize));
551
0
    tsk_fprintf(hFile, "Inode per Block : %" PRIu8 "\n", sb->sb_inopblog);
552
    
553
0
    tsk_fprintf(hFile, "\nCONTENT INFORMATION\n");
554
0
    tsk_fprintf(hFile, "--------------------------------------------\n");
555
0
    tsk_fprintf(hFile, "Block Range : %" PRIuINUM " - %" PRIuINUM "\n", fs->first_block, fs->last_block);
556
0
    tsk_fprintf(hFile, "Block Size : %" PRIu32 "\n", tsk_getu32(fs->endian, sb->sb_blocksize));
557
0
    tsk_fprintf(hFile, "Block Count : %" PRIu64 "\n", tsk_getu64(fs->endian, sb->sb_dblocks));
558
0
    tsk_fprintf(hFile, "Free Block Count : %" PRIu64 "\n", tsk_getu64(fs->endian, sb->sb_fdblocks));
559
0
    tsk_fprintf(hFile, "Allocation Group Block Size : % " PRIu32 "\n", tsk_getu32(fs->endian, sb->sb_agblocks));
560
0
    tsk_fprintf(hFile, "Allocation Group Count : %" PRIu32 "\n", tsk_getu32(fs->endian, sb->sb_agcount));
561
0
    tsk_fprintf(hFile, "Sector Size : %" PRIu16 "\n", tsk_getu16(fs->endian, sb->sb_sectsize));
562
    
563
0
    tsk_fprintf(hFile, "\nLOG INFORMATION\n");
564
0
    tsk_fprintf(hFile, "——————————————————————\n");
565
0
    tsk_fprintf(hFile, "Log2 of Block Size : %" PRIu8 "\n", sb->sb_blocklog);
566
0
    tsk_fprintf(hFile, "Log2 of Sector Size : %" PRIu8 "\n", sb->sb_sectlog);
567
0
    tsk_fprintf(hFile, "Log2 of Inode Size : %" PRIu8 "\n", sb->sb_inodelog);
568
0
    tsk_fprintf(hFile, "Log2 of Inode per Block : %" PRIu8 "\n", sb->sb_inopblog);
569
0
    tsk_fprintf(hFile, "Log2 of Allocation Block Size : %" PRIu8 "\n", sb->sb_agblklog);
570
0
    tsk_fprintf(hFile, "Log2 of Extent Count : %" PRIu8 "\n", sb->sb_rextslog);
571
0
    tsk_fprintf(hFile, "Log2 of Extent Count : %" PRIu8 "\n", sb->sb_inprogress);
572
0
    tsk_fprintf(hFile, "Inode max persentage : %" PRIu8 "\n", sb->sb_imax_pct);
573
    
574
0
    return -1;
575
0
}
576
577
uint8_t xfs_fscheck([[maybe_unused]] TSK_FS_INFO * fs,[[maybe_unused]] FILE * HFile)
578
0
{
579
0
    return -1;
580
0
}
581
582
uint8_t xfs_istat([[maybe_unused]]TSK_FS_INFO * fs, [[maybe_unused]]TSK_FS_ISTAT_FLAG_ENUM flags,[[maybe_unused]] FILE * hFile,[[maybe_unused]] TSK_INUM_T inum,
583
            [[maybe_unused]]TSK_DADDR_T numblock, [[maybe_unused]]int32_t sec_skew)
584
0
{
585
0
    return -1;
586
0
}
587
588
void xfs_close(TSK_FS_INFO * fs)
589
0
{
590
0
    XFS_INFO * xfs = (XFS_INFO *) fs;
591
592
0
    fs->tag = 0;
593
0
    free(xfs->fs);
594
0
    free(xfs->bmap_buf);
595
0
    free(xfs->imap_buf);
596
    
597
0
    tsk_deinit_lock(&xfs->lock);
598
0
    tsk_fs_free(fs);
599
0
    return;
600
0
}
601
602
TSK_FS_INFO *
603
xfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset,
604
    TSK_FS_TYPE_ENUM ftype, [[maybe_unused]] const char* a_pass, [[maybe_unused]] uint8_t test)
605
0
{
606
0
    XFS_INFO *xfs;
607
0
    unsigned int len;
608
0
    TSK_FS_INFO *fs;
609
0
    ssize_t cnt;
610
611
0
    tsk_error_reset();
612
613
0
    if(TSK_FS_TYPE_ISXFS(ftype) == 0){
614
0
        tsk_error_reset();
615
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
616
0
        tsk_error_set_errstr("Invalid FS Type in xfs_open");
617
0
        return NULL;
618
0
    }
619
620
0
    if (img_info->sector_size == 0) {
621
0
        tsk_error_reset();
622
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
623
0
        tsk_error_set_errstr("xfs_open: sector size is 0");
624
0
        return NULL;
625
0
    }
626
627
0
    if ((xfs = (XFS_INFO *) tsk_fs_malloc(sizeof(*xfs))) == NULL)
628
0
        return NULL;
629
0
    fs = &(xfs->fs_info);
630
0
    fs->ftype = ftype;
631
0
    fs->flags = TSK_FS_INFO_FLAG_NONE;
632
0
    fs->img_info = img_info;
633
0
    fs->offset = offset;
634
0
    fs->tag = TSK_FS_INFO_TAG;
635
636
0
    len = sizeof(xfs_sb);    
637
638
0
    if ((xfs->fs = (xfs_sb *) tsk_malloc(len)) == NULL) {
639
0
        fs->tag = 0;
640
0
        tsk_fs_free((TSK_FS_INFO *)xfs);
641
0
        return NULL;
642
0
    }
643
0
    cnt = tsk_fs_read(fs, XFS_SBOFF, (char *) xfs->fs, len);
644
645
0
    if (cnt != len){
646
0
        if (cnt >= 0) {
647
0
            tsk_error_reset();
648
0
            tsk_error_set_errno(TSK_ERR_FS_READ);
649
0
        }
650
0
        tsk_error_set_errstr("xfs_open: superblock");
651
0
        fs->tag = 0;
652
0
        free(xfs->fs);
653
0
        tsk_fs_free((TSK_FS_INFO *)xfs);
654
0
        return NULL;
655
0
    }
656
    
657
658
0
    if(tsk_fs_guessu32(fs, xfs->fs->sb_magicnum, XFS_FS_MAGIC)){
659
0
        if (tsk_verbose){
660
0
            fprintf(stderr, "xfs_open : superblock magic failed\n");
661
0
            fprintf(stderr, "xfs_open : superblock read : %x%x%x%x\n", 
662
0
                xfs->fs->sb_magicnum[0], xfs->fs->sb_magicnum[1], xfs->fs->sb_magicnum[2], xfs->fs->sb_magicnum[3]);
663
0
        }
664
665
0
        fs->tag = 0;
666
0
        free(xfs->fs);
667
0
        tsk_fs_free((TSK_FS_INFO *)xfs);
668
0
        tsk_error_reset();
669
0
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
670
0
        tsk_error_set_errstr("not an xfs file system (magic)");
671
        
672
0
        if (tsk_verbose)
673
0
            fprintf(stderr, "xfs_open : invalid magic\n");
674
0
        return NULL;
675
0
    }
676
677
0
    fs->inum_count = tsk_getu64(fs->endian, xfs->fs->sb_icount);
678
0
    fs->last_inum = 0xFFFFFFFFFFFFFFFF;
679
0
    fs->first_inum = XFS_FIRSTINO;
680
0
    fs->root_inum = tsk_getu64(fs->endian, xfs->fs->sb_rootino);
681
    
682
0
    if (tsk_getu64(fs->endian, xfs->fs->sb_icount) < 10) {
683
0
        fs->tag = 0;
684
0
        free(xfs->fs);
685
0
        tsk_fs_free((TSK_FS_INFO *)xfs);
686
0
        tsk_error_reset();
687
0
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
688
0
        tsk_error_set_errstr("Not an XFS file system (inum count)");
689
0
        if (tsk_verbose)
690
0
            fprintf(stderr, "xfs_open: two few inodes\n");
691
0
        return NULL;
692
0
    }
693
    /* Set the size of the inode, but default to our data structure
694
     * size if it is larger */
695
0
    xfs->inode_size = tsk_getu16(fs->endian, xfs->fs->sb_inodesize);
696
0
    if (xfs->inode_size < sizeof(xfs_dinode)) {
697
0
        if (tsk_verbose)
698
0
            tsk_fprintf(stderr, "SB inode size is small");
699
0
    }
700
701
    /*
702
     * Calculate the block info
703
     */
704
0
    fs->dev_bsize = img_info->sector_size;
705
0
    fs->first_block = 0;
706
0
    fs->block_count = (TSK_DADDR_T)tsk_getu64(fs->endian, xfs->fs->sb_dblocks);
707
0
    fs->last_block_act = fs->last_block = fs->block_count - 1;
708
0
    fs->block_size = tsk_getu32(fs->endian, xfs->fs->sb_blocksize);
709
710
0
    if((fs->block_size == 0) || (fs->block_size % 512)){
711
0
        fs->tag = 0;
712
0
        free(xfs->fs);
713
0
        tsk_fs_free((TSK_FS_INFO *)xfs);
714
0
        tsk_error_reset();
715
0
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
716
0
        tsk_error_set_errstr("Not an XFS file system (block size)");
717
0
        if(tsk_verbose)
718
0
            fprintf(stderr, "xfs_open : invalid block size\n");
719
0
        return NULL;
720
0
    }
721
722
0
    if ((TSK_DADDR_T) ((img_info->size - offset) / fs->block_size) <
723
0
        fs->block_count)
724
0
        fs->last_block_act =
725
0
            (img_info->size - offset) / fs->block_size - 1;
726
727
    /* Volume ID */
728
0
    for(fs->fs_id_used = 0 ; fs->fs_id_used < 16; fs->fs_id_used++){
729
0
        fs->fs_id[fs->fs_id_used] = xfs->fs->sb_uuid[fs->fs_id_used];
730
0
    }
731
732
    /* Set the generic function pointers */
733
0
    fs->inode_walk = xfs_inode_walk;
734
0
    fs->block_walk = xfs_block_walk;
735
0
    fs->block_getflags = xfs_block_getflags;
736
737
0
    fs->get_default_attr_type = tsk_fs_unix_get_default_attr_type;
738
0
    fs->load_attrs = xfs_load_attrs;
739
740
0
    fs->file_add_meta = xfs_inode_lookup;
741
0
    fs->dir_open_meta = xfs_dir_open_meta;
742
0
    fs->fsstat = xfs_fsstat;
743
0
    fs->fscheck = xfs_fscheck;
744
0
    fs->istat = xfs_istat;
745
0
    fs->name_cmp = tsk_fs_unix_name_cmp;
746
0
    fs->close = xfs_close;
747
748
    /*
749
     * Print some stats.
750
     */
751
0
    if (tsk_verbose)
752
0
        tsk_fprintf(stderr,
753
0
            "inodes %" PRIu32 " root ino %" PRIuINUM " blocks %" PRIu32
754
0
            " inodes/block %" PRIu32 "\n", tsk_getu64(fs->endian,
755
0
                xfs->fs->sb_icount),
756
0
            fs->root_inum, tsk_getu64(fs->endian,
757
0
                xfs->fs->sb_dblocks), tsk_getu16(fs->endian,
758
0
                xfs->fs->sb_inopblock));
759
760
0
    tsk_init_lock(&xfs->lock);
761
762
0
    return (fs);
763
0
}
764