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 *
tsk_fs_attrlist_alloc()25 tsk_fs_attrlist_alloc()
26 {
27     TSK_FS_ATTRLIST *fs_attrlist;
28 
29     if ((fs_attrlist =
30             (TSK_FS_ATTRLIST *) tsk_malloc(sizeof(TSK_FS_ATTRLIST))) ==
31         NULL)
32         return NULL;
33     return fs_attrlist;
34 }
35 
36 /** \internal
37  * Free a list and the attributes inside of it
38  */
39 void
tsk_fs_attrlist_free(TSK_FS_ATTRLIST * a_fs_attrlist)40 tsk_fs_attrlist_free(TSK_FS_ATTRLIST * a_fs_attrlist)
41 {
42     TSK_FS_ATTR *fs_attr_cur, *fs_attr_tmp;
43     if (a_fs_attrlist == NULL)
44         return;
45 
46     fs_attr_cur = a_fs_attrlist->head;
47     while (fs_attr_cur) {
48         fs_attr_tmp = fs_attr_cur->next;
49         tsk_fs_attr_free(fs_attr_cur);
50         fs_attr_cur = fs_attr_tmp;
51     }
52     free(a_fs_attrlist);
53 }
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
tsk_fs_attrlist_add(TSK_FS_ATTRLIST * a_fs_attrlist,TSK_FS_ATTR * a_fs_attr)63 tsk_fs_attrlist_add(TSK_FS_ATTRLIST * a_fs_attrlist,
64     TSK_FS_ATTR * a_fs_attr)
65 {
66     if (a_fs_attrlist == NULL) {
67         tsk_error_reset();
68         tsk_error_set_errno(TSK_ERR_FS_ARG);
69         tsk_error_set_errstr("Null list in tsk_fs_attrlist_add");
70         return 1;
71     }
72 
73     // verify INUSE is set
74     a_fs_attr->flags |= TSK_FS_ATTR_INUSE;
75 
76     if (a_fs_attrlist->head == NULL) {
77         a_fs_attrlist->head = a_fs_attr;
78     }
79     else {
80         TSK_FS_ATTR *fs_attr_cur;
81         fs_attr_cur = a_fs_attrlist->head;
82         while (fs_attr_cur) {
83             // check if it already exists
84             if ((fs_attr_cur->type == a_fs_attr->type)
85                 && (fs_attr_cur->id == a_fs_attr->id)) {
86                 tsk_error_reset();
87                 tsk_error_set_errno(TSK_ERR_FS_ARG);
88                 tsk_error_set_errstr
89                     ("datalist_add: Type %d and Id %d already in list",
90                     a_fs_attr->type, a_fs_attr->id);
91                 return 1;
92             }
93             if (fs_attr_cur->next == NULL) {
94                 fs_attr_cur->next = a_fs_attr;
95                 break;
96             }
97             fs_attr_cur = fs_attr_cur->next;
98         }
99     }
100     return 0;
101 }
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 *
tsk_fs_attrlist_getnew(TSK_FS_ATTRLIST * a_fs_attrlist,TSK_FS_ATTR_FLAG_ENUM a_atype)118 tsk_fs_attrlist_getnew(TSK_FS_ATTRLIST * a_fs_attrlist,
119     TSK_FS_ATTR_FLAG_ENUM a_atype)
120 {
121     TSK_FS_ATTR *fs_attr_cur;
122     TSK_FS_ATTR *fs_attr_ok = NULL;
123 
124     if (a_fs_attrlist == NULL) {
125         tsk_error_reset();
126         tsk_error_set_errno(TSK_ERR_FS_ARG);
127         tsk_error_set_errstr("Null list in tsk_fs_attrlist_getnew()");
128         return NULL;
129     }
130 
131     if ((a_atype != TSK_FS_ATTR_NONRES) && (a_atype != TSK_FS_ATTR_RES)) {
132         tsk_error_reset();
133         tsk_error_set_errno(TSK_ERR_FS_ARG);
134         tsk_error_set_errstr("Invalid Type in tsk_fs_attrlist_getnew()");
135         return NULL;
136     }
137 
138     for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur;
139         fs_attr_cur = fs_attr_cur->next) {
140         if (fs_attr_cur->flags == 0) {
141             if (a_atype == TSK_FS_ATTR_NONRES) {
142                 if (fs_attr_cur->nrd.run)
143                     break;
144                 else if (!fs_attr_ok)
145                     fs_attr_ok = fs_attr_cur;
146             }
147             /* we want one with an allocated buf */
148             else {
149                 if (fs_attr_cur->rd.buf_size)
150                     break;
151                 else if (!fs_attr_ok)
152                     fs_attr_ok = fs_attr_cur;
153             }
154         }
155     }
156 
157     /* if we fell out then check fs_attr_tmp */
158     if (!fs_attr_cur) {
159         if (fs_attr_ok)
160             fs_attr_cur = fs_attr_ok;
161         else {
162             /* make a new one */
163             if ((fs_attr_cur = tsk_fs_attr_alloc(a_atype)) == NULL)
164                 return NULL;
165 
166             // add it to the list
167             if (tsk_fs_attrlist_add(a_fs_attrlist, fs_attr_cur)) {
168                 tsk_fs_attr_free(fs_attr_cur);
169                 return NULL;
170             }
171         }
172     }
173 
174     fs_attr_cur->flags = (TSK_FS_ATTR_INUSE | a_atype);
175     return fs_attr_cur;
176 }
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
tsk_fs_attrlist_markunused(TSK_FS_ATTRLIST * a_fs_attrlist)184 tsk_fs_attrlist_markunused(TSK_FS_ATTRLIST * a_fs_attrlist)
185 {
186     TSK_FS_ATTR *fs_attr_cur;
187     if (a_fs_attrlist == NULL)
188         return;
189 
190     fs_attr_cur = a_fs_attrlist->head;
191     while (fs_attr_cur) {
192         tsk_fs_attr_clear(fs_attr_cur);
193         fs_attr_cur = fs_attr_cur->next;
194     }
195 }
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 *
tsk_fs_attrlist_get(const TSK_FS_ATTRLIST * a_fs_attrlist,TSK_FS_ATTR_TYPE_ENUM a_type)210 tsk_fs_attrlist_get(const TSK_FS_ATTRLIST * a_fs_attrlist,
211     TSK_FS_ATTR_TYPE_ENUM a_type)
212 {
213     TSK_FS_ATTR *fs_attr_cur;
214     TSK_FS_ATTR *fs_attr_ok = NULL;
215 
216     if (!a_fs_attrlist) {
217         tsk_error_reset();
218         tsk_error_set_errno(TSK_ERR_FS_ARG);
219         tsk_error_set_errstr("tsk_fs_attrlist_get: Null list pointer");
220         return NULL;
221     }
222 
223     for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur;
224         fs_attr_cur = fs_attr_cur->next) {
225         if ((fs_attr_cur->flags & TSK_FS_ATTR_INUSE)
226             && (fs_attr_cur->type == a_type)) {
227 
228             /* If we are looking for NTFS $Data,
229              * then return default when we see it */
230             if ((fs_attr_cur->type == TSK_FS_ATTR_TYPE_NTFS_DATA) &&
231                 (fs_attr_cur->name == NULL)) {
232                 return fs_attr_cur;
233             }
234 
235             // make sure we return the lowest if multiple exist
236             if ((fs_attr_ok == NULL) || (fs_attr_ok->id > fs_attr_cur->id))
237                 fs_attr_ok = fs_attr_cur;
238         }
239     }
240 
241     if (!fs_attr_ok) {
242         tsk_error_set_errno(TSK_ERR_FS_ATTR_NOTFOUND);
243         tsk_error_set_errstr("tsk_fs_attrlist_get: Attribute %d not found",
244             a_type);
245         return NULL;
246     }
247     else {
248         return fs_attr_ok;
249     }
250 }
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 *
tsk_fs_attrlist_get_id(const TSK_FS_ATTRLIST * a_fs_attrlist,TSK_FS_ATTR_TYPE_ENUM a_type,uint16_t a_id)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 {
268     TSK_FS_ATTR *fs_attr_cur;
269 
270     if (!a_fs_attrlist) {
271         tsk_error_reset();
272         tsk_error_set_errno(TSK_ERR_FS_ARG);
273         tsk_error_set_errstr("tsk_fs_attrlist_get_id: Null list pointer");
274         return NULL;
275     }
276 
277     for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur;
278         fs_attr_cur = fs_attr_cur->next) {
279         if ((fs_attr_cur->flags & TSK_FS_ATTR_INUSE)
280             && (fs_attr_cur->type == a_type) && (fs_attr_cur->id == a_id))
281             return fs_attr_cur;
282     }
283 
284     tsk_error_set_errno(TSK_ERR_FS_ATTR_NOTFOUND);
285     tsk_error_set_errstr
286         ("tsk_fs_attrlist_get_id: Attribute %d-%d not found", a_type,
287         a_id);
288     return NULL;
289 }
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 *
tsk_fs_attrlist_get_name_type(const TSK_FS_ATTRLIST * a_fs_attrlist,TSK_FS_ATTR_TYPE_ENUM a_type,const char * name)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 {
312     TSK_FS_ATTR *fs_attr_cur;
313     TSK_FS_ATTR *fs_attr_ok = NULL;
314 
315     if (!a_fs_attrlist) {
316         tsk_error_reset();
317         tsk_error_set_errno(TSK_ERR_FS_ARG);
318         tsk_error_set_errstr
319             ("tsk_fs_attrlist_get_name_type: Null list pointer");
320         return NULL;
321     }
322 
323     for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur; fs_attr_cur =
324         fs_attr_cur->next) {
325         if ((fs_attr_cur->flags & TSK_FS_ATTR_INUSE) &&
326             (fs_attr_cur->type == a_type)) {
327 
328             if (((name == NULL) && (fs_attr_cur->name == NULL)) ||
329                 ((name) && (fs_attr_cur->name)
330                     && (!strcmp(fs_attr_cur->name, name)))) {
331 
332                 /* If we are looking for NTFS $Data,
333                  * then return default when we see it */
334                 if ((fs_attr_cur->type == TSK_FS_ATTR_TYPE_NTFS_DATA) &&
335                     (fs_attr_cur->name == NULL)) {
336                     return fs_attr_cur;
337                 }
338 
339                 // make sure we return the lowest if multiple exist
340                 if ((fs_attr_ok == NULL)
341                     || (fs_attr_ok->id > fs_attr_cur->id))
342                     fs_attr_ok = fs_attr_cur;
343             }
344         }
345     }
346 
347     if (!fs_attr_ok) {
348         tsk_error_set_errno(TSK_ERR_FS_ATTR_NOTFOUND);
349         tsk_error_set_errstr("tsk_fs_attrlist_get: Attribute %d not found",
350             a_type);
351         return NULL;
352     }
353     else {
354         return fs_attr_ok;
355     }
356 }
357 
358 
359 /**
360  * \internal
361  * Return the a_idx'th attribute in the attribute list.
362  *
363  * @param a_fs_attrlist Data list structure to search in
364  * @param a_idx 0-based index of attribute to return
365  *
366  * @return NULL is returned on error and if an entry could not be found.
367  * tsk_errno will be set to TSK_ERR_FS_ATTR_NOTFOUND if entry could not be found.
368  */
369 const TSK_FS_ATTR *
tsk_fs_attrlist_get_idx(const TSK_FS_ATTRLIST * a_fs_attrlist,int a_idx)370 tsk_fs_attrlist_get_idx(const TSK_FS_ATTRLIST * a_fs_attrlist, int a_idx)
371 {
372     TSK_FS_ATTR *fs_attr_cur;
373     int i = 0;
374 
375     if (!a_fs_attrlist) {
376         tsk_error_reset();
377         tsk_error_set_errno(TSK_ERR_FS_ARG);
378         tsk_error_set_errstr("tsk_fs_attrlist_get_idx: Null list pointer");
379         return NULL;
380     }
381 
382     for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur;
383         fs_attr_cur = fs_attr_cur->next) {
384         if (fs_attr_cur->flags & TSK_FS_ATTR_INUSE) {
385             if (i == a_idx) {
386                 return fs_attr_cur;
387             }
388             i++;
389         }
390     }
391 
392     tsk_error_set_errno(TSK_ERR_FS_ATTR_NOTFOUND);
393     tsk_error_set_errstr
394         ("tsk_fs_attrlist_get_idx: Attribute index %d not found", a_idx);
395     return NULL;
396 }
397 
398 
399 /**
400  * \internal
401  * Return the number of attributes in the attribute list
402  *
403  * @param a_fs_attrlist Data list structure to analyze
404  *
405  * @return the number of attributes and 0 if error (if argument is NULL)
406  */
407 int
tsk_fs_attrlist_get_len(const TSK_FS_ATTRLIST * a_fs_attrlist)408 tsk_fs_attrlist_get_len(const TSK_FS_ATTRLIST * a_fs_attrlist)
409 {
410     TSK_FS_ATTR *fs_attr_cur;
411     int len = 0;
412 
413     if (!a_fs_attrlist) {
414         tsk_error_reset();
415         tsk_error_set_errno(TSK_ERR_FS_ARG);
416         tsk_error_set_errstr("tsk_fs_attrlist_get_len: Null list pointer");
417         return 0;
418     }
419 
420     for (fs_attr_cur = a_fs_attrlist->head; fs_attr_cur;
421         fs_attr_cur = fs_attr_cur->next) {
422         if (fs_attr_cur->flags & TSK_FS_ATTR_INUSE)
423             len++;
424     }
425     return len;
426 }
427