/** * \internal * Searches an exFAT file system for its volume label directory entry, which * should be in the root directory of the file system. If the entry is found, * its metadata is copied into the TSK_FS_META object of a TSK_FS_FILE object. * * @param [in] a_fatfs Generic FAT file system info structure. * @param [out] a_fatfs Generic file system file structure. * @return 0 on success, 1 otherwise, per TSK convention. */ static uint8_t exfatfs_find_volume_label_dentry(FATFS_INFO *a_fatfs, TSK_FS_FILE *a_fs_file) { const char *func_name = "exfatfs_find_volume_label_dentry"; TSK_FS_INFO *fs = (TSK_FS_INFO *)a_fatfs; TSK_DADDR_T current_sector = 0; TSK_DADDR_T last_sector_of_data_area = 0; char *sector_buf = NULL; ssize_t bytes_read = 0; TSK_INUM_T current_inum = 0; FATFS_DENTRY *dentry = NULL; uint64_t i = 0; assert(a_fatfs != NULL); assert(a_fs_file != NULL); tsk_error_reset(); if (fatfs_ptr_arg_is_null(a_fatfs, "a_fatfs", func_name) || fatfs_ptr_arg_is_null(a_fs_file, "a_fs_file", func_name)) { return FATFS_FAIL; } /* Allocate or reset the TSK_FS_META object. */ if (a_fs_file->meta == NULL) { if ((a_fs_file->meta = tsk_fs_meta_alloc(FATFS_FILE_CONTENT_LEN)) == NULL) { return FATFS_FAIL; } } else { tsk_fs_meta_reset(a_fs_file->meta); } /* Allocate a buffer for reading in sector-size chunks of the image. */ if ((sector_buf = (char*)tsk_malloc(a_fatfs->ssize)) == NULL) { return FATFS_FAIL; } current_sector = a_fatfs->rootsect; last_sector_of_data_area = a_fatfs->firstdatasect + (a_fatfs->clustcnt * a_fatfs->csize) - 1; while (current_sector < last_sector_of_data_area) { int8_t sector_is_alloc = 0; /* Read in a sector from the root directory. The volume label * directory entry will probably be near the beginning of the * directory, probably in the first sector. */ bytes_read = tsk_fs_read_block(fs, current_sector, sector_buf, a_fatfs->ssize); if (bytes_read != a_fatfs->ssize) { if (bytes_read >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_READ); } tsk_error_set_errstr2("%s: error reading sector: %" PRIuDADDR, func_name, current_sector); free(sector_buf); return FATFS_FAIL; } /* Get the allocation status of the sector (yes, it should be allocated). */ sector_is_alloc = fatfs_is_sectalloc(a_fatfs, current_sector); if (sector_is_alloc == -1) { return FATFS_FAIL; } /* Get the inode address of the first directory entry of the sector. */ current_inum = FATFS_SECT_2_INODE(a_fatfs, current_sector); /* Loop through the putative directory entries in the sector, * until the volume label entry is found. */ for (i = 0; i < a_fatfs->ssize; i += sizeof(FATFS_DENTRY)) { dentry = (FATFS_DENTRY*)&(sector_buf[i]); /* The type of the directory entry is encoded in the first byte * of the entry. See EXFATFS_DIR_ENTRY_TYPE_ENUM. */ if (exfatfs_get_enum_from_type(dentry->data[0]) == EXFATFS_DIR_ENTRY_TYPE_VOLUME_LABEL) { if (!exfatfs_is_vol_label_dentry(dentry, FATFS_DATA_UNIT_ALLOC_STATUS_UNKNOWN)) { continue; } /* Found it, save it to the TSK_FS_META object of the * TSK_FS_FILE object and exit. */ if (exfatfs_dinode_copy(a_fatfs, current_inum, dentry, sector_is_alloc, a_fs_file) == TSK_OK) { return FATFS_OK; } else { return FATFS_FAIL; } } } } free(sector_buf); return FATFS_OK; }
/** * /internal * Parse a buffer containing the contents of a directory and add TSK_FS_NAME * objects for each named file found to the TSK_FS_DIR representation of the * directory. * * @param fatfs File system information structure for file system that * contains the directory. * @param a_fs_dir Directory structure into to which parsed file metadata will * be added. * @param buf Buffer that contains the directory contents. * @param len Length of buffer in bytes (must be a multiple of sector * size). * @param addrs Array where each element is the original address of * the corresponding sector in a_buf (size of array is number of sectors in * the directory). * @return TSK_RETVAL_ENUM */ TSK_RETVAL_ENUM fatxxfs_dent_parse_buf(FATFS_INFO *fatfs, TSK_FS_DIR *a_fs_dir, char *buf, TSK_OFF_T len, TSK_DADDR_T *addrs) { char *func_name = "fatxxfs_dent_parse_buf"; unsigned int idx = 0; unsigned int sidx = 0; int a = 0; int b = 0; TSK_INUM_T ibase = 0; FATXXFS_DENTRY *dep = NULL; TSK_FS_INFO *fs = (TSK_FS_INFO*)&fatfs->fs_info; int sectalloc = 0; TSK_FS_NAME *fs_name = NULL; FATXXFS_LFN lfninfo; int entrySeenCount = 0; int entryInvalidCount = 0; uint8_t isCorruptDir = 0; tsk_error_reset(); if (fatfs_ptr_arg_is_null(fatfs, "fatfs", func_name) || fatfs_ptr_arg_is_null(a_fs_dir, "a_fs_dir", func_name) || fatfs_ptr_arg_is_null(buf, "buf", func_name) || fatfs_ptr_arg_is_null(addrs, "addrs", func_name)) { return TSK_ERR; } assert(len > 0); if (len < 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("%s: invalid buffer length", func_name); return TSK_ERR; } dep = (FATXXFS_DENTRY*)buf; if ((fs_name = tsk_fs_name_alloc(FATFS_MAXNAMLEN_UTF8, 32)) == NULL) { return TSK_ERR; } memset(&lfninfo, 0, sizeof(FATXXFS_LFN)); lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; /* Loop through the sectors in the buffer. */ for (sidx = 0; sidx < (unsigned int) (len / fatfs->ssize); sidx++) { /* Get the base inode for the current sector */ ibase = FATFS_SECT_2_INODE(fatfs, addrs[sidx]); if (ibase > fs->last_inum) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr ("fatfs_parse: inode address is too large"); tsk_fs_name_free(fs_name); return TSK_COR; } if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Parsing sector %" PRIuDADDR " for dir %" PRIuINUM "\n", addrs[sidx], a_fs_dir->addr); /* Get the allocation status of the current sector. */ if ((sectalloc = fatfs_is_sectalloc(fatfs, addrs[sidx])) == -1) { if (tsk_verbose) { tsk_fprintf(stderr, "fatfs_dent_parse_buf: Error looking up sector allocation: %" PRIuDADDR "\n", addrs[sidx]); tsk_error_print(stderr); } tsk_error_reset(); continue; } /* Loop through the putative directory entries in the current sector. */ for (idx = 0; idx < fatfs->dentry_cnt_se; idx++, dep++) { FATXXFS_DENTRY *dir; TSK_INUM_T inode; entrySeenCount++; /* Is the current entry a valid entry? */ if (0 == fatxxfs_is_dentry(fatfs, (FATFS_DENTRY*)dep, (FATFS_DATA_UNIT_ALLOC_STATUS_ENUM)sectalloc, ((isCorruptDir == 0) && (sectalloc)) ? 1 : 0)) { if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Entry %u is invalid\n", idx); entryInvalidCount++; /* If we have seen four entries and all of them are corrupt, * then test every remaining entry in this folder -- * even if the sector is allocated. The scenario is one * where we are processing a cluster that is allocated * to a file and we happen to get some data that matches * every now and then. */ if ((entrySeenCount == 4) && (entryInvalidCount == 4)) { isCorruptDir = 1; } continue; } dir = dep; /* Compute the inode address corresponding to this directory entry. */ inode = ibase + idx; if ((dir->attrib & FATFS_ATTR_LFN) == FATFS_ATTR_LFN) { /* The current entry is a long file name entry. */ FATXXFS_DENTRY_LFN *dirl = (FATXXFS_DENTRY_LFN *) dir; /* Store the name in dinfo until we get the 8.3 name * Use the checksum to identify a new sequence. */ if (((dirl->seq & FATXXFS_LFN_SEQ_FIRST) && (dirl->seq != FATXXFS_SLOT_DELETED)) || (dirl->chksum != lfninfo.chk)) { // @@@ Do a partial output here /* This is the last long file name entry in a sequence. * Reset the sequence number, check sum, and next char * address. */ lfninfo.seq = dirl->seq & FATXXFS_LFN_SEQ_MASK; lfninfo.chk = dirl->chksum; lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; } else if (dirl->seq != lfninfo.seq - 1) { // @@@ Check the sequence number - the checksum is correct though... } /* Copy the UTF16 values starting at end of buffer */ for (a = 3; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part3[a]; } for (a = 11; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part2[a]; } for (a = 9; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part1[a]; } // Skip ahead until we get a new sequence num or the 8.3 name continue; } else if ((dir->attrib & FATFS_ATTR_VOLUME) == FATFS_ATTR_VOLUME) { /* Special case for volume label: name does not have an * extension and we add a note at the end that it is a label */ a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] >= 0x20) && (dir->name[b] != 0xff)) { fs_name->name[a++] = dir->name[b]; } else { fs_name->name[a++] = '^'; } } for (b = 0; b < 3; b++) { if ((dir->ext[b] >= 0x20) && (dir->ext[b] != 0xff)) { fs_name->name[a++] = dir->ext[b]; } else { fs_name->name[a++] = '^'; } } fs_name->name[a] = '\0'; /* Append a string to show it is a label */ if (a + 22 < FATFS_MAXNAMLEN_UTF8) { const char *volstr = " (Volume Label Entry)"; strncat(fs_name->name, volstr, FATFS_MAXNAMLEN_UTF8 - a); } } else { /* A short (8.3) entry */ char *name_ptr; // The dest location for the short name /* if we have a lfn, copy it into fs_name->name * and put the short name in fs_name->shrt_name */ if (lfninfo.start != FATFS_MAXNAMLEN_UTF8 - 1) { int retVal; /* @@@ Check the checksum */ /* Convert the UTF16 to UTF8 */ UTF16 *name16 = (UTF16 *) ((uintptr_t) & lfninfo. name[lfninfo.start + 1]); UTF8 *name8 = (UTF8 *) fs_name->name; retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16, (UTF16 *) & lfninfo.name[FATFS_MAXNAMLEN_UTF8], &name8, (UTF8 *) ((uintptr_t) name8 + FATFS_MAXNAMLEN_UTF8), TSKlenientConversion); if (retVal != TSKconversionOK) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_UNICODE); tsk_error_set_errstr ("fatfs_parse: Error converting FAT LFN to UTF8: %d", retVal); continue; } /* Make sure it is NULL Terminated */ if ((uintptr_t) name8 > (uintptr_t) fs_name->name + FATFS_MAXNAMLEN_UTF8) fs_name->name[FATFS_MAXNAMLEN_UTF8 - 1] = '\0'; else *name8 = '\0'; lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; name_ptr = fs_name->shrt_name; // put 8.3 into shrt_name } /* We don't have a LFN, so put the short name in * fs_name->name */ else { fs_name->shrt_name[0] = '\0'; name_ptr = fs_name->name; // put 8.3 into normal location } /* copy in the short name into the place specified above. * Skip spaces and put in the . */ a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] != 0) && (dir->name[b] != 0xff) && (dir->name[b] != 0x20)) { if ((b == 0) && (dir->name[0] == FATXXFS_SLOT_DELETED)) { name_ptr[a++] = '_'; } else if ((dir->lowercase & FATXXFS_CASE_LOWER_BASE) && (dir->name[b] >= 'A') && (dir->name[b] <= 'Z')) { name_ptr[a++] = dir->name[b] + 32; } else { name_ptr[a++] = dir->name[b]; } } } for (b = 0; b < 3; b++) { if ((dir->ext[b] != 0) && (dir->ext[b] != 0xff) && (dir->ext[b] != 0x20)) { if (b == 0) name_ptr[a++] = '.'; if ((dir->lowercase & FATXXFS_CASE_LOWER_EXT) && (dir->ext[b] >= 'A') && (dir->ext[b] <= 'Z')) name_ptr[a++] = dir->ext[b] + 32; else name_ptr[a++] = dir->ext[b]; } } name_ptr[a] = '\0'; // make sure that only ASCII is in the short name fatfs_cleanup_ascii(name_ptr); } /* file type: FAT only knows DIR and FILE */ if ((dir->attrib & FATFS_ATTR_DIRECTORY) == FATFS_ATTR_DIRECTORY) fs_name->type = TSK_FS_NAME_TYPE_DIR; else fs_name->type = TSK_FS_NAME_TYPE_REG; /* set the inode */ fs_name->meta_addr = inode; inode = 0; // so that we don't use it anymore -- use only fs_name->meta_addr /* Handle the . and .. entries specially * The current inode 'address' they have is for the current * slot in the cluster, but it needs to refer to the original * slot */ if (TSK_FS_ISDOT(fs_name->name) && (fs_name->type == TSK_FS_NAME_TYPE_DIR) && idx < 2) { if (fs_name->name[1] == '\0') { /* Current directory - "." */ fs_name->meta_addr = a_fs_dir->fs_file->meta->addr; } /* for the parent directory, look up in the list that * is maintained in fafs_info */ else if (fs_name->name[1] == '.') { /* Parent directory - ".." */ uint8_t dir_found = 0; if (fatfs_dir_buf_get(fatfs, a_fs_dir->fs_file->meta->addr, &(fs_name->meta_addr)) == 0) { dir_found = 1; } if ((dir_found == 0) && (addrs[0] == fatfs->firstdatasect)) { /* if we are currently in the root directory, we aren't going to find * a parent. This shouldn't happen, but could result in an infinite loop. */ fs_name->meta_addr = 0; dir_found = 1; } if (dir_found == 0) { if (tsk_verbose) fprintf(stderr, "fatfs_dent_parse_buf: Walking directory to find parent\n"); /* The parent directory is not in the list. We are going to walk * the directory until we hit this directory. This process will * populate the buffer table and we will then rescan it */ if (tsk_fs_dir_walk(fs, fs->root_inum, (TSK_FS_DIR_WALK_FLAG_ENUM)(TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE), fatfs_find_parent_act, (void *) &a_fs_dir->fs_file->meta->addr)) { return TSK_OK; } if (tsk_verbose) fprintf(stderr, "fatfs_dent_parse_buf: Finished walking directory to find parent\n"); if (fatfs_dir_buf_get(fatfs, a_fs_dir->fs_file->meta->addr, &(fs_name->meta_addr)) == 0) { dir_found = 1; } // if we did not find it, then it was probably // from the orphan directory... if (dir_found == 0) fs_name->meta_addr = TSK_FS_ORPHANDIR_INUM(fs); } } } else { /* Save the (non-. or ..) directory to parent directory info to local * structures so that we can later fill into the inode * info for '..' entries */ if (fs_name->type == TSK_FS_NAME_TYPE_DIR) { if (fatfs_dir_buf_add(fatfs, a_fs_dir->fs_file->meta->addr, fs_name->meta_addr)) return TSK_ERR; } } /* The allocation status of an entry is based on the allocation * status of the sector it is in and the flag. Deleted directories * do not always clear the flags of each entry */ if (sectalloc == 1) { if(FATXXFS_IS_DELETED(dep->name, fatfs)){ fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } else{ fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; } } else { fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } tsk_fs_dir_add(a_fs_dir, fs_name); } } tsk_fs_name_free(fs_name); return TSK_OK; }
/* * Process the contents of a directory and add them to FS_DIR. * * @param fatfs File system information structure * @param a_fs_dir Structure to store the files in. * @param list_seen List of directory inodes that have been seen thus far in * directory walking (can be a pointer to a NULL pointer on first call). * @param buf Buffer that contains the directory contents. * @param len Length of buffer in bytes (must be a multiple of sector size) * @param addrs Array where each element is the original address of the * corresponding block in buf (size of array is number of blocks in directory). * * @return -1 on error, 0 on success, and 1 to stop */ static TSK_RETVAL_ENUM fatfs_dent_parse_buf(FATFS_INFO * fatfs, TSK_FS_DIR * a_fs_dir, char *buf, TSK_OFF_T len, TSK_DADDR_T * addrs) { unsigned int idx, sidx; int a, b; TSK_INUM_T inode, ibase; fatfs_dentry *dep; TSK_FS_INFO *fs = (TSK_FS_INFO *) & fatfs->fs_info; int sectalloc; TSK_FS_NAME *fs_name; FATFS_LFN lfninfo; if (buf == NULL) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "fatfs_dent_parse_buf: buffer is NULL"); return TSK_ERR; } dep = (fatfs_dentry *) buf; if ((fs_name = tsk_fs_name_alloc(FATFS_MAXNAMLEN_UTF8, 32)) == NULL) { return TSK_ERR; } memset(&lfninfo, 0, sizeof(FATFS_LFN)); lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; for (sidx = 0; sidx < (unsigned int) (len / fatfs->ssize); sidx++) { /* Get the base inode for this sector */ ibase = FATFS_SECT_2_INODE(fatfs, addrs[sidx]); if (ibase > fs->last_inum) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "fatfs_parse: inode address is too large"); tsk_fs_name_free(fs_name); return TSK_COR; } if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Parsing sector %" PRIuDADDR "\n", addrs[sidx]); if ((sectalloc = fatfs_is_sectalloc(fatfs, addrs[sidx])) == -1) { if (tsk_verbose) { tsk_fprintf(stderr, "fatfs_dent_parse_buf: Error looking up sector allocation: %" PRIuDADDR "\n", addrs[sidx]); tsk_error_print(stderr); } tsk_error_reset(); continue; } /* cycle through the directory entries */ for (idx = 0; idx < fatfs->dentry_cnt_se; idx++, dep++) { fatfs_dentry *dir; int i; /* is it a valid dentry? */ if (0 == fatfs_isdentry(fatfs, dep)) { if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Entry %u is invalid\n", idx); continue; } /* Copy the directory entry into the TSK_FS_NAME structure */ dir = (fatfs_dentry *) dep; inode = ibase + idx; /* Take care of the name * Copy a long name to a buffer and take action if it * is a small name */ if ((dir->attrib & FATFS_ATTR_LFN) == FATFS_ATTR_LFN) { fatfs_dentry_lfn *dirl = (fatfs_dentry_lfn *) dir; /* Store the name in dinfo until we get the 8.3 name * Use the checksum to identify a new sequence * */ if (((dirl->seq & FATFS_LFN_SEQ_FIRST) && (dirl->seq != FATFS_SLOT_DELETED)) || (dirl->chksum != lfninfo.chk)) { // @@@ Do a partial output here /* Reset the values */ lfninfo.seq = dirl->seq & FATFS_LFN_SEQ_MASK; lfninfo.chk = dirl->chksum; lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; } else if (dirl->seq != lfninfo.seq - 1) { // @@@ Check the sequence number - the checksum is correct though... } /* Copy the UTF16 values starting at end of buffer */ for (a = 3; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part3[a]; } for (a = 11; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part2[a]; } for (a = 9; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part1[a]; } // Skip ahead until we get a new sequence num or the 8.3 name continue; } /* Special case for volume label: name does not have an * extension and we add a note at the end that it is a label */ else if ((dir->attrib & FATFS_ATTR_VOLUME) == FATFS_ATTR_VOLUME) { a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] >= 0x20) && (dir->name[b] != 0xff)) { fs_name->name[a++] = dir->name[b]; } else { fs_name->name[a++] = '^'; } } for (b = 0; b < 3; b++) { if ((dir->ext[b] >= 0x20) && (dir->ext[b] != 0xff)) { fs_name->name[a++] = dir->ext[b]; } else { fs_name->name[a++] = '^'; } } fs_name->name[a] = '\0'; /* Append a string to show it is a label */ if (a + 22 < FATFS_MAXNAMLEN_UTF8) { char *volstr = " (Volume Label Entry)"; strncat(fs_name->name, volstr, FATFS_MAXNAMLEN_UTF8 - a); } } /* A short (8.3) entry */ else { char *name_ptr; // The dest location for the short name /* if we have a lfn, copy it into fs_name->name * and put the short name in fs_name->shrt_name */ if (lfninfo.start != FATFS_MAXNAMLEN_UTF8 - 1) { int retVal; /* @@@ Check the checksum */ /* Convert the UTF16 to UTF8 */ UTF16 *name16 = (UTF16 *) ((uintptr_t) & lfninfo.name[lfninfo. start + 1]); UTF8 *name8 = (UTF8 *) fs_name->name; retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16, (UTF16 *) & lfninfo.name[FATFS_MAXNAMLEN_UTF8], &name8, (UTF8 *) ((uintptr_t) name8 + FATFS_MAXNAMLEN_UTF8), TSKlenientConversion); if (retVal != TSKconversionOK) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_UNICODE; snprintf(tsk_errstr, TSK_ERRSTR_L, "fatfs_parse: Error converting FAT LFN to UTF8: %d", retVal); continue; } /* Make sure it is NULL Terminated */ if ((uintptr_t) name8 > (uintptr_t) fs_name->name + FATFS_MAXNAMLEN_UTF8) fs_name->name[FATFS_MAXNAMLEN_UTF8 - 1] = '\0'; else *name8 = '\0'; /* Clean up name */ i = 0; while (fs_name->name[i] != '\0') { if (TSK_IS_CNTRL(fs_name->name[i])) fs_name->name[i] = '^'; i++; } lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; name_ptr = fs_name->shrt_name; // put 8.3 into shrt_name } /* We don't have a LFN, so put the short name in * fs_name->name */ else { fs_name->shrt_name[0] = '\0'; name_ptr = fs_name->name; // put 8.3 into normal location } /* copy in the short name into the place specified above. * Skip spaces and put in the . */ a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] != 0) && (dir->name[b] != 0xff) && (dir->name[b] != 0x20)) { if ((b == 0) && (dir->name[0] == FATFS_SLOT_DELETED)) { name_ptr[a++] = '_'; } else if ((dir->lowercase & FATFS_CASE_LOWER_BASE) && (dir->name[b] >= 'A') && (dir->name[b] <= 'Z')) { name_ptr[a++] = dir->name[b] + 32; } else { name_ptr[a++] = dir->name[b]; } } } for (b = 0; b < 3; b++) { if ((dir->ext[b] != 0) && (dir->ext[b] != 0xff) && (dir->ext[b] != 0x20)) { if (b == 0) name_ptr[a++] = '.'; if ((dir->lowercase & FATFS_CASE_LOWER_EXT) && (dir->ext[b] >= 'A') && (dir->ext[b] <= 'Z')) name_ptr[a++] = dir->ext[b] + 32; else name_ptr[a++] = dir->ext[b]; } } name_ptr[a] = '\0'; } /* Clean up name to remove control chars */ i = 0; while (fs_name->name[i] != '\0') { if (TSK_IS_CNTRL(fs_name->name[i])) fs_name->name[i] = '^'; i++; } /* file type: FAT only knows DIR and FILE */ if ((dir->attrib & FATFS_ATTR_DIRECTORY) == FATFS_ATTR_DIRECTORY) fs_name->type = TSK_FS_NAME_TYPE_DIR; else fs_name->type = TSK_FS_NAME_TYPE_REG; /* Get inode */ fs_name->meta_addr = inode; /* Handle the . and .. entries specially * The current inode 'address' they have is for the current * slot in the cluster, but it needs to refer to the original * slot */ if (TSK_FS_ISDOT(fs_name->name)) { if (fs_name->name[1] == '\0') { inode = fs_name->meta_addr = a_fs_dir->fs_file->meta->addr; } /* for the parent directory, look up in the list that * is maintained in fafs_info */ else if (fs_name->name[1] == '.') { size_t q; uint8_t dir_found = 0; for (q = 0; q < fatfs->dir_buf_next; q++) { if (fatfs->dir_buf[q] == a_fs_dir->fs_file->meta->addr) { inode = fs_name->meta_addr = fatfs->par_buf[q]; dir_found = 1; break; } } if ((dir_found == 0) && (fs->isOrphanHunting)) { /* if we are currently scanning the fs to determine the orphan files, * then we do not care about the value of '..' and this can only cause * infinite loop problems */ inode = fs_name->meta_addr = 0; dir_found = 1; } if ((dir_found == 0) && (addrs[0] == fatfs->firstdatasect)) { /* if we are currently in the root directory, we aren't going to find * a parent. This shouldn't happen, but could result in an infinite loop. */ inode = fs_name->meta_addr = 0; dir_found = 1; } if (dir_found == 0) { /* The parent directory is not in the list. We are going to walk * the directory until we hit this directory. This process will * populate the buffer table and we will then rescan it */ if (tsk_fs_dir_walk(fs, fs->root_inum, TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE, find_parent_act, (void *) &a_fs_dir->fs_file->meta->addr)) { return 0; } for (q = 0; q < fatfs->dir_buf_next; q++) { if (fatfs->dir_buf[q] == a_fs_dir->fs_file->meta->addr) { inode = fs_name->meta_addr = fatfs->par_buf[q]; dir_found = 1; break; } } // if we did not find it, then it was probably // from the orphan directory... if (dir_found == 0) inode = fs_name->meta_addr = TSK_FS_ORPHANDIR_INUM(fs); } } } else { /* Save the (non-. or ..) directory to parent directory info to local * structures so that we can later fill into the inode * info for '..' entries */ if (fs_name->type == TSK_FS_NAME_TYPE_DIR) { if (fatfs_dir_buf_add(fatfs, a_fs_dir->fs_file->meta->addr, inode)) return TSK_ERR; } } /* The allocation status of an entry is based on the allocation * status of the sector it is in and the flag. Deleted directories * do not always clear the flags of each entry */ if (sectalloc == 1) { fs_name->flags = (dep->name[0] == FATFS_SLOT_DELETED) ? TSK_FS_NAME_FLAG_UNALLOC : TSK_FS_NAME_FLAG_ALLOC; } else { fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } tsk_fs_dir_add(a_fs_dir, fs_name); } } tsk_fs_name_free(fs_name); return TSK_OK; }