Coverage Report

Created: 2025-11-11 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sleuthkit/tsk/fs/fs_attrlist.c
Line
Count
Source
1
/*
2
 ** fs_attrlist
3
 ** The Sleuth Kit
4
 **
5
 ** Brian Carrier [carrier <at> sleuthkit [dot] org]
6
 ** Copyright (c) 2008-2011 Brian Carrier.  All Rights reserved
7
 **
8
 ** This software is distributed under the Common Public License 1.0
9
 */
10
11
/**
12
 * \file fs_attrlist.c
13
 * File that contains functions to process TSK_FS_ATTRLIST structures, which
14
 * hold a linked list of TSK_FS_ATTR attribute structures.
15
 */
16
17
#include "tsk_fs_i.h"
18
19
/** \internal
20
 * Allocate a new data list structure
21
 *
22
 * @returns Pointer to new list structure or NULL on error
23
 */
24
TSK_FS_ATTRLIST *
25
tsk_fs_attrlist_alloc()
26
967k
{
27
967k
    TSK_FS_ATTRLIST *fs_attrlist;
28
29
967k
    if ((fs_attrlist =
30
967k
            (TSK_FS_ATTRLIST *) tsk_malloc(sizeof(TSK_FS_ATTRLIST))) ==
31
967k
        NULL)
32
0
        return NULL;
33
967k
    return fs_attrlist;
34
967k
}
35
36
/** \internal
37
 * Free a list and the attributes inside of it
38
 */
39
void
40
tsk_fs_attrlist_free(TSK_FS_ATTRLIST * a_fs_attrlist)
41
967k
{
42
967k
    TSK_FS_ATTR *fs_attr_cur, *fs_attr_tmp;
43
967k
    if (a_fs_attrlist == NULL)
44
0
        return;
45
46
967k
    fs_attr_cur = a_fs_attrlist->head;
47
3.54M
    while (fs_attr_cur) {
48
2.57M
        fs_attr_tmp = fs_attr_cur->next;
49
2.57M
        tsk_fs_attr_free(fs_attr_cur);
50
2.57M
        fs_attr_cur = fs_attr_tmp;
51
2.57M
    }
52
967k
    free(a_fs_attrlist);
53
967k
}
54
55
/** \internal
56
 * Add a new attribute to the list.
57
 *
58
 * @param a_fs_attrlist List structure to add to
59
 * @param a_fs_attr Data attribute to add
60
 * @returns 1 on error and 0 on success. Caller must free memory on error.
61
 */
62
uint8_t
63
tsk_fs_attrlist_add(TSK_FS_ATTRLIST * a_fs_attrlist,
64
    TSK_FS_ATTR * a_fs_attr)
65
2.58M
{
66
2.58M
    if (a_fs_attrlist == NULL) {
67
0
        tsk_error_reset();
68
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
69
0
        tsk_error_set_errstr("Null list in tsk_fs_attrlist_add");
70
0
        return 1;
71
0
    }
72
73
    // verify INUSE is set
74
2.58M
    a_fs_attr->flags |= TSK_FS_ATTR_INUSE;
75
76
2.58M
    if (a_fs_attrlist->head == NULL) {
77
932k
        a_fs_attrlist->head = a_fs_attr;
78
932k
    }
79
1.64M
    else {
80
1.64M
        TSK_FS_ATTR *fs_attr_cur;
81
1.64M
        fs_attr_cur = a_fs_attrlist->head;
82
5.00M
        while (fs_attr_cur) {
83
            // check if it already exists
84
5.00M
            if ((fs_attr_cur->type == a_fs_attr->type)
85
87.6k
                && (fs_attr_cur->id == a_fs_attr->id)) {
86
3.26k
                tsk_error_reset();
87
3.26k
                tsk_error_set_errno(TSK_ERR_FS_ARG);
88
3.26k
                tsk_error_set_errstr
89
3.26k
                    ("datalist_add: Type %d and Id %d already in list",
90
3.26k
                    a_fs_attr->type, a_fs_attr->id);
91
3.26k
                return 1;
92
3.26k
            }
93
5.00M
            if (fs_attr_cur->next == NULL) {
94
1.64M
                fs_attr_cur->next = a_fs_attr;
95
1.64M
                break;
96
1.64M
            }
97
3.35M
            fs_attr_cur = fs_attr_cur->next;
98
3.35M
        }
99
1.64M
    }
100
2.57M
    return 0;
101
2.58M
}
102
103
104
105
/**
106
 * \internal
107
 * Return either an empty element in the list or create a new one at the end
108
 *
109
 * Preference is given to finding one of the same type to prevent
110
 * excessive malloc's, but if one is not found then a different
111
 * type is used: type = [TSK_FS_ATTR_NONRES | TSK_FS_ATTR_RES]
112
 *
113
 * @param a_fs_attrlist Attribute list to search
114
 * @param a_atype Preference for attribute type to reuse
115
 * @return NULL on error or attribute in list to use
116
 */
