/src/sleuthkit/tsk/fs/fatfs.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ** The Sleuth Kit |
3 | | ** |
4 | | ** Copyright (c) 2013 Basis Technology Corp. All rights reserved |
5 | | ** Contact: Brian Carrier [carrier <at> sleuthkit [dot] org] |
6 | | ** |
7 | | ** This software is distributed under the Common Public License 1.0 |
8 | | ** |
9 | | */ |
10 | | |
11 | | /** |
12 | | * \file fatfs.c |
13 | | * Contains the internal TSK FAT file system code to handle basic file system |
14 | | * processing for opening file system, processing sectors, and directory entries. |
15 | | */ |
16 | | |
17 | | #include "tsk_fs_i.h" |
18 | | #include "tsk_fatfs.h" |
19 | | #include "tsk_fatxxfs.h" |
20 | | #include "tsk_exfatfs.h" |
21 | | |
22 | | #include "encryptionHelper.h" |
23 | | |
24 | | /** |
25 | | * \internal |
26 | | * Open part of a disk image as a FAT file system. |
27 | | * |
28 | | * @param a_img_info Disk image to analyze |
29 | | * @param a_offset Byte offset where FAT file system starts |
30 | | * @param a_ftype Specific type of FAT file system |
31 | | * @param a_pass (Optional) bitlocker password |
32 | | * @param a_test NOT USED |
33 | | * @returns NULL on error or if data is not a FAT file system |
34 | | */ |
35 | | TSK_FS_INFO * |
36 | | fatfs_open( |
37 | | TSK_IMG_INFO *a_img_info, |
38 | | TSK_OFF_T a_offset, |
39 | | TSK_FS_TYPE_ENUM a_ftype, |
40 | | const char* a_pass, |
41 | | [[maybe_unused]] uint8_t a_test) |
42 | 0 | { |
43 | 0 | const char *func_name = "fatfs_open"; |
44 | 0 | FATFS_INFO *fatfs = NULL; |
45 | 0 | TSK_FS_INFO *fs = NULL; |
46 | 0 | int find_boot_sector_attempt = 0; |
47 | |
|
48 | 0 | tsk_error_reset(); |
49 | |
|
50 | 0 | if (TSK_FS_TYPE_ISFAT(a_ftype) == 0) { |
51 | 0 | tsk_error_reset(); |
52 | 0 | tsk_error_set_errno(TSK_ERR_FS_ARG); |
53 | 0 | tsk_error_set_errstr("%s: Invalid FS Type", func_name); |
54 | 0 | return NULL; |
55 | 0 | } |
56 | | |
57 | 0 | if (a_img_info->sector_size == 0) { |
58 | 0 | tsk_error_reset(); |
59 | 0 | tsk_error_set_errno(TSK_ERR_FS_ARG); |
60 | 0 | tsk_error_set_errstr("fatfs_open: sector size is 0"); |
61 | 0 | return NULL; |
62 | 0 | } |
63 | | |
64 | | // Allocate an FATFS_INFO and initialize its generic TSK_FS_INFO members. |
65 | 0 | if ((fatfs = (FATFS_INFO*)tsk_fs_malloc(sizeof(FATFS_INFO))) == NULL) { |
66 | 0 | return NULL; |
67 | 0 | } |
68 | 0 | fs = &(fatfs->fs_info); |
69 | 0 | fs->ftype = a_ftype; |
70 | 0 | fs->img_info = a_img_info; |
71 | 0 | fs->offset = a_offset; |
72 | 0 | fs->dev_bsize = a_img_info->sector_size; |
73 | 0 | fs->journ_inum = 0; |
74 | 0 | fs->tag = TSK_FS_INFO_TAG; |
75 | | |
76 | | // Check for any volume encryption and initialize if found. |
77 | | // A non-zero value will only be returned if we are very confident encryption was found |
78 | | // but encountered an error and should not continue trying to open the volume. |
79 | | // In this case we should also have a specific error to get back to the user, such as reporting an incorrect password. |
80 | 0 | if (0 != handleVolumeEncryption(fs, a_pass)) { |
81 | 0 | tsk_fs_free((TSK_FS_INFO*)fatfs); |
82 | 0 | return NULL; |
83 | 0 | } |
84 | | |
85 | | // Look for a FAT boot sector. Try up to three times because FAT32 and exFAT file systems have backup boot sectors. |
86 | 0 | for (find_boot_sector_attempt = 0; find_boot_sector_attempt < 3; ++find_boot_sector_attempt) { |
87 | 0 | TSK_OFF_T boot_sector_offset; |
88 | 0 | FATFS_MASTER_BOOT_RECORD *bootSector; |
89 | 0 | ssize_t bytes_read = 0; |
90 | |
|
91 | 0 | switch (find_boot_sector_attempt) { |
92 | 0 | case 0: |
93 | 0 | boot_sector_offset = 0; |
94 | 0 | break; |
95 | 0 | case 1: |
96 | | // The FATXX backup boot sector is located in sector 6, look there. |
97 | 0 | boot_sector_offset = 6 * fs->img_info->sector_size; |
98 | 0 | break; |
99 | 0 | case 2: |
100 | | // The exFAT backup boot sector is located in sector 12, look there. |
101 | 0 | boot_sector_offset = 12 * fs->img_info->sector_size; |
102 | 0 | break; |
103 | 0 | } |
104 | | |
105 | | // Read in the prospective boot sector. |
106 | 0 | bytes_read = tsk_fs_read(fs, boot_sector_offset, fatfs->boot_sector_buffer, FATFS_MASTER_BOOT_RECORD_SIZE); |
107 | 0 | if (bytes_read != FATFS_MASTER_BOOT_RECORD_SIZE) { |
108 | 0 | if (bytes_read >= 0) { |
109 | 0 | tsk_error_reset(); |
110 | 0 | tsk_error_set_errno(TSK_ERR_FS_READ); |
111 | 0 | } |
112 | 0 | tsk_error_set_errstr2("%s: boot sector", func_name); |
113 | 0 | tsk_fs_free((TSK_FS_INFO *)fatfs); |
114 | 0 | return NULL; |
115 | 0 | } |
116 | | |
117 | | // Check it out... |
118 | 0 | bootSector = (FATFS_MASTER_BOOT_RECORD*)fatfs->boot_sector_buffer; |
119 | 0 | if (tsk_fs_guessu16(fs, bootSector->magic, FATFS_FS_MAGIC) != 0) { |
120 | | // No magic, look for a backup boot sector. |
121 | 0 | if ((tsk_getu16(TSK_LIT_ENDIAN, bootSector->magic) == 0) && (find_boot_sector_attempt < 3)) { |
122 | 0 | continue; |
123 | 0 | } |
124 | 0 | else { |
125 | 0 | tsk_error_reset(); |
126 | 0 | tsk_error_set_errno(TSK_ERR_FS_MAGIC); |
127 | 0 | tsk_error_set_errstr("Not a FATFS file system (magic)"); |
128 | 0 | if (tsk_verbose) { |
129 | 0 | fprintf(stderr, "%s: Incorrect FATFS magic\n", func_name); |
130 | 0 | } |
131 | 0 | tsk_fs_free((TSK_FS_INFO *)fatfs); |
132 | 0 | return NULL; |
133 | 0 | } |
134 | 0 | } |
135 | 0 | else { |
136 | | // Found the magic. |
137 | 0 | fatfs->using_backup_boot_sector = boot_sector_offset > 0; |
138 | 0 | if (fatfs->using_backup_boot_sector && tsk_verbose) { |
139 | 0 | fprintf(stderr, "%s: Using backup boot sector\n", func_name); |
140 | 0 | } |
141 | 0 | break; |
142 | 0 | } |
143 | 0 | } |
144 | | |
145 | | // Attempt to open the file system as one of the FAT types. |
146 | 0 | if ((a_ftype == TSK_FS_TYPE_FAT_DETECT && (fatxxfs_open(fatfs) == 0 || exfatfs_open(fatfs) == 0)) || |
147 | 0 | (a_ftype == TSK_FS_TYPE_EXFAT && exfatfs_open(fatfs) == 0) || |
148 | 0 | (fatxxfs_open(fatfs) == 0)) { |
149 | 0 | return (TSK_FS_INFO*)fatfs; |
150 | 0 | } |
151 | 0 | else { |
152 | 0 | tsk_fs_free((TSK_FS_INFO *)fatfs); |
153 | 0 | return NULL; |
154 | 0 | } |
155 | 0 | } |
156 | | |
157 | | /* TTL is 0 if the entry has not been used. TTL of 1 means it was the |
158 | | * most recently used, and TTL of FATFS_FAT_CACHE_N means it was the least |
159 | | * recently used. This function has a LRU replacement algo |
160 | | * |
161 | | * Note: This routine assumes &fatfs->cache_lock is locked by the caller. |
162 | | */ |
163 | | // return -1 on error, or cache index on success (0 to FATFS_FAT_CACHE_N) |
164 | | |
165 | | static int |
166 | | getFATCacheIdx(FATFS_INFO * fatfs, TSK_DADDR_T sect) |
167 | 0 | { |
168 | 0 | int i, cidx; |
169 | 0 | ssize_t cnt; |
170 | 0 | TSK_FS_INFO *fs = (TSK_FS_INFO *) & fatfs->fs_info; |
171 | | |
172 | | // see if we already have it in the cache |
173 | 0 | for (i = 0; i < FATFS_FAT_CACHE_N; i++) { |
174 | 0 | if ((fatfs->fatc_ttl[i] > 0) && |
175 | 0 | (sect >= fatfs->fatc_addr[i]) && |
176 | 0 | (sect < (fatfs->fatc_addr[i] + (FATFS_FAT_CACHE_B >> fatfs->ssize_sh)))) { |
177 | 0 | int a; |
178 | | |
179 | | // update the TTLs to push i to the front |
180 | 0 | for (a = 0; a < FATFS_FAT_CACHE_N; a++) { |
181 | 0 | if (fatfs->fatc_ttl[a] == 0) |
182 | 0 | continue; |
183 | | |
184 | 0 | if (fatfs->fatc_ttl[a] < fatfs->fatc_ttl[i]) |
185 | 0 | fatfs->fatc_ttl[a]++; |
186 | 0 | } |
187 | 0 | fatfs->fatc_ttl[i] = 1; |
188 | | // fprintf(stdout, "FAT Hit: %d\n", sect); |
189 | | // fflush(stdout); |
190 | 0 | return i; |
191 | 0 | } |
192 | 0 | } |
193 | | |
194 | | // fprintf(stdout, "FAT Miss: %d\n", (int)sect); |
195 | | // fflush(stdout); |
196 | | |
197 | | // Look for an unused entry or an entry with a TTL of FATFS_FAT_CACHE_N |
198 | 0 | cidx = 0; |
199 | 0 | for (i = 0; i < FATFS_FAT_CACHE_N; i++) { |
200 | 0 | if ((fatfs->fatc_ttl[i] == 0) || |
201 | 0 | (fatfs->fatc_ttl[i] >= FATFS_FAT_CACHE_N)) { |
202 | 0 | cidx = i; |
203 | 0 | } |
204 | 0 | } |
205 | | // fprintf(stdout, "FAT Removing: %d\n", (int)fatfs->fatc_addr[cidx]); |
206 | | // fflush(stdout); |
207 | | |
208 | | // read the data |
209 | 0 | cnt = |
210 | 0 | tsk_fs_read(fs, sect * fs->block_size, fatfs->fatc_buf[cidx], |
211 | 0 | FATFS_FAT_CACHE_B); |
212 | 0 | if (cnt != FATFS_FAT_CACHE_B) { |
213 | 0 | if (cnt >= 0) { |
214 | 0 | tsk_error_reset(); |
215 | 0 | tsk_error_set_errno(TSK_ERR_FS_READ); |
216 | 0 | } |
217 | 0 | tsk_error_set_errstr2("getFATCacheIdx: FAT: %" PRIuDADDR, sect); |
218 | 0 | return -1; |
219 | 0 | } |
220 | | |
221 | | // update the TTLs |
222 | 0 | if (fatfs->fatc_ttl[cidx] == 0) // special case for unused entry |
223 | 0 | fatfs->fatc_ttl[cidx] = FATFS_FAT_CACHE_N + 1; |
224 | |
|
225 | 0 | for (i = 0; i < FATFS_FAT_CACHE_N; i++) { |
226 | 0 | if (fatfs->fatc_ttl[i] == 0) |
227 | 0 | continue; |
228 | | |
229 | 0 | if (fatfs->fatc_ttl[i] < fatfs->fatc_ttl[cidx]) |
230 | 0 | fatfs->fatc_ttl[i]++; |
231 | 0 | } |
232 | |
|
233 | 0 | fatfs->fatc_ttl[cidx] = 1; |
234 | 0 | fatfs->fatc_addr[cidx] = sect; |
235 | |
|
236 | 0 | return cidx; |
237 | 0 | } |
238 | | |
239 | | /* |
240 | | * Set *value to the entry in the File Allocation Table (FAT) |
241 | | * for the given cluster |
242 | | * |
243 | | * *value is in clusters and may need to be converted to |
244 | | * sectors by the calling function |
245 | | * |
246 | | * Invalid values in the FAT (i.e. greater than the largest |
247 | | * cluster have a value of 0 returned and a 0 return value. |
248 | | * |
249 | | * Return 1 on error and 0 on success |
250 | | */ |
251 | | uint8_t |
252 | | fatfs_getFAT(FATFS_INFO * fatfs, TSK_DADDR_T clust, TSK_DADDR_T * value) |
253 | 0 | { |
254 | 0 | uint8_t *a_ptr; |
255 | 0 | uint16_t tmp16; |
256 | 0 | TSK_FS_INFO *fs = (TSK_FS_INFO *) & fatfs->fs_info; |
257 | 0 | TSK_DADDR_T sect, offs; |
258 | 0 | int cidx; |
259 | | |
260 | | /* Sanity Check */ |
261 | 0 | if (clust > fatfs->lastclust) { |
262 | | /* silently ignore requests for the unclustered sectors... */ |
263 | 0 | if ((clust == fatfs->lastclust + 1) && |
264 | 0 | ((fatfs->firstclustsect + fatfs->csize * fatfs->clustcnt - |
265 | 0 | 1) != fs->last_block)) { |
266 | 0 | if (tsk_verbose) |
267 | 0 | tsk_fprintf(stderr, |
268 | 0 | "fatfs_getFAT: Ignoring request for non-clustered sector\n"); |
269 | 0 | return 0; |
270 | 0 | } |
271 | | |
272 | 0 | tsk_error_reset(); |
273 | 0 | tsk_error_set_errno(TSK_ERR_FS_ARG); |
274 | 0 | tsk_error_set_errstr("fatfs_getFAT: invalid cluster address: %" |
275 | 0 | PRIuDADDR, clust); |
276 | 0 | return 1; |
277 | 0 | } |
278 | | |
279 | 0 | switch (fatfs->fs_info.ftype) { |
280 | 0 | case TSK_FS_TYPE_FAT12: |
281 | 0 | if (clust & 0xf000) { |
282 | 0 | tsk_error_reset(); |
283 | 0 | tsk_error_set_errno(TSK_ERR_FS_ARG); |
284 | 0 | tsk_error_set_errstr |
285 | 0 | ("fatfs_getFAT: TSK_FS_TYPE_FAT12 Cluster %" PRIuDADDR |
286 | 0 | " too large", clust); |
287 | 0 | return 1; |
288 | 0 | } |
289 | | |
290 | | /* id the sector in the FAT */ |
291 | 0 | sect = fatfs->firstfatsect + |
292 | 0 | ((clust + (clust >> 1)) >> fatfs->ssize_sh); |
293 | |
|
294 | 0 | tsk_take_lock(&fatfs->cache_lock); |
295 | | |
296 | | /* Load the FAT if we don't have it */ |
297 | | // see if it is in the cache |
298 | 0 | if (-1 == (cidx = getFATCacheIdx(fatfs, sect))) { |
299 | 0 | tsk_release_lock(&fatfs->cache_lock); |
300 | 0 | return 1; |
301 | 0 | } |
302 | | |
303 | | /* get the offset into the cache */ |
304 | 0 | offs = ((sect - fatfs->fatc_addr[cidx]) << fatfs->ssize_sh) + |
305 | 0 | (clust + (clust >> 1)) % fatfs->ssize; |
306 | | |
307 | | /* special case when the 12-bit value goes across the cache |
308 | | * we load the cache to start at this sect. The cache |
309 | | * size must therefore be at least 2 sectors large |
310 | | */ |
311 | 0 | if (offs == (FATFS_FAT_CACHE_B - 1)) { |
312 | 0 | ssize_t cnt; |
313 | | |
314 | | // read the data -- TTLs will already have been updated |
315 | 0 | cnt = |
316 | 0 | tsk_fs_read(fs, sect * fs->block_size, |
317 | 0 | fatfs->fatc_buf[cidx], FATFS_FAT_CACHE_B); |
318 | 0 | if (cnt != FATFS_FAT_CACHE_B) { |
319 | 0 | tsk_release_lock(&fatfs->cache_lock); |
320 | 0 | if (cnt >= 0) { |
321 | 0 | tsk_error_reset(); |
322 | 0 | tsk_error_set_errno(TSK_ERR_FS_READ); |
323 | 0 | } |
324 | 0 | tsk_error_set_errstr2 |
325 | 0 | ("fatfs_getFAT: TSK_FS_TYPE_FAT12 FAT overlap: %" |
326 | 0 | PRIuDADDR, sect); |
327 | 0 | return 1; |
328 | 0 | } |
329 | 0 | fatfs->fatc_addr[cidx] = sect; |
330 | |
|
331 | 0 | offs = (clust + (clust >> 1)) % fatfs->ssize; |
332 | 0 | } |
333 | | |
334 | | /* get pointer to entry in current buffer */ |
335 | 0 | a_ptr = (uint8_t *) fatfs->fatc_buf[cidx] + offs; |
336 | |
|
337 | 0 | tmp16 = tsk_getu16(fs->endian, a_ptr); |
338 | |
|
339 | 0 | tsk_release_lock(&fatfs->cache_lock); |
340 | | |
341 | | /* slide it over if it is one of the odd clusters */ |
342 | 0 | if (clust & 1) |
343 | 0 | tmp16 >>= 4; |
344 | |
|
345 | 0 | *value = tmp16 & FATFS_12_MASK; |
346 | | |
347 | | /* sanity check */ |
348 | 0 | if ((*value > (fatfs->lastclust)) && |
349 | 0 | (*value < (0x0ffffff7 & FATFS_12_MASK))) { |
350 | 0 | if (tsk_verbose) |
351 | 0 | tsk_fprintf(stderr, |
352 | 0 | "fatfs_getFAT: TSK_FS_TYPE_FAT12 cluster (%" PRIuDADDR |
353 | 0 | ") too large (%" PRIuDADDR ") - resetting\n", clust, |
354 | 0 | *value); |
355 | 0 | *value = 0; |
356 | 0 | } |
357 | 0 | return 0; |
358 | | |
359 | 0 | case TSK_FS_TYPE_FAT16: |
360 | | /* Get sector in FAT for cluster and load it if needed */ |
361 | 0 | sect = fatfs->firstfatsect + ((clust << 1) >> fatfs->ssize_sh); |
362 | |
|
363 | 0 | tsk_take_lock(&fatfs->cache_lock); |
364 | |
|
365 | 0 | if (-1 == (cidx = getFATCacheIdx(fatfs, sect))) { |
366 | 0 | tsk_release_lock(&fatfs->cache_lock); |
367 | 0 | return 1; |
368 | 0 | } |
369 | | |
370 | | |
371 | | /* get pointer to entry in the cache buffer */ |
372 | 0 | a_ptr = (uint8_t *) fatfs->fatc_buf[cidx] + |
373 | 0 | ((sect - fatfs->fatc_addr[cidx]) << fatfs->ssize_sh) + |
374 | 0 | ((clust << 1) % fatfs->ssize); |
375 | |
|
376 | 0 | *value = tsk_getu16(fs->endian, a_ptr) & FATFS_16_MASK; |
377 | |
|
378 | 0 | tsk_release_lock(&fatfs->cache_lock); |
379 | | |
380 | | /* sanity check */ |
381 | 0 | if ((*value > (fatfs->lastclust)) && |
382 | 0 | (*value < (0x0ffffff7 & FATFS_16_MASK))) { |
383 | 0 | if (tsk_verbose) |
384 | 0 | tsk_fprintf(stderr, |
385 | 0 | "fatfs_getFAT: contents of TSK_FS_TYPE_FAT16 entry %" |
386 | 0 | PRIuDADDR " too large - resetting\n", clust); |
387 | 0 | *value = 0; |
388 | 0 | } |
389 | 0 | return 0; |
390 | | |
391 | 0 | case TSK_FS_TYPE_FAT32: |
392 | 0 | case TSK_FS_TYPE_EXFAT: |
393 | | /* Get sector in FAT for cluster and load if needed */ |
394 | 0 | sect = fatfs->firstfatsect + ((clust << 2) >> fatfs->ssize_sh); |
395 | |
|
396 | 0 | tsk_take_lock(&fatfs->cache_lock); |
397 | |
|
398 | 0 | if (-1 == (cidx = getFATCacheIdx(fatfs, sect))) { |
399 | 0 | tsk_release_lock(&fatfs->cache_lock); |
400 | 0 | return 1; |
401 | 0 | } |
402 | | |
403 | | /* get pointer to entry in current buffer */ |
404 | 0 | a_ptr = (uint8_t *) fatfs->fatc_buf[cidx] + |
405 | 0 | ((sect - fatfs->fatc_addr[cidx]) << fatfs->ssize_sh) + |
406 | 0 | (clust << 2) % fatfs->ssize; |
407 | |
|
408 | 0 | *value = tsk_getu32(fs->endian, a_ptr) & FATFS_32_MASK; |
409 | |
|
410 | 0 | tsk_release_lock(&fatfs->cache_lock); |
411 | | |
412 | | /* sanity check */ |
413 | 0 | if ((*value > fatfs->lastclust) && |
414 | 0 | (*value < (0x0ffffff7 & FATFS_32_MASK))) { |
415 | 0 | if (tsk_verbose) |
416 | 0 | tsk_fprintf(stderr, |
417 | 0 | "fatfs_getFAT: contents of entry %" PRIuDADDR |
418 | 0 | " too large - resetting\n", clust); |
419 | |
|
420 | 0 | *value = 0; |
421 | 0 | } |
422 | 0 | return 0; |
423 | | |
424 | 0 | default: |
425 | 0 | tsk_error_reset(); |
426 | 0 | tsk_error_set_errno(TSK_ERR_FS_ARG); |
427 | 0 | tsk_error_set_errstr("fatfs_getFAT: Unknown FAT type: %d", |
428 | 0 | fatfs->fs_info.ftype); |
429 | 0 | return 1; |
430 | 0 | } |
431 | 0 | } |
432 | | |
433 | | /************************************************************************** |
434 | | * |
435 | | * BLOCK WALKING |
436 | | * |
437 | | *************************************************************************/ |
438 | | /* |
439 | | ** Walk the sectors of the partition. |
440 | | ** |
441 | | ** NOTE: This is by SECTORS and not CLUSTERS |
442 | | ** _flags: TSK_FS_BLOCK_FLAG_ALLOC, TSK_FS_BLOCK_FLAG_UNALLOC, TSK_FS_BLOCK_FLAG_META |
443 | | ** TSK_FS_BLOCK_FLAG_CONT |
444 | | ** |
445 | | */ |
446 | | uint8_t |
447 | | fatfs_block_walk(TSK_FS_INFO * fs, TSK_DADDR_T a_start_blk, |
448 | | TSK_DADDR_T a_end_blk, TSK_FS_BLOCK_WALK_FLAG_ENUM a_flags, |
449 | | TSK_FS_BLOCK_WALK_CB a_action, void *a_ptr) |
450 | 0 | { |
451 | 0 | const char *myname = "fatfs_block_walk"; |
452 | 0 | FATFS_INFO *fatfs = (FATFS_INFO *) fs; |
453 | 0 | char *data_buf = NULL; |
454 | 0 | ssize_t cnt; |
455 | 0 | TSK_FS_BLOCK *fs_block; |
456 | |
|
457 | 0 | TSK_DADDR_T addr; |
458 | 0 | int myflags; |
459 | 0 | unsigned int i; |
460 | | |
461 | | // clean up any error messages that are lying around |
462 | 0 | tsk_error_reset(); |
463 | | |
464 | | /* |
465 | | * Sanity checks. |
466 | | */ |
467 | 0 | if (a_start_blk < fs->first_block || a_start_blk > fs->last_block) { |
468 | 0 | tsk_error_reset(); |
469 | 0 | tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); |
470 | 0 | tsk_error_set_errstr("%s: Start block: %" PRIuDADDR "", myname, |
471 | 0 | a_start_blk); |
472 | 0 | return 1; |
473 | 0 | } |
474 | 0 | if (a_end_blk < fs->first_block || a_end_blk > fs->last_block) { |
475 | 0 | tsk_error_reset(); |
476 | 0 | tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); |
477 | 0 | tsk_error_set_errstr("%s: End block: %" PRIuDADDR "", myname, |
478 | 0 | a_end_blk); |
479 | 0 | return 1; |
480 | 0 | } |
481 | | |
482 | 0 | if (tsk_verbose) |
483 | 0 | tsk_fprintf(stderr, |
484 | 0 | "fatfs_block_walk: Block Walking %" PRIuDADDR " to %" |
485 | 0 | PRIuDADDR "\n", a_start_blk, a_end_blk); |
486 | | |
487 | | |
488 | | /* Sanity check on a_flags -- make sure at least one ALLOC is set */ |
489 | 0 | if (((a_flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC) == 0) && |
490 | 0 | ((a_flags & TSK_FS_BLOCK_WALK_FLAG_UNALLOC) == 0)) { |
491 | 0 | a_flags = (TSK_FS_BLOCK_WALK_FLAG_ENUM) |
492 | 0 | (a_flags | TSK_FS_BLOCK_WALK_FLAG_ALLOC | |
493 | 0 | TSK_FS_BLOCK_WALK_FLAG_UNALLOC); |
494 | 0 | } |
495 | 0 | if (((a_flags & TSK_FS_BLOCK_WALK_FLAG_META) == 0) && |
496 | 0 | ((a_flags & TSK_FS_BLOCK_WALK_FLAG_CONT) == 0)) { |
497 | 0 | a_flags = (TSK_FS_BLOCK_WALK_FLAG_ENUM) |
498 | 0 | (a_flags | TSK_FS_BLOCK_WALK_FLAG_CONT | TSK_FS_BLOCK_WALK_FLAG_META); |
499 | 0 | } |
500 | |
|
501 | 0 | if ((fs_block = tsk_fs_block_alloc(fs)) == NULL) { |
502 | 0 | return 1; |
503 | 0 | } |
504 | | |
505 | | /* cycle through the sectors. We do the sectors before the first |
506 | | * cluster separate from the data area */ |
507 | 0 | addr = a_start_blk; |
508 | | |
509 | | /* Before the data area beings (FAT, root directory etc.) */ |
510 | 0 | if ((a_start_blk < fatfs->firstclustsect) |
511 | 0 | && (a_flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC)) { |
512 | |
|
513 | 0 | if (tsk_verbose) |
514 | 0 | tsk_fprintf(stderr, |
515 | 0 | "fatfs_block_walk: Walking non-data area (pre %" |
516 | 0 | PRIuDADDR "\n)", fatfs->firstclustsect); |
517 | |
|
518 | 0 | if ((data_buf = (char *) tsk_malloc(fs->block_size * 8)) == NULL) { |
519 | 0 | tsk_fs_block_free(fs_block); |
520 | 0 | return 1; |
521 | 0 | } |
522 | | |
523 | | /* Read 8 sectors at a time to be faster */ |
524 | 0 | for (; addr < fatfs->firstclustsect && addr <= a_end_blk;) { |
525 | |
|
526 | 0 | if ((a_flags & TSK_FS_BLOCK_WALK_FLAG_AONLY) == 0) { |
527 | 0 | cnt = |
528 | 0 | tsk_fs_read_block(fs, addr, data_buf, |
529 | 0 | fs->block_size * 8); |
530 | 0 | if (cnt != fs->block_size * 8) { |
531 | 0 | if (cnt >= 0) { |
532 | 0 | tsk_error_reset(); |
533 | 0 | tsk_error_set_errno(TSK_ERR_FS_READ); |
534 | 0 | } |
535 | 0 | tsk_error_set_errstr2 |
536 | 0 | ("fatfs_block_walk: pre-data area block: %" |
537 | 0 | PRIuDADDR, addr); |
538 | 0 | free(data_buf); |
539 | 0 | tsk_fs_block_free(fs_block); |
540 | 0 | return 1; |
541 | 0 | } |
542 | 0 | } |
543 | | |
544 | | /* Process the sectors until we get to the clusters, |
545 | | * end of target, or end of buffer */ |
546 | 0 | for (i = 0; |
547 | 0 | i < 8 && (addr) <= a_end_blk |
548 | 0 | && (addr) < fatfs->firstclustsect; i++, addr++) { |
549 | 0 | int retval; |
550 | |
|
551 | 0 | myflags = TSK_FS_BLOCK_FLAG_ALLOC; |
552 | | |
553 | | /* stuff before the first data sector is the |
554 | | * FAT and boot sector */ |
555 | 0 | if (addr < fatfs->firstdatasect) |
556 | 0 | myflags |= TSK_FS_BLOCK_FLAG_META; |
557 | | /* This must be the root directory for FAT12/16 */ |
558 | 0 | else |
559 | 0 | myflags |= TSK_FS_BLOCK_FLAG_CONT; |
560 | | |
561 | | // test this sector (we already tested ALLOC) |
562 | 0 | if ((myflags & TSK_FS_BLOCK_FLAG_META) |
563 | 0 | && (!(a_flags & TSK_FS_BLOCK_WALK_FLAG_META))) |
564 | 0 | continue; |
565 | 0 | else if ((myflags & TSK_FS_BLOCK_FLAG_CONT) |
566 | 0 | && (!(a_flags & TSK_FS_BLOCK_WALK_FLAG_CONT))) |
567 | 0 | continue; |
568 | | |
569 | 0 | if (a_flags & TSK_FS_BLOCK_WALK_FLAG_AONLY) |
570 | 0 | myflags |= TSK_FS_BLOCK_FLAG_AONLY; |
571 | |
|
572 | 0 | tsk_fs_block_set(fs, fs_block, addr, |
573 | 0 | (TSK_FS_BLOCK_FLAG_ENUM) (myflags | TSK_FS_BLOCK_FLAG_RAW), |
574 | 0 | &data_buf[i * fs->block_size]); |
575 | |
|
576 | 0 | retval = a_action(fs_block, a_ptr); |
577 | 0 | if (retval == TSK_WALK_STOP) { |
578 | 0 | free(data_buf); |
579 | 0 | tsk_fs_block_free(fs_block); |
580 | 0 | return 0; |
581 | 0 | } |
582 | 0 | else if (retval == TSK_WALK_ERROR) { |
583 | 0 | free(data_buf); |
584 | 0 | tsk_fs_block_free(fs_block); |
585 | 0 | return 1; |
586 | 0 | } |
587 | 0 | } |
588 | 0 | } |
589 | | |
590 | 0 | free(data_buf); |
591 | | |
592 | | /* Was that it? */ |
593 | 0 | if (addr >= a_end_blk) { |
594 | 0 | tsk_fs_block_free(fs_block); |
595 | 0 | return 0; |
596 | 0 | } |
597 | 0 | } |
598 | | /* Reset the first sector to the start of the data area if we did |
599 | | * not examine it - the next calculation will screw up otherwise */ |
600 | 0 | else if (addr < fatfs->firstclustsect) { |
601 | 0 | addr = fatfs->firstclustsect; |
602 | 0 | } |
603 | | |
604 | | |
605 | | /* Now we read in the clusters in cluster-sized chunks, |
606 | | * sectors are too small |
607 | | */ |
608 | | |
609 | | /* Determine the base sector of the cluster where the first |
610 | | * sector is located */ |
611 | 0 | addr = FATFS_CLUST_2_SECT(fatfs, (FATFS_SECT_2_CLUST(fatfs, addr))); |
612 | |
|
613 | 0 | if ((data_buf = (char*) tsk_malloc(fs->block_size * fatfs->csize)) == NULL) { |
614 | 0 | tsk_fs_block_free(fs_block); |
615 | 0 | return 1; |
616 | 0 | } |
617 | | |
618 | 0 | if (tsk_verbose) |
619 | 0 | tsk_fprintf(stderr, |
620 | 0 | "fatfs_block_walk: Walking data area blocks (%" PRIuDADDR |
621 | 0 | " to %" PRIuDADDR ")\n", addr, a_end_blk); |
622 | |
|
623 | 0 | for (; addr <= a_end_blk; addr += fatfs->csize) { |
624 | 0 | int retval; |
625 | 0 | size_t read_size; |
626 | | |
627 | | /* Identify its allocation status */ |
628 | 0 | retval = fatfs_is_sectalloc(fatfs, addr); |
629 | 0 | if (retval == -1) { |
630 | 0 | free(data_buf); |
631 | 0 | tsk_fs_block_free(fs_block); |
632 | 0 | return 1; |
633 | 0 | } |
634 | 0 | else if (retval == 1) { |
635 | 0 | myflags = TSK_FS_BLOCK_FLAG_ALLOC; |
636 | 0 | } |
637 | 0 | else { |
638 | 0 | myflags = TSK_FS_BLOCK_FLAG_UNALLOC; |
639 | 0 | } |
640 | | |
641 | | /* At this point, there should be no more meta - just content */ |
642 | 0 | myflags |= TSK_FS_BLOCK_FLAG_CONT; |
643 | | |
644 | | // test if we should call the callback with this one |
645 | 0 | if ((myflags & TSK_FS_BLOCK_FLAG_CONT) |
646 | 0 | && (!(a_flags & TSK_FS_BLOCK_WALK_FLAG_CONT))) |
647 | 0 | continue; |
648 | 0 | else if ((myflags & TSK_FS_BLOCK_FLAG_ALLOC) |
649 | 0 | && (!(a_flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC))) |
650 | 0 | continue; |
651 | 0 | else if ((myflags & TSK_FS_BLOCK_FLAG_UNALLOC) |
652 | 0 | && (!(a_flags & TSK_FS_BLOCK_WALK_FLAG_UNALLOC))) |
653 | 0 | continue; |
654 | | |
655 | 0 | if (a_flags & TSK_FS_BLOCK_WALK_FLAG_AONLY) |
656 | 0 | myflags |= TSK_FS_BLOCK_FLAG_AONLY; |
657 | | |
658 | | |
659 | | /* The final cluster may not be full */ |
660 | 0 | if (a_end_blk - addr + 1 < fatfs->csize) |
661 | 0 | read_size = (size_t) (a_end_blk - addr + 1); |
662 | 0 | else |
663 | 0 | read_size = fatfs->csize; |
664 | |
|
665 | 0 | if ((a_flags & TSK_FS_BLOCK_WALK_FLAG_AONLY) == 0) { |
666 | 0 | cnt = tsk_fs_read_block |
667 | 0 | (fs, addr, data_buf, fs->block_size * read_size); |
668 | 0 | if (cnt != (ssize_t)(fs->block_size * read_size)) { |
669 | 0 | if (cnt >= 0) { |
670 | 0 | tsk_error_reset(); |
671 | 0 | tsk_error_set_errno(TSK_ERR_FS_READ); |
672 | 0 | } |
673 | 0 | tsk_error_set_errstr2("fatfs_block_walk: block: %" |
674 | 0 | PRIuDADDR, addr); |
675 | 0 | free(data_buf); |
676 | 0 | tsk_fs_block_free(fs_block); |
677 | 0 | return 1; |
678 | 0 | } |
679 | 0 | } |
680 | | |
681 | | /* go through each sector in the cluster */ |
682 | 0 | for (i = 0; i < read_size; i++) { |
683 | 0 | int retval; |
684 | |
|
685 | 0 | if (addr + i < a_start_blk) |
686 | 0 | continue; |
687 | 0 | else if (addr + i > a_end_blk) |
688 | 0 | break; |
689 | | |
690 | 0 | tsk_fs_block_set(fs, fs_block, addr + i, |
691 | 0 | (TSK_FS_BLOCK_FLAG_ENUM) (myflags | TSK_FS_BLOCK_FLAG_RAW), |
692 | 0 | &data_buf[i * fs->block_size]); |
693 | |
|
694 | 0 | retval = a_action(fs_block, a_ptr); |
695 | 0 | if (retval == TSK_WALK_STOP) { |
696 | 0 | free(data_buf); |
697 | 0 | tsk_fs_block_free(fs_block); |
698 | 0 | return 0; |
699 | 0 | } |
700 | 0 | else if (retval == TSK_WALK_ERROR) { |
701 | 0 | free(data_buf); |
702 | 0 | tsk_fs_block_free(fs_block); |
703 | 0 | return 1; |
704 | 0 | } |
705 | 0 | } |
706 | 0 | } |
707 | | |
708 | 0 | free(data_buf); |
709 | 0 | tsk_fs_block_free(fs_block); |
710 | 0 | return 0; |
711 | 0 | } |
712 | | |
713 | | TSK_FS_BLOCK_FLAG_ENUM |
714 | | fatfs_block_getflags(TSK_FS_INFO * a_fs, TSK_DADDR_T a_addr) |
715 | 0 | { |
716 | 0 | FATFS_INFO *fatfs = (FATFS_INFO *) a_fs; |
717 | 0 | int flags = 0; |
718 | | |
719 | | // FATs and boot sector |
720 | 0 | if (a_addr < fatfs->firstdatasect) { |
721 | 0 | flags = TSK_FS_BLOCK_FLAG_META | TSK_FS_BLOCK_FLAG_ALLOC; |
722 | 0 | } |
723 | | // root directory for FAT12/16 |
724 | 0 | else if (a_addr < fatfs->firstclustsect) { |
725 | 0 | flags = TSK_FS_BLOCK_FLAG_CONT | TSK_FS_BLOCK_FLAG_ALLOC; |
726 | 0 | } |
727 | 0 | else { |
728 | 0 | int retval; |
729 | 0 | flags = TSK_FS_BLOCK_FLAG_CONT; |
730 | | |
731 | | /* Identify its allocation status */ |
732 | 0 | retval = fatfs_is_sectalloc(fatfs, a_addr); |
733 | 0 | if (retval != -1) { |
734 | 0 | if (retval == 1) |
735 | 0 | flags |= TSK_FS_BLOCK_FLAG_ALLOC; |
736 | 0 | else |
737 | 0 | flags |= TSK_FS_BLOCK_FLAG_UNALLOC; |
738 | 0 | } |
739 | 0 | } |
740 | 0 | return (TSK_FS_BLOCK_FLAG_ENUM)flags; |
741 | 0 | } |
742 | | |
743 | | /* |
744 | | * Identifies if a sector is allocated |
745 | | * |
746 | | * If it is less than the data area, then it is allocated |
747 | | * else the FAT table is consulted |
748 | | * |
749 | | * Return 1 if allocated, 0 if unallocated, and -1 if error |
750 | | */ |
751 | | int8_t |
752 | | fatfs_is_sectalloc(FATFS_INFO * fatfs, TSK_DADDR_T sect) |
753 | 0 | { |
754 | 0 | TSK_FS_INFO *fs = (TSK_FS_INFO *) fatfs; |
755 | | /* If less than the first cluster sector, then it is allocated |
756 | | * otherwise check the FAT |
757 | | */ |
758 | 0 | if (sect < fatfs->firstclustsect) |
759 | 0 | return 1; |
760 | | |
761 | | /* If we are in the unused area, then we are "unalloc" */ |
762 | 0 | if ((sect <= fs->last_block) && |
763 | 0 | (sect >= (fatfs->firstclustsect + fatfs->csize * fatfs->clustcnt))) |
764 | 0 | return 0; |
765 | | |
766 | 0 | return fatfs->is_cluster_alloc(fatfs, FATFS_SECT_2_CLUST(fatfs, sect)); |
767 | 0 | } |
768 | | |
769 | | /* return 1 on error and 0 on success */ |
770 | | uint8_t |
771 | | fatfs_jopen( |
772 | | [[maybe_unused]] TSK_FS_INFO * fs, |
773 | | [[maybe_unused]] TSK_INUM_T inum) |
774 | 0 | { |
775 | 0 | tsk_error_reset(); |
776 | 0 | tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC); |
777 | 0 | tsk_error_set_errstr("FAT does not have a journal\n"); |
778 | 0 | return 1; |
779 | 0 | } |
780 | | |
781 | | /* return 1 on error and 0 on success */ |
782 | | uint8_t |
783 | | fatfs_fscheck( |
784 | | [[maybe_unused]] TSK_FS_INFO * fs, |
785 | | [[maybe_unused]] FILE * hFile) |
786 | 0 | { |
787 | 0 | tsk_error_reset(); |
788 | 0 | tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC); |
789 | 0 | tsk_error_set_errstr("fscheck not implemented for FAT yet"); |
790 | 0 | return 1; |
791 | | |
792 | | /* Check that allocated dentries point to start of allocated cluster chain */ |
793 | | |
794 | | |
795 | | /* Size of file is consistent with cluster chain length */ |
796 | | |
797 | | |
798 | | /* Allocated cluster chains have a corresponding alloc dentry */ |
799 | | |
800 | | |
801 | | /* Non file dentries have no clusters */ |
802 | | |
803 | | |
804 | | /* Only one volume label */ |
805 | | |
806 | | |
807 | | /* Dump Bad Sector Addresses */ |
808 | | |
809 | | |
810 | | /* Dump unused sector addresses |
811 | | * Reserved area, end of FAT, end of Data Area */ |
812 | 0 | } |
813 | | |
814 | | /* return 1 on error and 0 on success */ |
815 | | uint8_t |
816 | | fatfs_jentry_walk( |
817 | | [[maybe_unused]] TSK_FS_INFO * fs, |
818 | | [[maybe_unused]] int a_flags, |
819 | | [[maybe_unused]] TSK_FS_JENTRY_WALK_CB a_action, |
820 | | [[maybe_unused]] void *a_ptr) |
821 | 0 | { |
822 | 0 | tsk_error_reset(); |
823 | 0 | tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC); |
824 | 0 | tsk_error_set_errstr("FAT does not have a journal\n"); |
825 | 0 | return 1; |
826 | 0 | } |
827 | | |
828 | | /* return 1 on error and 0 on success */ |
829 | | uint8_t |
830 | | fatfs_jblk_walk( |
831 | | [[maybe_unused]] TSK_FS_INFO * fs, |
832 | | [[maybe_unused]] TSK_DADDR_T start, |
833 | | [[maybe_unused]] TSK_DADDR_T end, |
834 | | [[maybe_unused]] int a_flags, |
835 | | [[maybe_unused]] TSK_FS_JBLK_WALK_CB a_action, |
836 | | [[maybe_unused]] void *a_ptr) |
837 | 0 | { |
838 | 0 | tsk_error_reset(); |
839 | 0 | tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC); |
840 | 0 | tsk_error_set_errstr("FAT does not have a journal\n"); |
841 | 0 | return 1; |
842 | 0 | } |
843 | | |
844 | | /* fatfs_close - close an fatfs file system */ |
845 | | void |
846 | | fatfs_close(TSK_FS_INFO *fs) |
847 | 0 | { |
848 | 0 | FATFS_INFO *fatfs = (FATFS_INFO *) fs; |
849 | |
|
850 | 0 | fatfs_dir_buf_free(fatfs); |
851 | |
|
852 | 0 | fs->tag = 0; |
853 | 0 | memset(fatfs->boot_sector_buffer, 0, FATFS_MASTER_BOOT_RECORD_SIZE); |
854 | 0 | tsk_deinit_lock(&fatfs->cache_lock); |
855 | 0 | tsk_deinit_lock(&fatfs->dir_lock); |
856 | | |
857 | 0 | tsk_fs_free(fs); |
858 | 0 | } |
859 | | |