/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  | 5.05k  | { | 
175  | 5.05k  |     char *cpath;  | 
176  | 5.05k  |     size_t clen;  | 
177  | 5.05k  |     char *cur_dir;              // The "current" directory or file we are looking for  | 
178  | 5.05k  |     char *cur_attr;             // The "current" attribute of the dir we are looking for  | 
179  | 5.05k  |     TSK_INUM_T next_meta;  | 
180  | 5.05k  |     uint8_t is_done;  | 
181  | 5.05k  |     *a_result = 0;  | 
182  |  |  | 
183  |  |     // copy path to a buffer that we can modify  | 
184  | 5.05k  |     clen = strlen(a_path) + 1;  | 
185  | 5.05k  |     if ((cpath = (char *) tsk_malloc(clen)) == NULL) { | 
186  | 0  |         return -1;  | 
187  | 0  |     }  | 
188  | 5.05k  |     strncpy(cpath, a_path, clen);  | 
189  |  |  | 
190  |  |     // Get the first part of the directory path.  | 
191  | 5.05k  |     UNUSED char *strtok_last; // not actually unused; some compilers complain  | 
192  | 5.05k  |     cur_dir = (char *) strtok_r(cpath, "/", &strtok_last);  | 
193  | 5.05k  |     cur_attr = NULL;  | 
194  |  |  | 
195  |  |     /* If there is no token, then only a '/' was given */  | 
196  | 5.05k  |     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  | 5.05k  |     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  | 5.05k  |     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  | 5.05k  |     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  | 5.05k  |     is_done = 0;  | 
231  | 6.08k  |     while (is_done == 0) { | 
232  | 5.05k  |         size_t i;  | 
233  |  |  | 
234  |  |         // open the next directory in the recursion  | 
235  | 5.05k  |         std::unique_ptr<TSK_FS_DIR, decltype(&tsk_fs_dir_close)> fs_dir{ | 
236  | 5.05k  |            tsk_fs_dir_open_meta(a_fs, next_meta),  | 
237  | 5.05k  |            tsk_fs_dir_close  | 
238  | 5.05k  |         };  | 
239  |  |  | 
240  | 5.05k  |         if (!fs_dir) { | 
241  | 3.24k  |             free(cpath);  | 
242  | 3.24k  |             return -1;  | 
243  | 3.24k  |         }  | 
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  | 1.81k  |         if (!TSK_FS_IS_DIR_META(fs_dir->fs_file->meta->type)) { | 
250  | 536  |             tsk_error_reset();  | 
251  | 536  |             tsk_error_set_errno(TSK_ERR_FS_GENFS);  | 
252  | 536  |             tsk_error_set_errstr("Address %" PRIuINUM | 
253  | 536  |                 " is not for a directory\n", next_meta);  | 
254  | 536  |             free(cpath);  | 
255  | 536  |             return -1;  | 
256  | 536  |         }  | 
257  |  |  | 
258  | 1.27k  |         std::unique_ptr<TSK_FS_FILE, decltype(&tsk_fs_file_close)> fs_file_alloc{ | 
259  | 1.27k  |             nullptr,  // set to the allocated file that is our target  | 
260  | 1.27k  |             tsk_fs_file_close  | 
261  | 1.27k  |         };  | 
262  |  |  | 
263  | 1.27k  |         std::unique_ptr<TSK_FS_FILE, decltype(&tsk_fs_file_close)> fs_file_del{ | 
264  | 1.27k  |             nullptr,  // set to an unallocated file that matches our criteria  | 
265  | 1.27k  |             tsk_fs_file_close  | 
266  | 1.27k  |         };  | 
267  |  |  | 
268  |  |         // cycle through each entry  | 
269  | 12.7k  |         for (i = 0; i < tsk_fs_dir_getsize(fs_dir.get()); i++) { | 
270  |  |  | 
271  | 11.7k  |             uint8_t found_name = 0;  | 
272  |  |  | 
273  | 11.7k  |             std::unique_ptr<TSK_FS_FILE, decltype(&tsk_fs_file_close)> fs_file{ | 
274  | 11.7k  |                 tsk_fs_dir_get(fs_dir.get(), i),  | 
275  | 11.7k  |                 tsk_fs_file_close  | 
276  | 11.7k  |             };  | 
277  |  |  | 
278  | 11.7k  |             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  | 11.7k  |             if ((fs_file->name->name)  | 
288  | 11.7k  |                 && (a_fs->name_cmp(a_fs, fs_file->name->name,  | 
289  | 11.7k  |                         cur_dir) == 0)) { | 
290  | 251  |                 found_name = 1;  | 
291  | 251  |             }  | 
292  | 11.4k  |             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  | 11.7k  |             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  | 11.7k  |             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  | 251  |                 if (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC) { | 
330  | 251  |                     fs_file_alloc = std::move(fs_file);  | 
331  | 251  |                     break;  | 
332  | 251  |                 }  | 
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  | 251  |             }  | 
342  | 11.7k  |         }  | 
343  |  |  | 
344  |  |         // we found a directory, go into it  | 
345  | 1.27k  |         if (fs_file_alloc || fs_file_del) { | 
346  |  |  | 
347  | 251  |             const char *pname;  | 
348  | 251  |             TSK_FS_FILE *fs_file_tmp;  | 
349  |  |  | 
350  |  |             // choose the alloc one first (if they both exist)  | 
351  | 251  |             if (fs_file_alloc)  | 
352  | 251  |                 fs_file_tmp = fs_file_alloc.get();  | 
353  | 0  |             else  | 
354  | 0  |                 fs_file_tmp = fs_file_del.get();  | 
355  |  |  | 
356  | 251  |             pname = cur_dir;    // save a copy of the current name pointer  | 
357  |  |  | 
358  |  |             // advance to the next name  | 
359  | 251  |             cur_dir = (char *) strtok_r(NULL, "/", &strtok_last);  | 
360  | 251  |             cur_attr = NULL;  | 
361  |  |  | 
362  | 251  |             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  | 251  |             if (cur_dir == NULL) { | 
368  | 251  |                 *a_result = fs_file_tmp->name->meta_addr;  | 
369  |  |  | 
370  |  |                 // make a copy if one was requested  | 
371  | 251  |                 if (a_fs_name) { | 
372  | 0  |                     tsk_fs_name_copy(a_fs_name, fs_file_tmp->name);  | 
373  | 0  |                 }  | 
374  |  |  | 
375  | 251  |                 free(cpath);  | 
376  | 251  |                 return 0;  | 
377  | 251  |             }  | 
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  | 1.02k  |         else { | 
392  | 1.02k  |             is_done = 1;  | 
393  | 1.02k  |         }  | 
394  | 1.27k  |     }  | 
395  |  |  | 
396  | 1.02k  |     free(cpath);  | 
397  | 1.02k  |     return 1;  | 
398  | 5.05k  | }  | 
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  | }  |