From 4171e1dd9fb5cb6dcfd646c3992863e9df5eca13 Mon Sep 17 00:00:00 2001 From: Brian Carrier <carrier@sleuthkit.org> Date: Mon, 12 Jan 2009 05:01:47 +0000 Subject: [PATCH] HFS fixes from Rob --- CHANGES.txt | 2 + tsk3/fs/hfs.c | 90 ++++++++++++++++++++++++++++++++------------- tsk3/fs/hfs_dent.c | 2 +- tsk3/fs/ifind_lib.c | 26 +++++++++++++ tsk3/fs/tsk_hfs.h | 13 ++++--- 5 files changed, 102 insertions(+), 31 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index af19365a5..7bacfc226 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -24,6 +24,8 @@ to meta type). (Bug: 2389901). Reported by Barry Grundy. 1/11/09: Update: Support for HFS Wrappers was added. Patch by Rob Joyce. +1/11/09: Update: Lots of bug fixes in HFS code from 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 fe18b22a8..e2e66ea02 100644 --- a/tsk3/fs/hfs.c +++ b/tsk3/fs/hfs.c @@ -2750,8 +2750,10 @@ print_inode_file(FILE * hFile, TSK_FS_INFO * fs, TSK_INUM_T inum) if (inum == HFS_ROOT_INUM) tsk_fprintf(hFile, "/"); else { - if (print_parent_path(hFile, fs, inum)) + if (print_parent_path(hFile, fs, inum)) { + tsk_fprintf(hFile, "unknown]"); return 1; + } } tsk_fprintf(hFile, "]"); return 0; @@ -2819,6 +2821,12 @@ hfs_fsstat(TSK_FS_INFO * fs, FILE * hFile) tsk_fprintf(hFile, " (Mac OS X, Journaled)\n"); else if (tsk_getu32(fs->endian, sb->last_mnt_ver) == FSK_MOUNT_VERSION) tsk_fprintf(hFile, " (failed journal replay)\n"); + else if (tsk_getu32(fs->endian, + sb->last_mnt_ver) == FSCK_MOUNT_VERSION) + tsk_fprintf(hFile, " (fsck_hfs)\n"); + else if (tsk_getu32(fs->endian, + sb->last_mnt_ver) == OS89_MOUNT_VERSION) + tsk_fprintf(hFile, " (Mac OS 8.1 - 9.2.2)\n"); else tsk_fprintf(hFile, "\n"); @@ -2847,8 +2855,8 @@ hfs_fsstat(TSK_FS_INFO * fs, FILE * hFile) /* State of the file system */ if ((tsk_getu32(fs->endian, hfs->fs->attr) & HFS_BIT_VOLUME_UNMOUNTED) - || ((tsk_getu32(fs->endian, - hfs->fs->attr) & HFS_BIT_VOLUME_INCONSISTENT) == 0)) + && (!(tsk_getu32(fs->endian, + hfs->fs->attr) & HFS_BIT_VOLUME_INCONSISTENT))) tsk_fprintf(hFile, "Volume Unmounted Properly\n"); else tsk_fprintf(hFile, "Volume Unmounted Improperly\n"); @@ -2856,6 +2864,10 @@ hfs_fsstat(TSK_FS_INFO * fs, FILE * hFile) if (tsk_getu32(fs->endian, hfs->fs->attr) & HFS_BIT_VOLUME_BADBLOCKS) tsk_fprintf(hFile, "Volume has bad blocks\n"); + if (tsk_getu32(fs->endian, + hfs->fs->attr) & HFS_BIT_VOLUME_SOFTWARE_LOCK) + tsk_fprintf(hFile, "Software write protect enabled\n"); + tsk_fprintf(hFile, "Write count: %" PRIu32 "\n", tsk_getu32(fs->endian, sb->write_cnt)); @@ -2876,39 +2888,34 @@ hfs_fsstat(TSK_FS_INFO * fs, FILE * hFile) inode = tsk_getu32(fs->endian, &(sb->finder_info[0])); tsk_fprintf(hFile, "Bootable Folder ID: %" PRIuINUM, inode); - if (inode > HFS_ROOT_INUM) - if (print_inode_file(hFile, fs, inode)) - return 1; + if (inode > 0) + print_inode_file(hFile, fs, inode); tsk_fprintf(hFile, "\n"); inode = tsk_getu32(fs->endian, &(sb->finder_info[4])); tsk_fprintf(hFile, "Startup App ID: %" PRIuINUM, inode); - if (inode > HFS_ROOT_INUM) - if (print_inode_file(hFile, fs, inode)) - return 1; + if (inode > 0) + print_inode_file(hFile, fs, inode); tsk_fprintf(hFile, "\n"); inode = tsk_getu32(fs->endian, &(sb->finder_info[8])); tsk_fprintf(hFile, "Startup Open Folder ID: %" PRIuINUM, inode); - if (inode > HFS_ROOT_INUM) - if (print_inode_file(hFile, fs, inode)) - return 1; + if (inode > 0) + print_inode_file(hFile, fs, inode); tsk_fprintf(hFile, "\n"); inode = tsk_getu32(fs->endian, &(sb->finder_info[12])); tsk_fprintf(hFile, "Mac OS 8/9 Blessed System Folder ID: %" PRIuINUM, inode); - if (inode > HFS_ROOT_INUM) - if (print_inode_file(hFile, fs, inode)) - return 1; + if (inode > 0) + print_inode_file(hFile, fs, inode); tsk_fprintf(hFile, "\n"); inode = tsk_getu32(fs->endian, &(sb->finder_info[20])); tsk_fprintf(hFile, "Mac OS X Blessed System Folder ID: %" PRIuINUM, inode); - if (inode > HFS_ROOT_INUM) - if (print_inode_file(hFile, fs, inode)) - return 1; + if (inode > 0) + print_inode_file(hFile, fs, inode); tsk_fprintf(hFile, "\n"); tsk_fprintf(hFile, "Volume Identifier: %08" PRIx32 "%08" PRIx32 "\n", @@ -2958,7 +2965,18 @@ print_addr_act(TSK_FS_FILE * fs_file, TSK_OFF_T a_off, TSK_DADDR_T addr, return TSK_WALK_CONT; } -uint8_t +/** + * Print details on a specific file to a file handle. + * + * @param fs File system file is located in + * @param hFile File name to print text to + * @param inum Address of file in file system + * @param numblock The number of blocks in file to force print (can go beyond file size) + * @param sec_skew Clock skew in seconds to also print times in + * + * @returns 1 on error and 0 on success + */ +static uint8_t hfs_istat(TSK_FS_INFO * fs, FILE * hFile, TSK_INUM_T inum, TSK_DADDR_T numblock, int32_t sec_skew) { @@ -2973,11 +2991,11 @@ hfs_istat(TSK_FS_INFO * fs, FILE * hFile, TSK_INUM_T inum, "hfs_istat: inum: %" PRIuINUM " numblock: %" PRIu32 "\n", inum, numblock); - - - - if ((fs_file = tsk_fs_file_open_meta(fs, NULL, inum)) == NULL) + if ((fs_file = tsk_fs_file_open_meta(fs, NULL, inum)) == NULL) { + strncat(tsk_errstr2, " - istat", + TSK_ERRSTR_L - strlen(tsk_errstr2)); return 1; + } tsk_fprintf(hFile, "\nINODE INFORMATION\n"); tsk_fprintf(hFile, "Entry:\t%" PRIuINUM "\n", inum); @@ -2993,6 +3011,29 @@ hfs_istat(TSK_FS_INFO * fs, FILE * hFile, TSK_INUM_T inum, tsk_fs_make_ls(fs_file->meta, hfs_mode); tsk_fprintf(hFile, "Mode:\t%s\n", hfs_mode); + if (sec_skew != 0) { + tsk_fprintf(hFile, "\nAdjusted times:\n"); + fs_file->meta->mtime -= sec_skew; + fs_file->meta->atime -= sec_skew; + fs_file->meta->ctime -= sec_skew; + fs_file->meta->crtime -= sec_skew; + fs_file->meta->time2.hfs.bkup_time -= sec_skew; + tsk_fprintf(hFile, "Created:\t%s", ctime(&fs_file->meta->crtime)); + tsk_fprintf(hFile, "Content Modified:\t%s", + ctime(&fs_file->meta->mtime)); + tsk_fprintf(hFile, "Attributes Modified:\t%s", + ctime(&fs_file->meta->ctime)); + tsk_fprintf(hFile, "Accessed:\t%s", ctime(&fs_file->meta->atime)); + tsk_fprintf(hFile, "Backed Up:\t%s", + ctime(&fs_file->meta->time2.hfs.bkup_time)); + fs_file->meta->mtime += sec_skew; + fs_file->meta->atime += sec_skew; + fs_file->meta->ctime += sec_skew; + fs_file->meta->crtime += sec_skew; + fs_file->meta->time2.hfs.bkup_time += sec_skew; + tsk_fprintf(hFile, "\nOriginal times:\n"); + } + tsk_fprintf(hFile, "Created:\t%s", ctime(&fs_file->meta->crtime)); tsk_fprintf(hFile, "Content Modified:\t%s", ctime(&fs_file->meta->mtime)); @@ -3195,8 +3236,7 @@ hfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset, tsk_getu16(fs->endian, wrapper_sb->drAlBlSt); uint32_t drAlBlkSiz = tsk_getu32(fs->endian, wrapper_sb->drAlBlkSiz); - uint16_t startBlock = - tsk_getu16(fs->endian, + uint16_t startBlock = tsk_getu16(fs->endian, wrapper_sb->drEmbedExtent_startBlock); TSK_OFF_T hfsplus_offset = (drAlBlSt * (TSK_OFF_T) 512) + diff --git a/tsk3/fs/hfs_dent.c b/tsk3/fs/hfs_dent.c index 9deea822c..ca8e2c3df 100644 --- a/tsk3/fs/hfs_dent.c +++ b/tsk3/fs/hfs_dent.c @@ -73,7 +73,7 @@ #define UTF16_NULL 0x0000 #define UTF16_NULL_REPLACE 0xfffd #define UTF16_SLASH 0x002f -#define UTF16_COLON 0x001a +#define UTF16_COLON 0x003a /* convert HFS+'s UTF16 to UTF8 * replaces null characters with another character (0xfffd) diff --git a/tsk3/fs/ifind_lib.c b/tsk3/fs/ifind_lib.c index b7932921c..e20307e42 100644 --- a/tsk3/fs/ifind_lib.c +++ b/tsk3/fs/ifind_lib.c @@ -26,6 +26,7 @@ */ #include "tsk_fs_i.h" +#include "tsk_hfs.h" /******************************************************************************* @@ -240,6 +241,8 @@ tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path, return -1; } + // @@@ It seems that we could abstract this and have a name comparison + // function for each file system that hides the case sensitive details... /* * Check if this is the name that we are currently looking for, * as identified in 'cur_dir' @@ -302,6 +305,29 @@ tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path, } } + /* HFS+ can be case-sensitive or case-insensitive */ + else if (TSK_FS_TYPE_ISHFS(a_fs->ftype)) { + HFS_INFO *hfs = (HFS_INFO *)a_fs; + if ( hfs->is_case_sensitive ) { + if (strcmp(fs_file->name->name, cur_dir) == 0) { + found_name = 1; + } + } else { + if (strcasecmp(fs_file->name->name, cur_dir) == 0) { + found_name = 1; + } + } + } + + /* Unknown how to compare names in this filesystem */ + else { + tsk_errno = TSK_ERR_FS_GENFS; + snprintf(tsk_errstr, TSK_ERRSTR_L, + "tsk_fs_path2inum: File System type not supported for file name comparison (%X)", + a_fs->ftype); + return TSK_WALK_ERROR; + } + /* if found_name is 1, this entry was our target. Update * data and move on to the next step, if needed. */ if (found_name) { diff --git a/tsk3/fs/tsk_hfs.h b/tsk3/fs/tsk_hfs.h index 5852b5475..bdf28db9a 100644 --- a/tsk3/fs/tsk_hfs.h +++ b/tsk3/fs/tsk_hfs.h @@ -80,16 +80,18 @@ * Constants */ -#define HFS_MAGIC 0x4244 /* BD in big endian */ +#define HFS_MAGIC 0x4244 /* BD in big endian */ #define HFSPLUS_MAGIC 0x482b /* H+ in big endian */ #define HFSX_MAGIC 0x4858 /* HX in big endian */ #define HFSPLUS_VERSION 0x0004 /* all HFS+ volumes are version 4 */ #define HFSX_VERSION 0x0005 /* HFSX volumes start with version 5 */ -#define HFSPLUS_MOUNT_VERSION 0x31302e30 /* '10.0 for Mac OS X */ -#define HFSJ_MOUNT_VERSION 0x4846534a /* 'HFSJ' for jounraled HFS+ on Mac OS X */ +#define HFSPLUS_MOUNT_VERSION 0x31302e30 /* '10.0' for Mac OS X */ +#define HFSJ_MOUNT_VERSION 0x4846534a /* 'HFSJ' for journaled HFS+ on Mac OS X */ #define FSK_MOUNT_VERSION 0x46534b21 /* 'FSK!' for failed journal replay */ +#define FSCK_MOUNT_VERSION 0x6673636b /* 'fsck' for fsck_hfs */ +#define OS89_MOUNT_VERSION 0x382e3130 /* '8.10' for Mac OS 8.1-9.2.2 */ #define HFS_SBOFF 1024 #define HFS_FILE_CONTENT_LEN 160 // size of two hfs_fork data structures @@ -116,11 +118,12 @@ */ #define NSEC_BTWN_1904_1970 (uint32_t) 2082844800U -#define HFS_BIT_VOLUME_UNMOUNTED (uint32_t)(1 << 8) /* set if the volume was unmounted properly; as per TN 1150, modern Macintosh OSes always leave this bit set */ +#define HFS_BIT_VOLUME_UNMOUNTED (uint32_t)(1 << 8) /* set if the volume was unmounted properly; as per TN 1150, modern Macintosh OSes always leave this bit set for the boot volume */ #define HFS_BIT_VOLUME_BADBLOCKS (uint32_t)(1 << 9) /* set if there are any bad blocks for this volume (in the Extents B-tree) */ #define HFS_BIT_VOLUME_INCONSISTENT (uint32_t)(1 << 11) /* cleared if the volume was unmounted properly */ -#define HFS_BIT_VOLUME_JOURNALED (uint32_t)(1 << 13) #define HFS_BIT_VOLUME_CNIDS_REUSED (uint32_t)(1 << 12) /* set if CNIDs have wrapped around past the maximum value and are being reused; in this case, there are CNIDs on the disk larger than the nextCatalogId field */ +#define HFS_BIT_VOLUME_JOURNALED (uint32_t)(1 << 13) +#define HFS_BIT_VOLUME_SOFTWARE_LOCK (uint32_t)(1 << 14) /* set if volume should be write-protected in software */ /* constants for BTree header record attributes */ #define HFS_BT_BIGKEYS 0x00000002 /* kBTBigKeysMask : key length field is 16 bits */ -- GitLab