/** * \internal * Prints file system category data for an exFAT file system to a file * handle. * * @param [in] a_fs Generic file system info structure for the file system. * @param [in] a_hFile The file handle. * @return 0 on success, 1 otherwise, per TSK convention. */ static uint8_t exfatfs_fsstat_fs_info(TSK_FS_INFO *a_fs, FILE *a_hFile) { FATFS_INFO *fatfs = NULL; EXFATFS_MASTER_BOOT_REC *exfatbs = NULL; TSK_FS_FILE *fs_file = NULL; assert(a_fs != NULL); assert(a_hFile != NULL); fatfs = (FATFS_INFO*)a_fs; exfatbs = (EXFATFS_MASTER_BOOT_REC*)&(fatfs->boot_sector_buffer); if ((fs_file = tsk_fs_file_alloc(a_fs)) == NULL) { return FATFS_FAIL; } if ((fs_file->meta = tsk_fs_meta_alloc(FATFS_FILE_CONTENT_LEN)) == NULL) { return FATFS_FAIL; } tsk_fprintf(a_hFile, "FILE SYSTEM INFORMATION\n"); tsk_fprintf(a_hFile, "--------------------------------------------\n"); tsk_fprintf(a_hFile, "File System Type: exFAT\n"); tsk_fprintf(a_hFile, "\nVolume Serial Number: %x%x-%x%x\n", exfatbs->vol_serial_no[3], exfatbs->vol_serial_no[2], exfatbs->vol_serial_no[1], exfatbs->vol_serial_no[0]); if (exfatfs_find_volume_label_dentry(fatfs, fs_file) == 0) { tsk_fprintf(a_hFile, "Volume Label (from root directory): %s\n", fs_file->meta->name2->name); } else { tsk_fprintf(a_hFile, "Volume Label:\n"); } tsk_fprintf(a_hFile, "File System Name (from MBR): %s\n", exfatbs->fs_name); tsk_fprintf(a_hFile, "File System Revision: %x.%x\n", exfatbs->fs_revision[1], exfatbs->fs_revision[0]); tsk_fprintf(a_hFile, "Partition Offset: %" PRIuDADDR "\n", tsk_getu64(a_fs->endian, exfatbs->partition_offset)); tsk_fprintf(a_hFile, "Number of FATs: %d\n", fatfs->numfat); tsk_fs_file_close(fs_file); return FATFS_OK; }
/** \internal * Adds the fake metadata entry in the FS_DIR->fs_file struct for the orphan files directory * * @returns 1 on error */ static uint8_t tsk_fs_dir_add_orphan_dir_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR * a_fs_dir) { // populate the fake FS_FILE structure for the "Orphan Directory" if ((a_fs_dir->fs_file = tsk_fs_file_alloc(a_fs)) == NULL) { return 1; } if ((a_fs_dir->fs_file->meta = tsk_fs_meta_alloc(sizeof(TSK_DADDR_T))) == NULL) { return 1; } if (tsk_fs_dir_make_orphan_dir_meta(a_fs, a_fs_dir->fs_file->meta)) { return 1; } return 0; }
/** * \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; }