/src/sleuthkit/tsk/fs/ifind_lib.cpp
Line | Count | Source |
1 | | /* |
2 | | ** ifind (inode find) |
3 | | ** The Sleuth Kit |
4 | | ** |
5 | | ** Given an image and block number, identify which inode it is used by |
6 | | ** |
7 | | ** Brian Carrier [carrier <at> sleuthkit [dot] org] |
8 | | ** Copyright (c) 2006-2011 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 | | ** TCTUTILs |
15 | | ** Copyright (c) 2001 Brian Carrier. All rights reserved |
16 | | ** |
17 | | ** |
18 | | ** This software is distributed under the Common Public License 1.0 |
19 | | ** |
20 | | */ |
21 | | |
22 | | /** |
23 | | * \file ifind_lib.c |
24 | | * Contains the library API functions used by the TSK ifind command |
25 | | * line tool. |
26 | | */ |
27 | | |
28 | | #include "tsk_fs_i.h" |
29 | | #include "tsk_hfs.h" |
30 | | |
31 | | #include <memory> |
32 | | |
33 | | |
34 | | /******************************************************************************* |
35 | | * Find an unallocated NTFS MFT entry based on its parent directory |
36 | | */ |
37 | | |
38 | | typedef struct { |
39 | | TSK_INUM_T parinode; |
40 | | TSK_FS_IFIND_FLAG_ENUM flags; |
41 | | uint8_t found; |
42 | | } IFIND_PAR_DATA; |
43 | | |
44 | | |
45 | | /* inode walk call back for tsk_fs_ifind_par to find unallocated files |
46 | | * based on parent directory |
47 | | */ |
48 | | static TSK_WALK_RET_ENUM |
49 | | ifind_par_act(TSK_FS_FILE * fs_file, void *ptr) |
50 | 0 | { |
51 | 0 | IFIND_PAR_DATA *data = (IFIND_PAR_DATA *) ptr; |
52 | 0 | TSK_FS_META_NAME_LIST *fs_name_list; |
53 | | |
54 | | /* go through each file name attribute for this file */ |
55 | 0 | fs_name_list = fs_file->meta->name2; |
56 | 0 | while (fs_name_list) { |
57 | | |
58 | | /* we found a file that has the target parent directory. |
59 | | * Make a FS_NAME structure and print it. */ |
60 | 0 | if (fs_name_list->par_inode == data->parinode) { |
61 | 0 | int i, cnt; |
62 | 0 | uint8_t printed; |
63 | 0 | TSK_FS_NAME *fs_name; |
64 | |
|
65 | 0 | if ((fs_name = tsk_fs_name_alloc(256, 0)) == NULL) |
66 | 0 | return TSK_WALK_ERROR; |
67 | | |
68 | | /* Fill in the basics of the fs_name entry |
69 | | * so we can print in the fls formats */ |
70 | 0 | fs_name->meta_addr = fs_file->meta->addr; |
71 | 0 | fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; |
72 | 0 | strncpy(fs_name->name, fs_name_list->name, fs_name->name_size); |
73 | | |
74 | | // now look for the $Data and $IDXROOT attributes |
75 | 0 | fs_file->name = fs_name; |
76 | 0 | printed = 0; |
77 | | |
78 | | // cycle through the attributes |
79 | 0 | cnt = tsk_fs_file_attr_getsize(fs_file); |
80 | 0 | for (i = 0; i < cnt; i++) { |
81 | 0 | const TSK_FS_ATTR *fs_attr = |
82 | 0 | tsk_fs_file_attr_get_idx(fs_file, i); |
83 | 0 | if (!fs_attr) |
84 | 0 | continue; |
85 | | |
86 | 0 | if ((fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_DATA) |
87 | 0 | || (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_IDXROOT)) { |
88 | |
|
89 | 0 | if (data->flags & TSK_FS_IFIND_PAR_LONG) { |
90 | 0 | tsk_fs_name_print_long(stdout, fs_file, NULL, |
91 | 0 | fs_file->fs_info, fs_attr, 0, 0); |
92 | 0 | tsk_printf("\n"); |
93 | 0 | } |
94 | 0 | else { |
95 | 0 | tsk_fs_name_print(stdout, fs_file, NULL, |
96 | 0 | fs_file->fs_info, fs_attr, 0); |
97 | 0 | tsk_printf("\n"); |
98 | 0 | } |
99 | 0 | printed = 1; |
100 | 0 | } |
101 | 0 | } |
102 | | |
103 | | // if there were no attributes, print what we got |
104 | 0 | if (printed == 0) { |
105 | 0 | if (data->flags & TSK_FS_IFIND_PAR_LONG) { |
106 | 0 | tsk_fs_name_print_long(stdout, fs_file, NULL, |
107 | 0 | fs_file->fs_info, NULL, 0, 0); |
108 | 0 | tsk_printf("\n"); |
109 | 0 | } |
110 | 0 | else { |
111 | 0 | tsk_fs_name_print(stdout, fs_file, NULL, |
112 | 0 | fs_file->fs_info, NULL, 0); |
113 | 0 | tsk_printf("\n"); |
114 | 0 | } |
115 | 0 | } |
116 | 0 | tsk_fs_name_free(fs_name); |
117 | 0 | data->found = 1; |
118 | 0 | } |
119 | 0 | fs_name_list = fs_name_list->next; |
120 | 0 | } |
121 | | |
122 | 0 | return TSK_WALK_CONT; |
123 | 0 | } |
124 | | |
125 | | |
126 | | |
127 | | /** |
128 | | * Searches for unallocated MFT entries that have a given |
129 | | * MFT entry as their parent directory (as reported in FILE_NAME). |
130 | | * @param fs File system to search |
131 | | * @param lclflags Flags |
132 | | * @param par Parent directory MFT entry address |
133 | | * @returns 1 on error and 0 on success |
134 | | */ |
135 | | uint8_t |
136 | | tsk_fs_ifind_par(TSK_FS_INFO * fs, TSK_FS_IFIND_FLAG_ENUM lclflags, |
137 | | TSK_INUM_T par) |
138 | 0 | { |
139 | 0 | IFIND_PAR_DATA data; |
140 | |
|
141 | 0 | data.found = 0; |
142 | 0 | data.flags = lclflags; |
143 | 0 | data.parinode = par; |
144 | | |
145 | | /* Walk unallocated MFT entries */ |
146 | 0 | if (fs->inode_walk(fs, fs->first_inum, fs->last_inum, |
147 | 0 | TSK_FS_META_FLAG_UNALLOC, ifind_par_act, &data)) { |
148 | 0 | return 1; |
149 | 0 | } |
150 | | |
151 | 0 | return 0; |
152 | 0 | } |
153 | | |
154 | | |
155 | | |
156 | | |
157 | | /** |
158 | | * \ingroup fslib |
159 | | * |
160 | | * Find the meta data address for a given file name (UTF-8). |
161 | | * The basic idea of the function is to break the given name into its |
162 | | * subdirectories and start looking for each (starting in the root |
163 | | * directory). |
164 | | * |
165 | | * @param a_fs FS to analyze |
166 | | * @param a_path UTF-8 path of file to search for |
167 | | * @param [out] a_result Meta data address of file |
168 | | * @param [out] a_fs_name Copy of name details (or NULL if details not wanted) |
169 | | * @returns -1 on (system) error, 0 if found, and 1 if not found |
170 | | */ |
171 | | int8_t |
172 | | tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path, |
173 | | TSK_INUM_T * a_result, TSK_FS_NAME * a_fs_name) |
174 | 1.60k | { |
175 | 1.60k | char *cpath; |
176 | 1.60k | size_t clen; |
177 | 1.60k | char *cur_dir; // The "current" directory or file we are looking for |
178 | 1.60k | char *cur_attr; // The "current" attribute of the dir we are looking for |
179 | 1.60k | TSK_INUM_T next_meta; |
180 | 1.60k | uint8_t is_done; |
181 | 1.60k | *a_result = 0; |
182 | | |
183 | | // copy path to a buffer that we can modify |
184 | 1.60k | clen = strlen(a_path) + 1; |
185 | 1.60k | if ((cpath = (char *) tsk_malloc(clen)) == NULL) { |
186 | 0 | return -1; |
187 | 0 | } |
188 | 1.60k | strncpy(cpath, a_path, clen); |
189 | | |
190 | | // Get the first part of the directory path. |
191 | 1.60k | UNUSED char *strtok_last; // not actually unused; some compilers complain |
192 | 1.60k | cur_dir = (char *) strtok_r(cpath, "/", &strtok_last); |
193 | 1.60k | cur_attr = NULL; |
194 | | |
195 | | /* If there is no token, then only a '/' was given */ |
196 | 1.60k | if (cur_dir == NULL) { |
197 | 0 | free(cpath); |
198 | 0 | *a_result = a_fs->root_inum; |
199 | | |
200 | | // create the dummy entry if needed |
201 | 0 | if (a_fs_name) { |
202 | 0 | a_fs_name->meta_addr = a_fs->root_inum; |
203 | | // Note that we are not filling in meta_seq -- we could, we just aren't |
204 | |
|
205 | 0 | a_fs_name->type = TSK_FS_NAME_TYPE_DIR; |
206 | 0 | a_fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; |
207 | 0 | if (a_fs_name->name) |
208 | 0 | a_fs_name->name[0] = '\0'; |
209 | 0 | if (a_fs_name->shrt_name) |
210 | 0 | a_fs_name->shrt_name[0] = '\0'; |
211 | 0 | } |
212 | 0 | return 0; |
213 | 0 | } |
214 | | |
215 | | /* If this is NTFS, separate out the attribute of the current directory */ |
216 | 1.60k | if (TSK_FS_TYPE_ISNTFS(a_fs->ftype) |
217 | 0 | && ((cur_attr = strchr(cur_dir, ':')) != NULL)) { |
218 | 0 | *(cur_attr) = '\0'; |
219 | 0 | cur_attr++; |
220 | 0 | } |
221 | | |
222 | 1.60k | if (tsk_verbose) |
223 | 0 | tsk_fprintf(stderr, "Looking for %s\n", cur_dir); |
224 | | |
225 | | // initialize the first place to look, the root dir |
226 | 1.60k | next_meta = a_fs->root_inum; |
227 | | |
228 | | // we loop until we know the outcome and then exit. |
229 | | // everything should return from inside the loop. |
230 | 1.60k | is_done = 0; |
231 | 2.21k | while (is_done == 0) { |
232 | 1.60k | size_t i; |
233 | | |
234 | | // open the next directory in the recursion |
235 | 1.60k | std::unique_ptr<TSK_FS_DIR, decltype(&tsk_fs_dir_close)> fs_dir{ |
236 | 1.60k | tsk_fs_dir_open_meta(a_fs, next_meta), |
237 | 1.60k | tsk_fs_dir_close |
238 | 1.60k | }; |
239 | | |
240 | 1.60k | if (!fs_dir) { |
241 | 668 | free(cpath); |
242 | 668 | return -1; |
243 | 668 | } |
244 | | |
245 | | /* Verify this is indeed a directory. We had one reported |
246 | | * problem where a file was a disk image and opening it as |
247 | | * a directory found the directory entries inside of the file |
248 | | * and this caused problems... */ |
249 | 940 | if (!TSK_FS_IS_DIR_META(fs_dir->fs_file->meta->type)) { |
250 | 110 | tsk_error_reset(); |
251 | 110 | tsk_error_set_errno(TSK_ERR_FS_GENFS); |
252 | 110 | tsk_error_set_errstr("Address %" PRIuINUM |
253 | 110 | " is not for a directory\n", next_meta); |
254 | 110 | free(cpath); |
255 | 110 | return -1; |
256 | 110 | } |
257 | | |
258 | 830 | std::unique_ptr<TSK_FS_FILE, decltype(&tsk_fs_file_close)> fs_file_alloc{ |
259 | 830 | nullptr, // set to the allocated file that is our target |
260 | 830 | tsk_fs_file_close |
261 | 830 | }; |
262 | | |
263 | 830 | std::unique_ptr<TSK_FS_FILE, decltype(&tsk_fs_file_close)> fs_file_del{ |
264 | 830 | nullptr, // set to an unallocated file that matches our criteria |
265 | 830 | tsk_fs_file_close |
266 | 830 | }; |
267 | | |
268 | | // cycle through each entry |
269 | 9.94k | for (i = 0; i < tsk_fs_dir_getsize(fs_dir.get()); i++) { |
270 | | |
271 | 9.33k | uint8_t found_name = 0; |
272 | | |
273 | 9.33k | std::unique_ptr<TSK_FS_FILE, decltype(&tsk_fs_file_close)> fs_file{ |
274 | 9.33k | tsk_fs_dir_get(fs_dir.get(), i), |
275 | 9.33k | tsk_fs_file_close |
276 | 9.33k | }; |
277 | | |
278 | 9.33k | if (!fs_file) { |
279 | 0 | free(cpath); |
280 | 0 | return -1; |
281 | 0 | } |
282 | | |
283 | | /* |
284 | | * Check if this is the name that we are currently looking for, |
285 | | * as identified in 'cur_dir' |
286 | | */ |
287 | 9.33k | if ((fs_file->name->name) |
288 | 9.33k | && (a_fs->name_cmp(a_fs, fs_file->name->name, |
289 | 9.33k | cur_dir) == 0)) { |
290 | 220 | found_name = 1; |
291 | 220 | } |
292 | 9.11k | else if ((fs_file->name->shrt_name) |
293 | 0 | && (a_fs->name_cmp(a_fs, fs_file->name->shrt_name, |
294 | 0 | cur_dir) == 0)) { |
295 | 0 | found_name = 1; |
296 | 0 | } |
297 | | |
298 | | /* For NTFS, we have to check the attribute name. */ |
299 | 9.33k | if ((found_name == 1) && (TSK_FS_TYPE_ISNTFS(a_fs->ftype))) { |
300 | | /* ensure we have the right attribute name */ |
301 | 0 | if (cur_attr != NULL) { |
302 | 0 | found_name = 0; |
303 | 0 | if (fs_file->meta) { |
304 | 0 | int cnt, i; |
305 | | |
306 | | // cycle through the attributes |
307 | 0 | cnt = tsk_fs_file_attr_getsize(fs_file.get()); |
308 | 0 | for (i = 0; i < cnt; i++) { |
309 | 0 | const TSK_FS_ATTR *fs_attr = |
310 | 0 | tsk_fs_file_attr_get_idx(fs_file.get(), i); |
311 | 0 | if (!fs_attr) |
312 | 0 | continue; |
313 | | |
314 | 0 | if ((fs_attr->name) |
315 | 0 | && (a_fs->name_cmp(a_fs, fs_attr->name, |
316 | 0 | cur_attr) == 0)) { |
317 | 0 | found_name = 1; |
318 | 0 | break; |
319 | 0 | } |
320 | 0 | } |
321 | 0 | } |
322 | 0 | } |
323 | 0 | } |
324 | | |
325 | 9.33k | if (found_name) { |
326 | | /* If we found our file and it is allocated, then stop. If |
327 | | * it is unallocated, keep on going to see if we can get |
328 | | * an allocated hit */ |
329 | 220 | if (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC) { |
330 | 220 | fs_file_alloc = std::move(fs_file); |
331 | 220 | break; |
332 | 220 | } |
333 | 0 | else { |
334 | | // if we already have an unalloc and its addr is 0, then use the new one |
335 | 0 | if (fs_file_del |
336 | 0 | && fs_file_del->name->meta_addr == 0) { |
337 | 0 | fs_file_del.reset(); |
338 | 0 | } |
339 | 0 | fs_file_del = std::move(fs_file); |
340 | 0 | } |
341 | 220 | } |
342 | 9.33k | } |
343 | | |
344 | | // we found a directory, go into it |
345 | 830 | if (fs_file_alloc || fs_file_del) { |
346 | | |
347 | 220 | const char *pname; |
348 | 220 | TSK_FS_FILE *fs_file_tmp; |
349 | | |
350 | | // choose the alloc one first (if they both exist) |
351 | 220 | if (fs_file_alloc) |
352 | 220 | fs_file_tmp = fs_file_alloc.get(); |
353 | 0 | else |
354 | 0 | fs_file_tmp = fs_file_del.get(); |
355 | | |
356 | 220 | pname = cur_dir; // save a copy of the current name pointer |
357 | | |
358 | | // advance to the next name |
359 | 220 | cur_dir = (char *) strtok_r(NULL, "/", &strtok_last); |
360 | 220 | cur_attr = NULL; |
361 | | |
362 | 220 | if (tsk_verbose) |
363 | 0 | tsk_fprintf(stderr, |
364 | 0 | "Found it (%s), now looking for %s\n", pname, cur_dir); |
365 | | |
366 | | /* That was the last name in the path -- we found the file! */ |
367 | 220 | if (cur_dir == NULL) { |
368 | 220 | *a_result = fs_file_tmp->name->meta_addr; |
369 | | |
370 | | // make a copy if one was requested |
371 | 220 | if (a_fs_name) { |
372 | 0 | tsk_fs_name_copy(a_fs_name, fs_file_tmp->name); |
373 | 0 | } |
374 | | |
375 | 220 | free(cpath); |
376 | 220 | return 0; |
377 | 220 | } |
378 | | |
379 | | // update the attribute field, if needed |
380 | 0 | if (TSK_FS_TYPE_ISNTFS(a_fs->ftype) |
381 | 0 | && ((cur_attr = strchr(cur_dir, ':')) != NULL)) { |
382 | 0 | *(cur_attr) = '\0'; |
383 | 0 | cur_attr++; |
384 | 0 | } |
385 | | |
386 | | // update the value for the next directory to open |
387 | 0 | next_meta = fs_file_tmp->name->meta_addr; |
388 | 0 | } |
389 | | |
390 | | // no hit in directory |
391 | 610 | else { |
392 | 610 | is_done = 1; |
393 | 610 | } |
394 | 830 | } |
395 | | |
396 | 610 | free(cpath); |
397 | 610 | return 1; |
398 | 1.60k | } |
399 | | |
400 | | |
401 | | /** |
402 | | * Find the meta data address for a given file TCHAR name |
403 | | * |
404 | | * @param fs FS to analyze |
405 | | * @param tpath Path of file to search for |
406 | | * @param [out] result Meta data address of file |
407 | | * @returns -1 on error, 0 if found, and 1 if not found |
408 | | */ |
409 | | int8_t |
410 | | tsk_fs_ifind_path(TSK_FS_INFO * fs, TSK_TCHAR * tpath, TSK_INUM_T * result) |
411 | 0 | { |
412 | |
|
413 | | #ifdef TSK_WIN32 |
414 | | // Convert the UTF-16 path to UTF-8 |
415 | | { |
416 | | size_t clen; |
417 | | UTF8 *ptr8; |
418 | | UTF16 *ptr16; |
419 | | int retval; |
420 | | char *cpath; |
421 | | |
422 | | clen = TSTRLEN(tpath) * 4; |
423 | | if ((cpath = (char *) tsk_malloc(clen)) == NULL) { |
424 | | return -1; |
425 | | } |
426 | | ptr8 = (UTF8 *) cpath; |
427 | | ptr16 = (UTF16 *) tpath; |
428 | | |
429 | | retval = |
430 | | tsk_UTF16toUTF8_lclorder((const UTF16 **) &ptr16, (UTF16 *) |
431 | | & ptr16[TSTRLEN(tpath) + 1], &ptr8, |
432 | | (UTF8 *) ((uintptr_t) ptr8 + clen), TSKlenientConversion); |
433 | | if (retval != TSKconversionOK) { |
434 | | tsk_error_reset(); |
435 | | tsk_error_set_errno(TSK_ERR_FS_UNICODE); |
436 | | tsk_error_set_errstr |
437 | | ("tsk_fs_ifind_path: Error converting path to UTF-8: %d", |
438 | | retval); |
439 | | free(cpath); |
440 | | return -1; |
441 | | } |
442 | | return tsk_fs_path2inum(fs, cpath, result, NULL); |
443 | | } |
444 | | #else |
445 | 0 | return tsk_fs_path2inum(fs, (const char *) tpath, result, NULL); |
446 | 0 | #endif |
447 | 0 | } |
448 | | |
449 | | |
450 | | |
451 | | |
452 | | |
453 | | |
454 | | /******************************************************************************* |
455 | | * Find an inode given a data unit |
456 | | */ |
457 | | |
458 | | typedef struct { |
459 | | TSK_DADDR_T block; /* the block to find */ |
460 | | TSK_FS_IFIND_FLAG_ENUM flags; |
461 | | uint8_t found; |
462 | | |
463 | | TSK_INUM_T curinode; /* the inode being analyzed */ |
464 | | uint32_t curtype; /* the type currently being analyzed: NTFS */ |
465 | | uint16_t curid; |
466 | | } IFIND_DATA_DATA; |
467 | | |
468 | | |
469 | | /* |
470 | | * file_walk action for non-ntfs |
471 | | */ |
472 | | static TSK_WALK_RET_ENUM |
473 | | ifind_data_file_act( |
474 | | TSK_FS_FILE * fs_file, |
475 | | [[maybe_unused]] TSK_OFF_T a_off, |
476 | | TSK_DADDR_T addr, |
477 | | [[maybe_unused]] char *buf, |
478 | | [[maybe_unused]] size_t size, |
479 | | TSK_FS_BLOCK_FLAG_ENUM flags, |
480 | | void *ptr) |
481 | 0 | { |
482 | 0 | TSK_FS_INFO *fs = fs_file->fs_info; |
483 | 0 | IFIND_DATA_DATA *data = (IFIND_DATA_DATA *) ptr; |
484 | | |
485 | | /* Ignore sparse blocks because they do not reside on disk */ |
486 | 0 | if (flags & TSK_FS_BLOCK_FLAG_SPARSE) |
487 | 0 | return TSK_WALK_CONT; |
488 | | |
489 | 0 | if (addr == data->block) { |
490 | 0 | if (TSK_FS_TYPE_ISNTFS(fs->ftype)) |
491 | 0 | tsk_printf("%" PRIuINUM "-%" PRIu32 "-%" PRIu16 "\n", |
492 | 0 | data->curinode, data->curtype, data->curid); |
493 | 0 | else |
494 | 0 | tsk_printf("%" PRIuINUM "\n", data->curinode); |
495 | 0 | data->found = 1; |
496 | 0 | return TSK_WALK_STOP; |
497 | 0 | } |
498 | 0 | return TSK_WALK_CONT; |
499 | 0 | } |
500 | | |
501 | | |
502 | | /* |
503 | | ** find_inode |
504 | | ** |
505 | | ** Callback action for inode_walk |
506 | | */ |
507 | | static TSK_WALK_RET_ENUM |
508 | | ifind_data_act(TSK_FS_FILE * fs_file, void *ptr) |
509 | 0 | { |
510 | 0 | IFIND_DATA_DATA *data = (IFIND_DATA_DATA *) ptr; |
511 | 0 | int file_flags = |
512 | 0 | (TSK_FS_FILE_WALK_FLAG_AONLY | TSK_FS_FILE_WALK_FLAG_SLACK); |
513 | 0 | int i, cnt; |
514 | |
|
515 | 0 | data->curinode = fs_file->meta->addr; |
516 | | |
517 | | /* Search all attributes */ |
518 | 0 | cnt = tsk_fs_file_attr_getsize(fs_file); |
519 | 0 | for (i = 0; i < cnt; i++) { |
520 | 0 | const TSK_FS_ATTR *fs_attr = tsk_fs_file_attr_get_idx(fs_file, i); |
521 | 0 | if (!fs_attr) |
522 | 0 | continue; |
523 | | |
524 | 0 | data->curtype = fs_attr->type; |
525 | 0 | data->curid = fs_attr->id; |
526 | 0 | if (fs_attr->flags & TSK_FS_ATTR_NONRES) { |
527 | 0 | if (tsk_fs_attr_walk(fs_attr, |
528 | 0 | (TSK_FS_FILE_WALK_FLAG_ENUM) file_flags, ifind_data_file_act, ptr)) { |
529 | 0 | if (tsk_verbose) |
530 | 0 | tsk_fprintf(stderr, |
531 | 0 | "Error walking file %" PRIuINUM |
532 | 0 | " Attribute: %i", fs_file->meta->addr, i); |
533 | | |
534 | | /* Ignore these errors */ |
535 | 0 | tsk_error_reset(); |
536 | 0 | } |
537 | | |
538 | | // stop if we only want one hit |
539 | 0 | if ((data->found) && (!(data->flags & TSK_FS_IFIND_ALL))) |
540 | 0 | break; |
541 | 0 | } |
542 | 0 | } |
543 | |
|
544 | 0 | if ((data->found) && (!(data->flags & TSK_FS_IFIND_ALL))) |
545 | 0 | return TSK_WALK_STOP; |
546 | 0 | else |
547 | 0 | return TSK_WALK_CONT; |
548 | 0 | } |
549 | | |
550 | | |
551 | | |
552 | | |
553 | | /* |
554 | | * Find the inode that has allocated block blk |
555 | | * Return 1 on error, 0 if no error */ |
556 | | uint8_t |
557 | | tsk_fs_ifind_data(TSK_FS_INFO * fs, TSK_FS_IFIND_FLAG_ENUM lclflags, |
558 | | TSK_DADDR_T blk) |
559 | 0 | { |
560 | 0 | IFIND_DATA_DATA data; |
561 | |
|
562 | 0 | memset(&data, 0, sizeof(IFIND_DATA_DATA)); |
563 | 0 | data.flags = lclflags; |
564 | 0 | data.block = blk; |
565 | |
|
566 | 0 | if (fs->inode_walk(fs, fs->first_inum, fs->last_inum, |
567 | 0 | (TSK_FS_META_FLAG_ENUM) (TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_UNALLOC), |
568 | 0 | ifind_data_act, &data)) { |
569 | 0 | return 1; |
570 | 0 | } |
571 | | |
572 | | /* If we did not find an inode yet, get the block's |
573 | | * flags so we can identify it as a meta data block */ |
574 | 0 | if (!data.found) { |
575 | 0 | TSK_FS_BLOCK *fs_block; |
576 | |
|
577 | 0 | if ((fs_block = tsk_fs_block_get(fs, NULL, blk)) != NULL) { |
578 | 0 | if (fs_block->flags & TSK_FS_BLOCK_FLAG_META) { |
579 | 0 | tsk_printf("Meta Data\n"); |
580 | 0 | data.found = 1; |
581 | 0 | } |
582 | 0 | tsk_fs_block_free(fs_block); |
583 | 0 | } |
584 | 0 | } |
585 | |
|
586 | 0 | if (!data.found) { |
587 | 0 | tsk_printf("Inode not found\n"); |
588 | 0 | } |
589 | 0 | return 0; |
590 | 0 | } |