From e5536656fe725dd46c0e6ddbd44fc3977cb7acaa Mon Sep 17 00:00:00 2001 From: Brian Carrier <carrier@sleuthkit.org> Date: Mon, 12 Jan 2009 04:41:06 +0000 Subject: [PATCH] HFS Wrapper Support Added --- CHANGES.txt | 2 + tsk3/fs/hfs.c | 177 ++++++++++++++++++++++++++++++++-------------- tsk3/fs/tsk_fs.h | 4 +- tsk3/fs/tsk_hfs.h | 39 +++++++++- 4 files changed, 165 insertions(+), 57 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 48697cd17..af19365a5 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -22,6 +22,8 @@ Rob Joyce and Judson Powers. directory have an unknown file name type (instead of being equal to meta type). (Bug: 2389901). Reported by Barry Grundy. +1/11/09: Update: Support for HFS Wrappers was added. Patch by Rob Joyce. + ---------------- VERSION 3.0.0 -------------- 0/00/00: Update: Many, many, many API changes. diff --git a/tsk3/fs/hfs.c b/tsk3/fs/hfs.c index ed7486600..fe18b22a8 100644 --- a/tsk3/fs/hfs.c +++ b/tsk3/fs/hfs.c @@ -938,7 +938,7 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_ext_find_extent_record_attr: Error reading header"); + "hfs_ext_find_extent_record_attr: Error reading header"); return 0; } } @@ -985,7 +985,8 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_ext_find_extent_record_attr: Error reading node %d at offset %"PRIuOFF, cur_node, cur_off); + "hfs_ext_find_extent_record_attr: Error reading node %d at offset %" + PRIuOFF, cur_node, cur_off); free(node); return 1; } @@ -1026,8 +1027,8 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, if (rec_off > nodesize) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_ext_find_extent_record_attr: offset of record %d in index node %d too large (%zu vs %"PRIu16")", - rec, cur_node, rec_off, nodesize); + "hfs_ext_find_extent_record_attr: offset of record %d in index node %d too large (%zu vs %" + PRIu16 ")", rec, cur_node, rec_off, nodesize); free(node); return 1; } @@ -1048,11 +1049,12 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, /* if all keys are larger than our key, select the leftmost key */ if ((cmp <= 0) || (next_node == 0)) { int keylen = tsk_getu16(fs->endian, key->key_len); - if (rec_off+keylen > nodesize) { + if (rec_off + keylen > nodesize) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_ext_find_extent_record_attr: offset and keylenth of record %d in index node %d too large (%zu vs %"PRIu16")", - rec, cur_node, rec_off+keylen, nodesize); + "hfs_ext_find_extent_record_attr: offset and keylenth of record %d in index node %d too large (%zu vs %" + PRIu16 ")", rec, cur_node, rec_off + keylen, + nodesize); free(node); return 1; } @@ -1063,13 +1065,13 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, break; } } - + // check if we found any relevant node if (next_node == 0) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_ext_find_extent_record_attr: did not find any keys for %d in index node %d", - cnid, cur_node); + "hfs_ext_find_extent_record_attr: did not find any keys for %d in index node %d", + cnid, cur_node); free(node); return 1; } @@ -1094,8 +1096,8 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, if (rec_off > nodesize) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_ext_find_extent_record_attr: offset of record %d in leaf node %d too large (%zu vs %"PRIu16")", - rec, cur_node, rec_off, nodesize); + "hfs_ext_find_extent_record_attr: offset of record %d in leaf node %d too large (%zu vs %" + PRIu16 ")", rec, cur_node, rec_off, nodesize); free(node); return 1; } @@ -1120,33 +1122,36 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, break; keylen = tsk_getu16(fs->endian, key->key_len); - if (rec_off+keylen > nodesize) { + if (rec_off + keylen > nodesize) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_ext_find_extent_record_attr: offset and keylenth of record %d in leaf node %d too large (%zu vs %"PRIu16")", - rec, cur_node, rec_off+keylen, nodesize); + "hfs_ext_find_extent_record_attr: offset and keylenth of record %d in leaf node %d too large (%zu vs %" + PRIu16 ")", rec, cur_node, rec_off + keylen, + nodesize); free(node); return 1; } // get the starting offset of this extent ext_off = tsk_getu32(fs->endian, key->start_block); - + // convert the extents to the TSK format extents = (hfs_extents *) & node[rec_off + keylen]; - + attr_run = hfs_extents_to_attr(fs, extents->extents, ext_off); if (attr_run == NULL) { - strncat(tsk_errstr2, " - hfs_ext_find_extent_record_attr", - TSK_ERRSTR_L - strlen(tsk_errstr2)); + strncat(tsk_errstr2, + " - hfs_ext_find_extent_record_attr", + TSK_ERRSTR_L - strlen(tsk_errstr2)); free(node); return 1; } if (tsk_fs_attr_add_run(fs, a_attr, attr_run)) { - strncat(tsk_errstr2, " - hfs_ext_find_extent_record_attr", - TSK_ERRSTR_L - strlen(tsk_errstr2)); + strncat(tsk_errstr2, + " - hfs_ext_find_extent_record_attr", + TSK_ERRSTR_L - strlen(tsk_errstr2)); free(node); return 1; } @@ -1255,7 +1260,8 @@ hfs_cat_get_record_offset(HFS_INFO * hfs, hfs_cat_key * needle) tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_cat_get_record_offset: Error reading node %d at offset %"PRIuOFF, cur_node, cur_off); + "hfs_cat_get_record_offset: Error reading node %d at offset %" + PRIuOFF, cur_node, cur_off); free(node); return 0; } @@ -1294,8 +1300,8 @@ hfs_cat_get_record_offset(HFS_INFO * hfs, hfs_cat_key * needle) if (rec_off > nodesize) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_cat_get_record_offset: offset of record %d in index node %d too large (%zu vs %"PRIu16")", - rec, cur_node, rec_off, nodesize); + "hfs_cat_get_record_offset: offset of record %d in index node %d too large (%zu vs %" + PRIu16 ")", rec, cur_node, rec_off, nodesize); free(node); return 1; } @@ -1316,8 +1322,9 @@ hfs_cat_get_record_offset(HFS_INFO * hfs, hfs_cat_key * needle) if (rec_off + keylen > nodesize) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_cat_get_record_offset: offset of record and keylength %d in index node %d too large (%zu vs %"PRIu16")", - rec, cur_node, rec_off+keylen, nodesize); + "hfs_cat_get_record_offset: offset of record and keylength %d in index node %d too large (%zu vs %" + PRIu16 ")", rec, cur_node, rec_off + keylen, + nodesize); free(node); return 0; } @@ -1332,8 +1339,8 @@ hfs_cat_get_record_offset(HFS_INFO * hfs, hfs_cat_key * needle) if (next_node == 0) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_cat_get_record_offset: did not find any keys in index node %d", - cur_node); + "hfs_cat_get_record_offset: did not find any keys in index node %d", + cur_node); is_done = 1; break; } @@ -1356,8 +1363,8 @@ hfs_cat_get_record_offset(HFS_INFO * hfs, hfs_cat_key * needle) if (rec_off > nodesize) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_cat_get_record_offset: offset of record %d in leaf node %d too large (%zu vs %"PRIu16")", - rec, cur_node, rec_off, nodesize); + "hfs_cat_get_record_offset: offset of record %d in leaf node %d too large (%zu vs %" + PRIu16 ")", rec, cur_node, rec_off, nodesize); free(node); return 0; } @@ -1388,8 +1395,8 @@ hfs_cat_get_record_offset(HFS_INFO * hfs, hfs_cat_key * needle) if (rec_off2 > nodesize) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_cat_get_record_offset: offset of record and keylength %d in leaf node %d too large (%zu vs %"PRIu16")", - rec, cur_node, rec_off2, nodesize); + "hfs_cat_get_record_offset: offset of record and keylength %d in leaf node %d too large (%zu vs %" + PRIu16 ")", rec, cur_node, rec_off2, nodesize); free(node); return 0; } @@ -1438,7 +1445,8 @@ hfs_cat_read_thread_record(HFS_INFO * hfs, TSK_OFF_T off, tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_cat_read_thread_record: Error reading catalog offset %"PRIuOFF" (header)", off); + "hfs_cat_read_thread_record: Error reading catalog offset %" + PRIuOFF " (header)", off); return 1; } @@ -1471,7 +1479,8 @@ hfs_cat_read_thread_record(HFS_INFO * hfs, TSK_OFF_T off, tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_cat_read_thread_record: Error reading catalog offset %"PRIuOFF" (name)", off+10); + "hfs_cat_read_thread_record: Error reading catalog offset %" + PRIuOFF " (name)", off + 10); return 1; } @@ -1501,7 +1510,8 @@ hfs_cat_read_file_folder_record(HFS_INFO * hfs, TSK_OFF_T off, tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_cat_read_file_folder_record: Error reading catalog offset %"PRIuOFF" (header)", off); + "hfs_cat_read_file_folder_record: Error reading catalog offset %" + PRIuOFF " (header)", off); return 1; } @@ -1515,7 +1525,8 @@ hfs_cat_read_file_folder_record(HFS_INFO * hfs, TSK_OFF_T off, tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_cat_read_file_folder_record: Error reading catalog offset %"PRIuOFF" (folder)", off); + "hfs_cat_read_file_folder_record: Error reading catalog offset %" + PRIuOFF " (folder)", off); return 1; } } @@ -1530,7 +1541,8 @@ hfs_cat_read_file_folder_record(HFS_INFO * hfs, TSK_OFF_T off, tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_cat_read_file_folder_record: Error reading catalog offset %"PRIuOFF" (file)", off); + "hfs_cat_read_file_folder_record: Error reading catalog offset %" + PRIuOFF " (file)", off); return 1; } } @@ -1579,7 +1591,8 @@ hfs_cat_file_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry) (inum == HFS_ATTRIBUTES_FILE_ID)) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_cat_file_lookup: Called on special file: %"PRIuINUM, inum); + "hfs_cat_file_lookup: Called on special file: %" PRIuINUM, + inum); return 1; } @@ -1592,13 +1605,15 @@ hfs_cat_file_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry) /* look up the thread record */ off = hfs_cat_get_record_offset(hfs, &key); if (off == 0) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, " hfs_cat_file_lookup: thread for file (%"PRIuINUM")", inum); + snprintf(tsk_errstr2, TSK_ERRSTR_L, + " hfs_cat_file_lookup: thread for file (%" PRIuINUM ")", inum); return 1; } /* read the thread record */ if (hfs_cat_read_thread_record(hfs, off, &thread)) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, " hfs_cat_file_lookup: file (%"PRIuINUM")", inum); + snprintf(tsk_errstr2, TSK_ERRSTR_L, + " hfs_cat_file_lookup: file (%" PRIuINUM ")", inum); return 1; } @@ -1613,13 +1628,15 @@ hfs_cat_file_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry) /* look up the record */ off = hfs_cat_get_record_offset(hfs, &key); if (off == 0) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, " hfs_cat_file_lookup: file (%"PRIuINUM")", inum); + snprintf(tsk_errstr2, TSK_ERRSTR_L, + " hfs_cat_file_lookup: file (%" PRIuINUM ")", inum); return 1; } /* read the record */ if (hfs_cat_read_file_folder_record(hfs, off, &record)) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, " hfs_cat_file_lookup: file (%"PRIuINUM")", inum); + snprintf(tsk_errstr2, TSK_ERRSTR_L, + " hfs_cat_file_lookup: file (%" PRIuINUM ")", inum); return 1; } @@ -2337,14 +2354,14 @@ hfs_load_attrs(TSK_FS_FILE * fs_file) TSK_ERRSTR_L - strlen(tsk_errstr2)); return 1; } - + // if not a file, then make an empty entry if (fs_file->meta->type != TSK_FS_META_TYPE_REG) { if (tsk_fs_attr_set_run(fs_file, fs_attr, NULL, NULL, - TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT, - 0, 0, 0, 0)) { + TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT, + 0, 0, 0, 0)) { strncat(tsk_errstr2, " - hfs_load_attrs (non-file)", - TSK_ERRSTR_L - strlen(tsk_errstr2)); + TSK_ERRSTR_L - strlen(tsk_errstr2)); tsk_fs_attr_free(fs_attr); tsk_fs_attr_run_free(attr_run); return 1; @@ -2456,7 +2473,8 @@ hfs_block_is_alloc(HFS_INFO * hfs, TSK_DADDR_T a_addr) tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_block_is_alloc: Error reading block bitmap at offset %"PRIuOFF, b); + "hfs_block_is_alloc: Error reading block bitmap at offset %" + PRIuOFF, b); return -1; } hfs->blockmap_cache_start = b; @@ -2785,6 +2803,11 @@ hfs_fsstat(TSK_FS_INFO * fs, FILE * hFile) tsk_fprintf(hFile, " (unknown)\n"); break; } + if (hfs->hfs_wrapper_offset > 0) { + tsk_fprintf(hFile, + "File system is embedded in an HFS wrapper at offset %" PRIuOFF + "\n", hfs->hfs_wrapper_offset); + } tsk_fprintf(hFile, "Last mounted version: %" PRIx32, tsk_getu32(fs->endian, sb->last_mnt_ver)); @@ -3139,15 +3162,13 @@ hfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset, return NULL; } - /* * Verify we are looking at an HFS+ image */ if (tsk_fs_guessu16(fs, hfs->fs->signature, HFSPLUS_MAGIC) && - tsk_fs_guessu16(fs, hfs->fs->signature, HFSX_MAGIC)) { - if (!tsk_fs_guessu16(fs, hfs->fs->signature, HFS_MAGIC)) { - tsk_fprintf(stderr, "HFS volumes not supported\n"); - } + tsk_fs_guessu16(fs, hfs->fs->signature, HFSX_MAGIC) && + tsk_fs_guessu16(fs, hfs->fs->signature, HFS_MAGIC)) { + fs->tag = 0; free(hfs->fs); free(hfs); @@ -3157,6 +3178,54 @@ hfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset, return NULL; } + /* + * Handle an HFS-wrapped HFS+ image + */ + if (tsk_getu16(fs->endian, hfs->fs->signature) == HFS_MAGIC) { + + hfs_wrapper_sb *wrapper_sb = (hfs_wrapper_sb *) hfs->fs; + + if ((tsk_getu16(fs->endian, + wrapper_sb->drEmbedSigWord) == HFSPLUS_MAGIC) + || (tsk_getu16(fs->endian, + wrapper_sb->drEmbedSigWord) == HFSX_MAGIC)) { + + TSK_FS_INFO *fs_info2; + uint16_t drAlBlSt = + tsk_getu16(fs->endian, wrapper_sb->drAlBlSt); + uint32_t drAlBlkSiz = + tsk_getu32(fs->endian, wrapper_sb->drAlBlkSiz); + uint16_t startBlock = + tsk_getu16(fs->endian, + wrapper_sb->drEmbedExtent_startBlock); + TSK_OFF_T hfsplus_offset = + (drAlBlSt * (TSK_OFF_T) 512) + + (drAlBlkSiz * (TSK_OFF_T) startBlock); + if (tsk_verbose) + tsk_fprintf(stderr, + "hfs_open: HFS+/HFSX within HFS wrapper at byte offset %" + PRIuOFF "\n", hfsplus_offset); + + fs->tag = 0; + free(hfs->fs); + free(hfs); + + /* just re-open with the new offset, then record the offset */ + fs_info2 = + hfs_open(img_info, offset + hfsplus_offset, ftype, test); + ((HFS_INFO *) fs_info2)->hfs_wrapper_offset = hfsplus_offset; + return fs_info2; + } + + fs->tag = 0; + free(hfs->fs); + free(hfs); + tsk_errno = TSK_ERR_FS_MAGIC; + snprintf(tsk_errstr, TSK_ERRSTR_L, + "HFS file systems (other than wrappers HFS+/HFSX file systems) are not supported"); + return NULL; + } + fs->block_count = tsk_getu32(fs->endian, hfs->fs->blk_cnt); fs->first_block = 0; fs->last_block = fs->last_block_act = fs->block_count - 1; @@ -3239,7 +3308,7 @@ hfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset, tsk_errno = TSK_ERR_FS_READ; } snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_open: Error reading catalog header"); + "hfs_open: Error reading catalog header"); fs->tag = 0; free(hfs->fs); free(hfs); @@ -3269,7 +3338,7 @@ hfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset, // update the numbers. fs->last_inum = hfs_find_highest_inum(hfs); - fs->inum_count = fs->last_inum+1; + fs->inum_count = fs->last_inum + 1; snprintf((char *) fs->fs_id, 17, "%08" PRIx32 "%08" PRIx32, tsk_getu32(fs->endian, &(hfs->fs->finder_info[24])), diff --git a/tsk3/fs/tsk_fs.h b/tsk3/fs/tsk_fs.h index 36ba50a50..bf6e9eff9 100644 --- a/tsk3/fs/tsk_fs.h +++ b/tsk3/fs/tsk_fs.h @@ -698,11 +698,11 @@ extern "C" { TSK_FS_TYPE_SWAP = 0x00000200, ///< SWAP file system TSK_FS_TYPE_SWAP_DETECT = 0x00000200, ///< SWAP auto detection TSK_FS_TYPE_RAW = 0x00000400, ///< RAW file system - TSK_FS_TYPE_RAW_DETECT = 0x00000400, ///< Raw auto detection + TSK_FS_TYPE_RAW_DETECT = 0x00000400, ///< RAW auto detection TSK_FS_TYPE_ISO9660 = 0x00000800, ///< ISO9660 file system TSK_FS_TYPE_ISO9660_DETECT = 0x00000800, ///< ISO9660 auto detection TSK_FS_TYPE_HFS = 0x00001000, ///< HFS file system - TSK_FS_TYPE_HFS_DETECT = 0x00001000, ///< FAT auto detection + TSK_FS_TYPE_HFS_DETECT = 0x00001000, ///< HFS auto detection TSK_FS_TYPE_UNSUPP = 0xffffffff, ///< Unsupported file system }; typedef enum TSK_FS_TYPE_ENUM TSK_FS_TYPE_ENUM; diff --git a/tsk3/fs/tsk_hfs.h b/tsk3/fs/tsk_hfs.h index 336760fff..5852b5475 100644 --- a/tsk3/fs/tsk_hfs.h +++ b/tsk3/fs/tsk_hfs.h @@ -222,7 +222,7 @@ typedef struct { } hfs_fork; /* -** Super Block +** HFS+/HFSX Super Block */ typedef struct { uint8_t signature[2]; /* "H+" for HFS+, "HX" for HFSX */ @@ -253,6 +253,42 @@ typedef struct { hfs_fork start_file; /* location and size of startup file */ } hfs_sb; +/* +** HFS Super Block for wrapped HFS+/HFSX file systems +*/ +typedef struct { + uint8_t drSigWord[2]; /* "BD" for HFS (same location as hfs_sb.signature) */ + uint8_t drCrDate[4]; /* volume creation date */ + uint8_t drLsMod[4]; /* volume last modified date */ + uint8_t drAtrb[2]; /* volume attributes */ + uint8_t drNmFls[2]; /* number of files on volume */ + uint8_t drVBMSt[2]; /* starting block for volume bitmap */ + uint8_t drAllocPtr[2]; /* start of next allocation search */ + uint8_t drNmAlBlks[2]; /* number of blocks on disk */ + uint8_t drAlBlkSiz[4]; /* size in bytes of each allocation block */ + uint8_t drClpSiz[4]; /* default clump size for volume */ + uint8_t drAlBlSt[2]; /* first allocation block, in 512-byte sectors */ + uint8_t drNxtCNID[4]; /* next unused catalog node ID */ + uint8_t drFreeBlks[2]; /* number of unused allocation blocks */ + uint8_t drVN[28]; /* volume name, where first byte is length */ + uint8_t drVolBkUp[4]; /* volume last backup date */ + uint8_t drVSeqNum[2]; /* volume sequence number */ + uint8_t drWrCnt[4]; /* write count */ + uint8_t drXTClpSiz[4]; /* clump size for extents overflow file */ + uint8_t drCTClpSiz[4]; /* clump size for catalog file */ + uint8_t drNmRtDirs[2]; /* number of folders in root directory */ + uint8_t drFilCnt[4]; /* number of files on volume */ + uint8_t drDirCnt[4]; /* number of directories on volume */ + uint8_t drFndrInfo[32]; /* Finder info */ + uint8_t drEmbedSigWord[2]; /* signature of the embedded HFS+ volume (eg, "H+") */ + uint8_t drEmbedExtent_startBlock[2]; /* extent descriptor for start of embedded volume */ + uint8_t drEmbedExtent_blockCount[2]; /* extent descriptor for start of embedded volume */ + uint8_t drXTFlSize[4]; /* size of the extents overflow file */ + uint8_t drXTExtRec[12]; /* extent record with size and location of extents overflow file */ + uint8_t drCTFlSize[4]; /* size of the catalog file */ + uint8_t drCTExtRec[12]; /* extent record with size and location of catalog file */ +} hfs_wrapper_sb; + typedef struct { uint8_t key_len[2]; uint8_t parent_cnid[4]; @@ -398,6 +434,7 @@ typedef struct { const TSK_FS_ATTR *extents_attr; hfs_btree_header_record extents_header; + TSK_OFF_T hfs_wrapper_offset; /* byte offset of this FS within an HFS wrapper */ } HFS_INFO; typedef struct { -- GitLab