117
TSK_FS_ATTR *
118
tsk_fs_attrlist_getnew(TSK_FS_ATTRLIST * a_fs_attrlist,
119
    TSK_FS_ATTR_FLAG_ENUM a_atype)
120
2.72M
{
121
2.72M
    TSK_FS_ATTR *fs_attr_cur;
122
2.72M
    TSK_FS_ATTR *fs_attr_ok = NULL;
123
124
2.72M
    if (a_fs_attrlist == NULL) {
125
0
        tsk_error_reset();
126
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
127
0
        tsk_error_set_errstr("Null list in tsk_fs_attrlist_getnew()");
128
0
        return NULL;
129
0
    }
130
131
2.72M
    if ((a_atype != TSK_FS_ATTR_NONRES) && (a_atype != TSK_FS_ATTR_RES)) {
132
0
        tsk_error_reset();
133
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
134
0
        tsk_error_set_errstr("Invalid Type in tsk_fs_attrlist_getnew()");
135
0
        return NULL;
136
0
    }
137
138
7.87M
    for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur;
139
5.29M
        fs_attr_cur = fs_attr_cur->next) {
140
5.29M
        if (fs_attr_cur->flags == 0) {
141
148k
            if (a_atype == TSK_FS_ATTR_NONRES) {
142
0
                if (fs_attr_cur->nrd.run)
143
0
                    break;
144
0
                else if (!fs_attr_ok)
145
0
                    fs_attr_ok = fs_attr_cur;
146
0
            }
147
            /* we want one with an allocated buf */
148
148k
            else {
149
148k
                if (fs_attr_cur->rd.buf_size)
150
148k
                    break;
151
0
                else if (!fs_attr_ok)
152
0
                    fs_attr_ok = fs_attr_cur;
153
148k
            }
154
148k
        }
155
5.29M
    }
156
157
    /* if we fell out then check fs_attr_tmp */
158
2.72M
    if (!fs_attr_cur) {
159
2.58M
        if (fs_attr_ok)
160
0
            fs_attr_cur = fs_attr_ok;
161
2.58M
        else {
162
            /* make a new one */
163
2.58M
            if ((fs_attr_cur = tsk_fs_attr_alloc(a_atype)) == NULL)
164
0
                return NULL;
165
166
            // add it to the list
167
2.58M
            if (tsk_fs_attrlist_add(a_fs_attrlist, fs_attr_cur)) {
168
3.26k
                tsk_fs_attr_free(fs_attr_cur);
169
3.26k
                return NULL;
170
3.26k
            }
171
2.58M
        }
172
2.58M
    }
173
174
2.72M
    fs_attr_cur->flags = (TSK_FS_ATTR_INUSE | a_atype);
175
2.72M
    return fs_attr_cur;
