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