diff --git a/tsk3/fs/hfs.c b/tsk3/fs/hfs.c index 2e8a7aca6cf616df5c9f196c20f865ed3e6d4106..5b81370265f9fab6c5d13ddf3f43275ce0d3085f 100644 --- a/tsk3/fs/hfs.c +++ b/tsk3/fs/hfs.c @@ -197,6 +197,7 @@ hfs_get_keylen(HFS_INFO * hfs, uint16_t keylen, * @param nodenum Node number in B-Tree to find * @returns byte offset or 0 on failure. */ +#if 0 static TSK_OFF_T hfs_ext_find_node_offset(HFS_INFO * hfs, hfs_btree_header_record * hdr, uint32_t nodenum) @@ -280,6 +281,7 @@ hfs_ext_find_node_offset(HFS_INFO * hfs, hfs_btree_header_record * hdr, return r_offs; } +#endif /** \internal * Process a B-Tree node record and return the record contents and the @@ -397,6 +399,7 @@ hfs_get_bt_rec_off(HFS_INFO * hfs, TSK_OFF_T node_off, * @param cur_node_off [in,out] XXXX * @param header [in] Header of tree * @returns 0 on error */ +#if 0 static uint32_t hfs_ext_next_record(HFS_INFO * hfs, uint16_t * rec, uint16_t * num_rec, hfs_btree_node * node, uint32_t * cur_node, TSK_OFF_T * cur_node_off, @@ -445,9 +448,9 @@ hfs_ext_next_record(HFS_INFO * hfs, uint16_t * rec, uint16_t * num_rec, return *cur_node; } +#endif -// @@@ This could probably return TSK_FS_ATTR /** \internal * Returns the extents (data runs) for the data fork of a given file. The * caller must free the returned array. @@ -463,6 +466,7 @@ hfs_ext_next_record(HFS_INFO * hfs, uint16_t * rec, uint16_t * num_rec, * found, this function will also return NULL. * May set up to error string 2. */ +#if 0 static hfs_ext_desc * hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, hfs_ext_desc * first_ext) @@ -503,7 +507,7 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, } /* Get the starting address of the extents file to read header record */ - // @@@@ ERROR: header is 0 here, which doesn't help to find the node size, which is why it is passe to find_.... + // ERROR: header is 0 here, which doesn't help to find the node size, which is why it is passe to find_.... off = hfs_ext_find_node_offset(hfs, &header, 0); if (off == 0) { snprintf(tsk_errstr2, TSK_ERRSTR_L, @@ -561,7 +565,6 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, return NULL; } - // @@@ We could probably make this faster by reading the entire node if (hfs_checked_read_random(fs, (char *) &node, sizeof(node), cur_off)) { @@ -838,7 +841,7 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, } } - +#endif /** * Convert the extents runs to TSK_FS_ATTR_RUN runs. @@ -934,10 +937,11 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, } } + // allocate a node buffer nodesize = tsk_getu16(fs->endian, hfs->extents_header.nodesize); - if ((node = (char *) tsk_malloc(nodesize)) == NULL) + if ((node = (char *) tsk_malloc(nodesize)) == NULL) { return 1; - // @@@ ADD FREE CODE + } /* start at root node */ cur_node = tsk_getu32(fs->endian, hfs->extents_header.root); @@ -950,6 +954,7 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, if (tsk_verbose) tsk_fprintf(stderr, "hfs_ext_find_extent_record: " "empty extents btree\n"); + free(node); return 0; } @@ -970,6 +975,7 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, node, nodesize, 0); if (cnt != nodesize) { // @@@ + free(node); return 1; } @@ -987,6 +993,7 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, snprintf(tsk_errstr, TSK_ERRSTR_L, "hfs_ext_find_extent_record: zero records in node %" PRIu32, cur_node); + free(node); return 1; } @@ -1102,9 +1109,11 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, "hfs_ext_find_extent_record: btree node %" PRIu32 " (%" PRIu64 ") is neither index nor leaf (%" PRIu8 ")", cur_node, cur_off, node_desc->kind); + free(node); return 1; } } + free(node); } @@ -1523,7 +1532,7 @@ hfs_cat_file_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry) memcpy((char *) &entry->thread, (char *) &thread, sizeof(hfs_thread)); - entry->flags |= TSK_FS_META_FLAG_ALLOC; /// @@@ What about USED, etc.? + entry->flags = TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_USED; entry->inum = inum; if (tsk_verbose) @@ -1678,6 +1687,7 @@ hfs_make_catalog(HFS_INFO * hfs, TSK_FS_FILE * fs_file) tsk_getu64(fs->endian, hfs->fs->cat_file.logic_sz); + // convert the runs in the volume header to attribute runs if ((attr_run = hfs_extents_to_attr(fs, hfs->fs->cat_file.extents, 0)) == NULL) { @@ -1983,46 +1993,59 @@ hfs_make_attrfile(HFS_INFO * hfs, TSK_FS_FILE * fs_file) } -/* - * Copy the inode into the generic structure +/** \internal + * Copy the catalog file record entry into a TSK data structure. + * @param a_hfs File system being analyzed + * @param a_entry Catalog record entry (could be a hfs_folder structure too) + * @param a_fs_meta Structure to copy data into * Returns 1 on error. */ static uint8_t -hfs_dinode_copy(HFS_INFO * hfs, hfs_file * entry, TSK_FS_META * fs_meta) +hfs_dinode_copy(HFS_INFO * a_hfs, const hfs_file * a_entry, + TSK_FS_META * a_fs_meta) { - TSK_FS_INFO *fs = (TSK_FS_INFO *) & hfs->fs_info; + TSK_FS_INFO *fs = (TSK_FS_INFO *) & a_hfs->fs_info; + + if (a_fs_meta == NULL) { + tsk_errno = TSK_ERR_FS_ARG; + snprintf(tsk_errstr, TSK_ERRSTR_L, + "hfs_dinode_copy: a_fs_meta is NULL"); + return 1; + } if (tsk_verbose) tsk_fprintf(stderr, "hfs_dinode_copy: called\n"); - fs_meta->attr_state = TSK_FS_META_ATTR_EMPTY; - if (fs_meta->attr) { - tsk_fs_attrlist_markunused(fs_meta->attr); + if (a_fs_meta->content_len < HFS_FILE_CONTENT_LEN) { + if ((a_fs_meta = + tsk_fs_meta_realloc(a_fs_meta, + HFS_FILE_CONTENT_LEN)) == NULL) { + return 1; + } } - fs_meta->mode = - hfsmode2tskmode(tsk_getu32(fs->endian, entry->perm.mode)); + a_fs_meta->attr_state = TSK_FS_META_ATTR_EMPTY; + if (a_fs_meta->attr) { + tsk_fs_attrlist_markunused(a_fs_meta->attr); + } - if (tsk_getu16(fs->endian, entry->rec_type) == HFS_FOLDER_RECORD) { - fs_meta->size = 0; - fs_meta->type = - hfsmode2tskmetatype(tsk_getu16(fs->endian, entry->perm.mode)); - if (fs_meta->type != TSK_FS_META_TYPE_DIR) { - tsk_fprintf(stderr, - "hfs_dinode_copy error: folder has non-directory type %" - PRIu16 "\n", fs_meta->type); - return 1; - } + a_fs_meta->mode = + hfsmode2tskmode(tsk_getu32(fs->endian, a_entry->perm.mode)); + a_fs_meta->type = + hfsmode2tskmetatype(tsk_getu32(fs->endian, a_entry->perm.mode)); + + if (tsk_getu16(fs->endian, a_entry->rec_type) == HFS_FOLDER_RECORD) { + a_fs_meta->size = 0; + memset(a_fs_meta->content_ptr, 0, HFS_FILE_CONTENT_LEN); } - else if (tsk_getu16(fs->endian, entry->rec_type) == HFS_FILE_RECORD) { - fs_meta->size = tsk_getu64(fs->endian, entry->data.logic_sz); - fs_meta->type = - hfsmode2tskmetatype(tsk_getu16(fs->endian, entry->perm.mode)); - if (fs_meta->type == TSK_FS_META_TYPE_DIR) { - tsk_fprintf(stderr, - "hfs_dinode_copy error: file has directory type\n"); - return 1; - } + else if (tsk_getu16(fs->endian, a_entry->rec_type) == HFS_FILE_RECORD) { + hfs_fork *fork; + a_fs_meta->size = tsk_getu64(fs->endian, a_entry->data.logic_sz); + + // copy the data and resource forks + fork = (hfs_fork *) a_fs_meta->content_ptr; + memcpy(fork, &(a_entry->data), sizeof(hfs_fork)); + memcpy(&fork[1], &(a_entry->resource), sizeof(hfs_fork)); } else { tsk_fprintf(stderr, @@ -2030,30 +2053,34 @@ hfs_dinode_copy(HFS_INFO * hfs, hfs_file * entry, TSK_FS_META * fs_meta) return 1; } - fs_meta->uid = tsk_getu32(fs->endian, entry->perm.owner); - fs_meta->gid = tsk_getu32(fs->endian, entry->perm.group); - fs_meta->mtime = hfs2unixtime(tsk_getu32(fs->endian, entry->cmtime)); - fs_meta->atime = hfs2unixtime(tsk_getu32(fs->endian, entry->atime)); - fs_meta->crtime = hfs2unixtime(tsk_getu32(fs->endian, entry->ctime)); - fs_meta->ctime = - hfs2unixtime(tsk_getu32(fs->endian, entry->attr_mtime)); - fs_meta->time2.hfs.bkup_time = - hfs2unixtime(tsk_getu32(fs->endian, entry->bkup_date)); - fs_meta->addr = tsk_getu32(fs->endian, entry->cnid); + a_fs_meta->uid = tsk_getu32(fs->endian, a_entry->perm.owner); + a_fs_meta->gid = tsk_getu32(fs->endian, a_entry->perm.group); + + a_fs_meta->mtime = + hfs2unixtime(tsk_getu32(fs->endian, a_entry->cmtime)); + a_fs_meta->atime = + hfs2unixtime(tsk_getu32(fs->endian, a_entry->atime)); + a_fs_meta->crtime = + hfs2unixtime(tsk_getu32(fs->endian, a_entry->ctime)); + a_fs_meta->ctime = + hfs2unixtime(tsk_getu32(fs->endian, a_entry->attr_mtime)); + a_fs_meta->time2.hfs.bkup_time = + hfs2unixtime(tsk_getu32(fs->endian, a_entry->bkup_date)); + + a_fs_meta->addr = tsk_getu32(fs->endian, a_entry->cnid); - fs_meta->flags = 0; // @@@ entry->flags; + // All entries here are used. @@@ What about alloc? + a_fs_meta->flags = TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_USED; /* TODO could fill in name2 with this entry's name and parent inode from Catalog entry */ - // @@@ Shouldn't there be basic filling in of record locations etc? - return 0; } /** \internal - * Read a catalog file entry and save it in the generic TSK_FS_META format. + * Load a catalog file entry and save it in the TSK_FS_FILE structure. * * @param fs File system to read from. * @param a_fs_file Structure to read into. @@ -2135,18 +2162,20 @@ hfs_inode_lookup(TSK_FS_INFO * fs, TSK_FS_FILE * a_fs_file, } /** \internal + * Populate the attributes in fs_file using the internal fork data. This uses + * the data cached in the content_ptr structure. + * @param fs_file File to load attributes for * * @returns 1 on error and 0 on success */ static uint8_t -hfs_make_data_run(TSK_FS_FILE * fs_file) +hfs_load_attrs(TSK_FS_FILE * fs_file) { TSK_FS_INFO *fs; HFS_INFO *hfs; - int i; TSK_FS_ATTR *fs_attr; - HFS_ENTRY entry; - hfs_ext_desc *extents; + TSK_FS_ATTR_RUN *attr_run; + hfs_fork *fork; // clean up any error messages that are lying around tsk_error_reset(); @@ -2155,16 +2184,21 @@ hfs_make_data_run(TSK_FS_FILE * fs_file) || (fs_file->fs_info == NULL)) { tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_make_data_run: fs_file or meta is NULL"); + "hfs_load_attrs: fs_file or meta is NULL"); + return 1; + } + if (fs_file->meta->content_ptr == NULL) { + tsk_errno = TSK_ERR_FS_ARG; + snprintf(tsk_errstr, TSK_ERRSTR_L, + "hfs_load_attrs: content_ptr is NULL"); return 1; } fs = (TSK_FS_INFO *) fs_file->fs_info; hfs = (HFS_INFO *) fs; - if (tsk_verbose) tsk_fprintf(stderr, - "hfs_make_data_run: Processing file %" PRIuINUM "\n", + "hfs_load_attrs: Processing file %" PRIuINUM "\n", fs_file->meta->addr); // see if we have already loaded the runs @@ -2183,62 +2217,54 @@ hfs_make_data_run(TSK_FS_FILE * fs_file) } - // look up the catalog entries for this file - // (they have already been looked up once before, but that information - // isn't propagated to here, so we look it up again) - if (hfs_cat_file_lookup(hfs, fs_file->meta->addr, &entry)) - return 1; - - // if the catalog entry is not a file entry (presumably it would have - // to be a folder entry), then it has no data - if (tsk_getu16(fs->endian, entry.cat.rec_type) != HFS_FILE_RECORD) + //@@@ is this teh best response? + // need to come up with compete plan on dealig with directories, size, content etc. + if (fs_file->meta->type != TSK_FS_META_TYPE_REG) return 0; + // get an attribute structure to store the data in if ((fs_attr = tsk_fs_attrlist_getnew(fs_file->meta->attr, TSK_FS_ATTR_NONRES)) == NULL) { + strncat(tsk_errstr2, " - hfs_load_attrs", + TSK_ERRSTR_L - strlen(tsk_errstr2)); return 1; } - // initialize the data run - if (tsk_fs_attr_set_run(fs_file, fs_attr, NULL, NULL, 0, 0, - fs_file->meta->size, roundup(fs_file->meta->size, - fs->block_size), 0, 0)) { + + // Get the data fork and convert it to the TSK format + fork = (hfs_fork *) fs_file->meta->content_ptr; + if ((attr_run = hfs_extents_to_attr(fs, fork->extents, 0)) == NULL) { + strncat(tsk_errstr2, " - hfs_load_attrs", + TSK_ERRSTR_L - strlen(tsk_errstr2)); + tsk_fs_attr_free(fs_attr); return 1; } - extents = - hfs_ext_find_extent_record(hfs, (uint32_t) entry.inum, - entry.cat.data.extents); - - if (extents == NULL) + // add the runs to the attribute and the attribute to the file. + if (tsk_fs_attr_set_run(fs_file, fs_attr, attr_run, NULL, + TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT, + tsk_getu64(fs->endian, fork->logic_sz), + tsk_getu32(fs->endian, fork->total_blk) * fs->block_size, 0, + 0)) { + strncat(tsk_errstr2, " - hfs_load_attrs", + TSK_ERRSTR_L - strlen(tsk_errstr2)); + tsk_fs_attr_free(fs_attr); + tsk_fs_attr_run_free(attr_run); return 1; + } - for (i = 0; (tsk_getu32(fs->endian, extents[i].start_blk) != 0) || - (tsk_getu32(fs->endian, extents[i].blk_cnt) != 0); i++) { - TSK_FS_ATTR_RUN *data_run; - - data_run = tsk_fs_attr_run_alloc(); - if (data_run == NULL) { - free(extents); - return -1; - } - - data_run->addr = (TSK_DADDR_T) tsk_getu32(fs->endian, - extents[i].start_blk); - data_run->len = (TSK_DADDR_T) tsk_getu32(fs->endian, - extents[i].blk_cnt); - - // save the run - tsk_fs_attr_append_run(fs, fs_attr, data_run); + // see if extents file has additional runs + if (hfs_ext_find_extent_record_attr(hfs, fs_file->meta->addr, fs_attr)) { + strncat(tsk_errstr2, " - hfs_load_attrs", + TSK_ERRSTR_L - strlen(tsk_errstr2)); + fs_file->meta->attr_state = TSK_FS_META_ATTR_ERROR; + return 1; } - // note that the old code used to check if the total number of blocks in the - // extents was too large or small for the size of the file (fork) - // this is no longer done (at least within this function) + // @@@ Resource fork too fs_file->meta->attr_state = TSK_FS_META_ATTR_STUDIED; - free(extents); return 0; } @@ -2487,7 +2513,8 @@ hfs_inode_walk(TSK_FS_INFO * fs, TSK_INUM_T start_inum, if (hfs_dinode_copy(hfs, &entry.cat, fs_file->meta)) return 1; - // @@@ We should be looking at some flags here... + if ((fs_file->meta->flags & flags) != flags) + continue; /* call action */ retval = action(fs_file, ptr); @@ -3027,7 +3054,7 @@ hfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset, fs->inode_walk = hfs_inode_walk; fs->block_walk = hfs_block_walk; fs->block_getflags = hfs_block_getflags; - fs->load_attrs = hfs_make_data_run; + fs->load_attrs = hfs_load_attrs; fs->get_default_attr_type = hfs_get_default_attr_type; fs->file_add_meta = hfs_inode_lookup; @@ -3047,24 +3074,11 @@ hfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset, fs->last_inum = HFS_FIRST_USER_CNID - 1; // we will later increase this fs->inum_count = fs->last_inum - fs->first_inum + 1; - /* Load the Catalog file extents (data runs) starting with - * the data in the volume header */ - // @@@@ How will this know to load only one entry from the volume header? - hfs->cat_extents = - hfs_ext_find_extent_record(hfs, HFS_CATALOG_FILE_ID, - hfs->fs->cat_file.extents); - if (hfs->cat_extents == NULL) { - fs->tag = 0; - free(hfs->fs); - free(hfs); - return NULL; - } - - hfs->extents_file = NULL; // we will load this when needed + /* We will load the extents file data when we need it */ + hfs->extents_file = NULL; hfs->extents_attr = NULL; - - + /* Load the catalog file though */ if ((hfs->catalog_file = tsk_fs_file_open_meta(fs, NULL, HFS_CATALOG_FILE_ID)) == NULL) { diff --git a/tsk3/fs/tsk_hfs.h b/tsk3/fs/tsk_hfs.h index cee47f1349da6315e1a2f813c8c39adca22cc13e..336760fff4071e6c88699edd3e370bae598a8937 100644 --- a/tsk3/fs/tsk_hfs.h +++ b/tsk3/fs/tsk_hfs.h @@ -92,7 +92,7 @@ #define FSK_MOUNT_VERSION 0x46534b21 /* 'FSK!' for failed journal replay */ #define HFS_SBOFF 1024 -#define HFS_FILE_CONTENT_LEN 0 +#define HFS_FILE_CONTENT_LEN 160 // size of two hfs_fork data structures /* b-tree kind types */ #define HFS_BTREE_LEAF_NODE -1 @@ -202,28 +202,24 @@ typedef struct { #define HFS_IFXATTR 0200000 /* extended attributes */ /* HFS extent descriptor */ -//typedef struct { -struct hfs_ext_desc { +typedef struct { uint8_t start_blk[4]; /* start block */ uint8_t blk_cnt[4]; /* block count */ -}; -//} hfs_ext_desc; -typedef struct hfs_ext_desc hfs_ext_desc; +} hfs_ext_desc; +/* Structre used in the extents tree */ typedef struct { hfs_ext_desc extents[8]; } hfs_extents; /* fork data structure */ -//typedef struct { -struct hfs_fork { - uint8_t logic_sz[8]; /* logical size */ - uint8_t clmp_sz[4]; /* clump size */ - uint8_t total_blk[4]; /* total blocks */ +typedef struct { + uint8_t logic_sz[8]; /* The size (in bytes) of the fork */ + uint8_t clmp_sz[4]; /* For forks in volume header, clump size. For + * catalog files, this is number of blocks read or not used. */ + uint8_t total_blk[4]; /* total blocks in all extents of the fork */ hfs_ext_desc extents[8]; -}; -//} hfs_fork; -typedef struct hfs_fork hfs_fork; +} hfs_fork; /* ** Super Block @@ -384,17 +380,16 @@ typedef struct { typedef struct { TSK_FS_INFO fs_info; /* SUPER CLASS */ - + hfs_sb *fs; /* cached superblock */ - hfs_ext_desc *cat_extents; /* full extents of the Catalog file */ - + char is_case_sensitive; - + TSK_FS_FILE *blockmap_file; const TSK_FS_ATTR *blockmap_attr; char blockmap_cache[4096]; int blockmap_cache_start; - + TSK_FS_FILE *catalog_file; const TSK_FS_ATTR *catalog_attr; hfs_btree_header_record catalog_header;