176
2.72M
}
177
178
179
/** \internal
180
 * Cycle through the attributes and mark them as unused.  Does not free anything.
181
 * @param a_fs_attrlist Attribute list too mark.
182
 */
183
void
184
tsk_fs_attrlist_markunused(TSK_FS_ATTRLIST * a_fs_attrlist)
185
614k
{
186
614k
    TSK_FS_ATTR *fs_attr_cur;
187
614k
    if (a_fs_attrlist == NULL)
188
0
        return;
189
190
614k
    fs_attr_cur = a_fs_attrlist->head;
191
1.35M
    while (fs_attr_cur) {
192
744k
        tsk_fs_attr_clear(fs_attr_cur);
193
744k
        fs_attr_cur = fs_attr_cur->next;
194
744k
    }
195
614k
}
196
197
/**
198
 * \internal
199
 * Search the attribute list of TSK_FS_ATTR structures for an entry with a given
200
 * type (no ID).  If more than one entry with the same type exists, the one with
201
 * the lowest ID will be returned.
202
 *
203
 * @param a_fs_attrlist Data list structure to search in
204
 * @param a_type Type of attribute to find
205
 *
206
 * @return NULL is returned on error and if an entry could not be found.
207
 * tsk_errno will be set to TSK_ERR_FS_ATTR_NOTFOUND if entry could not be found.
208
 */
209
const TSK_FS_ATTR *
210
tsk_fs_attrlist_get(const TSK_FS_ATTRLIST * a_fs_attrlist,
211
    TSK_FS_ATTR_TYPE_ENUM a_type)
212
9.62M
{
213
9.62M
    TSK_FS_ATTR *fs_attr_cur;
214
9.62M
    TSK_FS_ATTR *fs_attr_ok = NULL;
215
216
9.62M
    if (!a_fs_attrlist) {
217
1.09k
        tsk_error_reset();
218
1.09k
        tsk_error_set_errno(TSK_ERR_FS_ARG);
219
1.09k
        tsk_error_set_errstr("tsk_fs_attrlist_get: Null list pointer");
220
1.09k
        return NULL;
221
1.09k
    }
222
223
23.5M
    for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur;
224
13.8M
        fs_attr_cur = fs_attr_cur->next) {
225
13.8M
        if ((fs_attr_cur->flags & TSK_FS_ATTR_INUSE)
226
13.8M
            && (fs_attr_cur->type == a_type)) {
227
228
            /* If we are looking for NTFS $Data,
229
             * then return default when we see it */
230
9.61M
            if ((fs_attr_cur->type == TSK_FS_ATTR_TYPE_NTFS_DATA) &&
231
2.20k
                (fs_attr_cur->name == NULL)) {
232
2.20k
                return fs_attr_cur;
233
2.20k
            }
234
235
            // make sure we return the lowest if multiple exist
236
9.61M
            if ((fs_attr_ok == NULL) || (fs_attr_ok->id > fs_attr_cur->id))
237
9.61M
                fs_attr_ok = fs_attr_cur;
238
9.61M
        }
239
13.8M
    }
240
241
9.62M
    if (!fs_attr_ok) {
242
12.6k
        tsk_error_set_errno(TSK_ERR_FS_ATTR_NOTFOUND);
243
12.6k
        tsk_error_set_errstr("tsk_fs_attrlist_get: Attribute %d not found",
244
12.6k
            a_type);
245
12.6k
        return NULL;
246
12.6k
    }
247
9.61M
    else {
248
9.61M
        return fs_attr_ok;
249
9.61M
    }
250
9.62M
}
251
252
/**
253
 * \internal
254
 * Search the attribute list of TSK_FS_ATTR structures for an entry with a given
255
 * type and id.
256
 *
257
 * @param a_fs_attrlist Data list structure to search in
258
 * @param a_type Type of attribute to find
259
 * @param a_id Id of attribute to find.
260
 *
261
 * @return NULL is returned on error and if an entry could not be found.
262
 * tsk_errno will be set to TSK_ERR_FS_ATTR_NOTFOUND if entry could not be found.
263
 */
264
const TSK_FS_ATTR *
265
tsk_fs_attrlist_get_id(const TSK_FS_ATTRLIST * a_fs_attrlist,
266
    TSK_FS_ATTR_TYPE_ENUM a_type, uint16_t a_id)
267
606k
{
268
606k
    TSK_FS_ATTR *fs_attr_cur;
269
270
606k
    if (!a_fs_attrlist) {
271
0
        tsk_error_reset();
272
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
273
0
        tsk_error_set_errstr("tsk_fs_attrlist_get_id: Null list pointer");
274
0
        return NULL;
275
0
    }
276
277
2.38M
    for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur;
278
1.81M
        fs_attr_cur = fs_attr_cur->next) {
279
1.81M
        if ((fs_attr_cur->flags & TSK_FS_ATTR_INUSE)
280
1.75M
            && (fs_attr_cur->type == a_type) && (fs_attr_cur->id == a_id))
281
35.2k
            return fs_attr_cur;
282
1.81M
    }
283
284
571k
    tsk_error_set_errno(TSK_ERR_FS_ATTR_NOTFOUND);
285
571k
    tsk_error_set_errstr
286
571k
        ("tsk_fs_attrlist_get_id: Attribute %d-%d not found", a_type,
287
571k
        a_id);
288
571k
    return NULL;
289
606k
}
290
291
292
/**
293
 * \internal
294
 * Search the attribute list of TSK_FS_ATTR structures for an entry with a
295
 given
296
 * type (no ID) and a given name. If more than one entry with the same
297
 type exists,
298
 * the one with the lowest ID will be returned.
299
 *
300
 * @param a_fs_attrlist Data list structure to search in
301
 * @param a_type Type of attribute to find
302
 * @param name Name of the attribute to find (NULL for an entry with no name)
303
 *
304
 * @return NULL is returned on error and if an entry could not be found.
305
 * tsk_errno will be set to TSK_ERR_FS_ATTR_NOTFOUND if entry could not be
306
 found.
307
 */
308
const TSK_FS_ATTR *
309
tsk_fs_attrlist_get_name_type(const TSK_FS_ATTRLIST * a_fs_attrlist,
310
    TSK_FS_ATTR_TYPE_ENUM a_type, const char *name)
311
179
{
312
179
    TSK_FS_ATTR *fs_attr_cur;
313
179
    TSK_FS_ATTR *fs_attr_ok = NULL;
314
315
179
    if (!a_fs_attrlist) {
316
6
        tsk_error_reset();
317
6
        tsk_error_set_errno(TSK_ERR_FS_ARG);
318
6
        tsk_error_set_errstr
319
6
            ("tsk_fs_attrlist_get_name_type: Null list pointer");
320
6
        return NULL;
321
6
    }
322
323
764
    for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur; fs_attr_cur =
324
591
        fs_attr_cur->next) {
325
591
        if ((fs_attr_cur->flags & TSK_FS_ATTR_INUSE) &&
326
591
            (fs_attr_cur->type == a_type)) {
327
328
45
            if (((name == NULL) && (fs_attr_cur->name == NULL)) ||
329
45
                ((name) && (fs_attr_cur->name)
330
32
                    && (!strcmp(fs_attr_cur->name, name)))) {
331
332
                /* If we are looking for NTFS $Data,
333
                 * then return default when we see it */
334
4
                if ((fs_attr_cur->type == TSK_FS_ATTR_TYPE_NTFS_DATA) &&
335
0
                    (fs_attr_cur->name == NULL)) {
336
0
                    return fs_attr_cur;
337
0
                }
338
339
                // make sure we return the lowest if multiple exist
340
4
                if ((fs_attr_ok == NULL)
341
0
                    || (fs_attr_ok->id > fs_attr_cur->id))
342
4
                    fs_attr_ok = fs_attr_cur;
343
4
            }
344
345
41
            else if ((name) && (fs_attr_cur->name) && fs_attr_cur->type == TSK_FS_ATTR_TYPE_NTFS_DATA && !strcasecmp(fs_attr_cur->name, name)) {
346
                // NTFS data streams should do case insensitive compare
347
                // make sure we return the lowest if multiple exist
348
0
                if ((fs_attr_ok == NULL) || (fs_attr_ok->id > fs_attr_cur->id))
349
0
                    fs_attr_ok = fs_attr_cur;
350
0
            }
351
45
        }
352
591
    }
353
354
173
    if (!fs_attr_ok) {
355
169
        tsk_error_set_errno(TSK_ERR_FS_ATTR_NOTFOUND);
356
169
        tsk_error_set_errstr("tsk_fs_attrlist_get: Attribute %d not found",
357
169
            a_type);
358
169
        return NULL;
359
169
    }
360
4
    else {
361
4
        return fs_attr_ok;
362
4
    }
363
173
}
364
365
366
/**
367
 * \internal
368
 * Return the a_idx'th attribute in the attribute list.
369
 *
370
 * @param a_fs_attrlist Data list structure to search in
371
 * @param a_idx 0-based index of attribute to return
372
 *
373
 * @return NULL is returned on error and if an entry could not be found.
374
 * tsk_errno will be set to TSK_ERR_FS_ATTR_NOTFOUND if entry could not be found.
375
 */
376
const TSK_FS_ATTR *
377
tsk_fs_attrlist_get_idx(const TSK_FS_ATTRLIST * a_fs_attrlist, int a_idx)
378
94.3k
{
379
94.3k
    TSK_FS_ATTR *fs_attr_cur;
380
94.3k
    int i = 0;
381
382
94.3k
    if (!a_fs_attrlist) {
383
0
        tsk_error_reset();
384
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
385
0
        tsk_error_set_errstr("tsk_fs_attrlist_get_idx: Null list pointer");
386
0
        return NULL;
387
0
    }
388
389
185k
    for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur;
390
185k
        fs_attr_cur = fs_attr_cur->next) {
391
185k
        if (fs_attr_cur->flags & TSK_FS_ATTR_INUSE) {
392
185k
            if (i == a_idx) {
393
94.3k
                return fs_attr_cur;
394
94.3k
            }
395
91.2k
            i++;
396
91.2k
        }
397
185k
    }
398
399
0
    tsk_error_set_errno(TSK_ERR_FS_ATTR_NOTFOUND);
400
0
    tsk_error_set_errstr
401
0
        ("tsk_fs_attrlist_get_idx: Attribute index %d not found", a_idx);
402
0
    return NULL;
403
94.3k
}
404
405
406
/**
407
 * \internal
408
 * Return the number of attributes in the attribute list
409
 *
410
 * @param a_fs_attrlist Data list structure to analyze
411
 *
412
 * @return the number of attributes and 0 if error (if argument is NULL)
413
 */
414
int
415
tsk_fs_attrlist_get_len(const TSK_FS_ATTRLIST * a_fs_attrlist)
416
36.9k
{
417
36.9k
    TSK_FS_ATTR *fs_attr_cur;
418
36.9k
    int len = 0;
419
420
36.9k
    if (!a_fs_attrlist) {
421
0
        tsk_error_reset();
422
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
423
0
        tsk_error_set_errstr("tsk_fs_attrlist_get_len: Null list pointer");
424
0
        return 0;
425
0
    }
426
427
139k
    for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur;
428
102k
        fs_attr_cur = fs_attr_cur->next) {
429
102k
        if (fs_attr_cur->flags & TSK_FS_ATTR_INUSE)
430
98.5k
            len++;
431
102k
    }
432
36.9k
    return len;
433
36.9k
}