diff --git a/tsk3/fs/hfs.c b/tsk3/fs/hfs.c index bcd3cd3163afefb9d5d143f2916ba573eb011d17..7507b2a6cc037720f355926b5df1ecc2a0b87516 100644 --- a/tsk3/fs/hfs.c +++ b/tsk3/fs/hfs.c @@ -107,51 +107,28 @@ hfs2unixtime(uint32_t hfsdate) } +/** + * Convert a cnid (metadata address) to big endian array. + * This is used to create the key for tree lookups. + * @param cnid Metadata address to convert + * @param array [out] Array to write data into. + */ +static void +cnid_to_array(uint32_t cnid, uint8_t array[4]) +{ + array[3] = (cnid >> 0) & 0xff; + array[2] = (cnid >> 8) & 0xff; + array[1] = (cnid >> 16) & 0xff; + array[0] = (cnid >> 24) & 0xff; +} + /********************************************************************** * * Lookup Functions * **********************************************************************/ -static int hfs_load_blockmap(HFS_INFO *); -/** \internal - * Get allocation status of file system block. - * adapted from IsAllocationBlockUsed from: - * http://developer.apple.com/technotes/tn/tn1150.html - * - * @param hfs File system being analyzed - * @param b Block address - * @returns 1 if allocated, 0 if not, -1 on error - */ -static int8_t -hfs_is_block_alloc(HFS_INFO * hfs, TSK_DADDR_T b) -{ - TSK_DADDR_T a; - uint8_t this_byte; - - // lazy loading of block map - if (hfs->block_map == NULL) { - if (hfs_load_blockmap(hfs)) { - // @@@ FIX error - tsk_fprintf(stderr, - "ERROR hfs_is_block_alloc: failed to load block map\n"); - return -1; - } - } - - a = b / 8; - if (a > hfs->block_map_size) { - // @@@ FIX error - tsk_fprintf(stderr, - "WARNING hfs_is_block_alloc: block %" PRIuDADDR - " is past the end of the allocation file\n", b); - return -1; - } - - this_byte = hfs->block_map[a]; - return (this_byte & (1 << (7 - (b % 8)))) != 0; -} /* Compares the given HFS+ Extents B-tree key to key constructed * for finding the beginning of the data fork extents for the given @@ -159,7 +136,7 @@ hfs_is_block_alloc(HFS_INFO * hfs, TSK_DADDR_T b) * fork = 0 and start_block = 0.) */ static int -hfs_compare_extent_keys(HFS_INFO * hfs, uint32_t cnid, hfs_ext_key * key) +hfs_ext_compare_keys(HFS_INFO * hfs, uint32_t cnid, hfs_ext_key * key) { TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info); uint32_t key_cnid; @@ -493,7 +470,7 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info); hfs_btree_header_record header; /* header for the Extents btree */ - uint16_t leafsize; /* size of nodes (all, regardless of the name) */ + uint16_t nodesize; /* size of nodes (all, regardless of the name) */ uint32_t cur_node; /* node id of the current node */ @@ -544,7 +521,7 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, free(out_ext); return NULL; } - leafsize = tsk_getu16(fs->endian, header.nodesize); + nodesize = tsk_getu16(fs->endian, header.nodesize); /* start at root node */ cur_node = tsk_getu32(fs->endian, header.root); @@ -562,8 +539,8 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, if (tsk_verbose) tsk_fprintf(stderr, "hfs_ext_find_extent_record: starting at " - "root node %" PRIu32 "; header @ %" PRIuOFF "; leafsize = %" - PRIu16 "\n", cur_node, off, leafsize); + "root node %" PRIu32 "; header @ %" PRIuOFF "; nodesize = %" + PRIu16 "\n", cur_node, off, nodesize); while (1) { TSK_OFF_T cur_off; /* start address of cur_node */ @@ -620,7 +597,7 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, int cmp; // get the record offset - addr = hfs_get_bt_rec_off(hfs, cur_off, leafsize, rec); + addr = hfs_get_bt_rec_off(hfs, cur_off, nodesize, rec); if (addr == 0) { snprintf(tsk_errstr2, TSK_ERRSTR_L, "hfs_ext_find_extent_record: finding record %" PRIu16 @@ -642,7 +619,7 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, free(out_ext); return NULL; } - cmp = hfs_compare_extent_keys(hfs, cnid, &key); + cmp = hfs_ext_compare_keys(hfs, cnid, &key); if (tsk_verbose) tsk_fprintf(stderr, @@ -680,7 +657,7 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, rec = recno; /* using rec as our counting variable again, for kicks */ /* reget key */ - addr = hfs_get_bt_rec_off(hfs, cur_off, leafsize, rec); + addr = hfs_get_bt_rec_off(hfs, cur_off, nodesize, rec); if (addr == 0) { snprintf(tsk_errstr2, TSK_ERRSTR_L, "hfs_ext_find_extent_record: finding record %" PRIu16 @@ -736,7 +713,7 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, } /* load new key data, since I'm about to use it */ - addr = hfs_get_bt_rec_off(hfs, cur_off, leafsize, rec); + addr = hfs_get_bt_rec_off(hfs, cur_off, nodesize, rec); if (addr == 0) { snprintf(tsk_errstr2, TSK_ERRSTR_L, "hfs_ext_find_extent_record: finding record %" @@ -825,7 +802,7 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid, } /* load new key data */ - addr = hfs_get_bt_rec_off(hfs, cur_off, leafsize, rec); + addr = hfs_get_bt_rec_off(hfs, cur_off, nodesize, rec); if (addr == 0) { snprintf(tsk_errstr2, TSK_ERRSTR_L, "hfs_ext_find_extent_record: finding record %" @@ -1029,7 +1006,7 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, // @@@ ERROR } key = (hfs_ext_key *) & node[rec_off]; - cmp = hfs_compare_extent_keys(hfs, cnid, key); + cmp = hfs_ext_compare_keys(hfs, cnid, key); if (tsk_verbose) tsk_fprintf(stderr, @@ -1128,169 +1105,6 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid, } -/* return the offset into the image that catalog btree node 'node' is at */ -/* returns 0 on failure; may set up to error string 1 */ -TSK_OFF_T -hfs_cat_find_node_offset(HFS_INFO * hfs, uint32_t nodenum) -{ - TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info); - uint16_t nodesize; /* size of each node */ - int i; - uint64_t bytes; /* bytes left this extent */ - TSK_OFF_T r_offs; /* offset we are reading from */ - TSK_OFF_T f_offs; /* offset into the catalog file */ - TSK_OFF_T n_offs; /* offset of the node we are looking for */ - hfs_ext_desc *extents; - - if (tsk_verbose) - tsk_fprintf(stderr, "hfs_cat_find_node_offset: finding offset of " - "btree node: %" PRIu32 "\n", nodenum); - - extents = hfs->cat_extents; - - /* find first extent with data in it */ - /* as above, holdover from previous code */ - i = 0; - while (!(tsk_getu32(fs->endian, extents[i].blk_cnt))) - i++; - - if (i > 7) { - tsk_errno = TSK_ERR_FS_GENFS; - snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_cat_find_node_offset: no data found in catalog file extents"); - return 0; - } - - bytes = - tsk_getu32(fs->endian, - extents[i].blk_cnt) * (TSK_OFF_T) fs->block_size; - r_offs = - tsk_getu32(fs->endian, - extents[i].start_blk) * (TSK_OFF_T) fs->block_size; - f_offs = 0; - - nodesize = tsk_getu16(fs->endian, hfs->catalog_header.nodesize); - - /* calculate where we will find the 'nodenum' node */ - n_offs = nodesize * nodenum; - - while (f_offs < n_offs) { - - if (n_offs <= (f_offs + (TSK_OFF_T)bytes)) { - - r_offs += n_offs - f_offs; - f_offs = n_offs; - - } - else { - - i++; - - if (i > 7) { - tsk_errno = TSK_ERR_FS_GENFS; - snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_cat_find_node_offset: file seek error while searching for node %" - PRIu32 "\n", nodenum); - return 0; - } - - r_offs = - tsk_getu32(fs->endian, - extents[i].start_blk) * (TSK_OFF_T) fs->block_size; - f_offs += bytes; - bytes = - tsk_getu32(fs->endian, - extents[i].blk_cnt) * (TSK_OFF_T) fs->block_size; - - } - } - - return r_offs; -} - -/* Advances to the next record in the Catalog B-tree, given information about - * where you currently are in the B-tree. - * Assumes that you are actually keeping track of these many fields. They - * must correctly contain the current values. If the current node is changed, - * they will be changed to their new values. - * Returns cur_node. If you have reached the end of the node chain (no more - * records), cur_node will be set to zero and returned. - * May set up to error string 2. Returns 0 on error. */ -uint32_t -hfs_cat_next_record(HFS_INFO * hfs, uint16_t * rec, uint16_t * num_rec, - hfs_btree_node * node, uint32_t * cur_node, TSK_OFF_T * cur_off, - hfs_btree_header_record * header) -{ - TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info); - - tsk_error_reset(); - - (*rec)++; - - if (*rec >= *num_rec) { /* ran out of records in this node */ - *cur_node = tsk_getu32(fs->endian, node->flink); - if (*cur_node == 0) - return *cur_node; - *cur_off = hfs_cat_find_node_offset(hfs, *cur_node); - if (*cur_off == 0) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_cat_next_record: find next node offset (%" PRIu32 ")", - *cur_node); - return 0; - } - if (hfs_checked_read_random(fs, (char *) node, - sizeof(hfs_btree_node), *cur_off)) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_cat_next_record: read btree node %" PRIu32 " at %" - PRIuDADDR, *cur_node, *cur_off); - return 0; - } - *num_rec = tsk_getu16(fs->endian, node->num_rec); - *rec = 0; - if (tsk_verbose) - tsk_fprintf(stderr, - "hfs_cat_next_record: advanced to next node %" PRIu32 - "(@ %" PRIu64 ", has %" PRIu16 "records \n", *cur_node, - *cur_off, *num_rec); - } - else { - if (tsk_verbose) - tsk_fprintf(stderr, - "hfs_cat_next_record: advanced to record %" PRIu16 "\n", - *rec); - } - - return *cur_node; -} - -/** \internal - * Returns the largest inode number in file system - * @param hfs File system being analyzed - * @returns largest metadata address - */ -static TSK_INUM_T -hfs_find_highest_inum(HFS_INFO * hfs) -{ - // @@@ get actual number from Catalog file - /* I haven't gotten looking at the end of the Catalog B-Tree to work - properly. A fast method: if HFS_BIT_VOLUME_CNIDS_REUSED is set, then - the maximum CNID is 2^32-1; if it's not set, then nextCatalogId is - supposed to be larger than all CNIDs on disk. - */ - - TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info); - - if (tsk_getu32(fs->endian, - hfs->fs->attr) & HFS_BIT_VOLUME_CNIDS_REUSED) - return (TSK_INUM_T) 0xffffffff; - else - return (TSK_INUM_T) tsk_getu32(fs->endian, - hfs->fs->next_cat_id) - 1; -} - - -// @@@ We should have a version of this that allows one key to have cnid already in local order... - /** \internal * Compares two Catalog B-tree keys. * @param hfs File System being analyzed @@ -1299,7 +1113,7 @@ hfs_find_highest_inum(HFS_INFO * hfs) * @returns -1 if key1 is smaller, 0 if equal, and 1 if key1 is larger */ int -hfs_compare_catalog_keys(HFS_INFO * hfs, hfs_cat_key * key1, +hfs_cat_compare_keys(HFS_INFO * hfs, hfs_cat_key * key1, hfs_cat_key * key2) { TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info); @@ -1317,200 +1131,227 @@ hfs_compare_catalog_keys(HFS_INFO * hfs, hfs_cat_key * key1, } + + /** \internal - * Find the byte offset (from the start of the disk) to a record - * in the catalog file. - * @param hfs File System being analyzed - * @param needle Key to search for - * @returns Byte offset or 0 on error. 0 is also returned if catalog - * record was not found. Check tsk_errno to determine if error occured. - */ +* Find the byte offset (from the start of the catalog file) to a record +* in the catalog file. +* @param hfs File System being analyzed +* @param needle Key to search for +* @returns Byte offset or 0 on error. 0 is also returned if catalog +* record was not found. Check tsk_errno to determine if error occured. +*/ static TSK_OFF_T -hfs_catalog_get_record_offset(HFS_INFO * hfs, hfs_cat_key * needle) +hfs_cat_get_record_offset(HFS_INFO * hfs, hfs_cat_key * needle) { - TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info); - - hfs_btree_header_record header; /* header for the Catalog btree */ - uint16_t leafsize; /* size of nodes (all, regardless of the name) */ + TSK_FS_INFO *fs = &(hfs->fs_info); uint32_t cur_node; /* node id of the current node */ - TSK_OFF_T off; + char *node; + uint16_t nodesize; + uint8_t is_done = 0; + tsk_error_reset(); - /* read catalog header record */ - off = hfs_cat_find_node_offset(hfs, 0); - if (off == 0) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_catalog_get_record_offset: find catalog header node"); + + nodesize = tsk_getu16(fs->endian, hfs->catalog_header.nodesize); + if ((node = (char *) tsk_malloc(nodesize)) == NULL) return 0; - } - off += 14; // sizeof header - if (hfs_checked_read_random(fs, (char *) &header, sizeof(header), off)) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_catalog_get_record_offset: read catalog header node"); + // @@@ ADD FREE CODE + + /* start at root node */ + cur_node = tsk_getu32(fs->endian, hfs->catalog_header.root); + + /* if the root node is zero, then the extents btree is empty */ + /* if no files have overflow extents, the Extents B-tree still + exists on disk, but is an empty B-tree containing only + the header node */ + if (cur_node == 0) { + if (tsk_verbose) + tsk_fprintf(stderr, "hfs_cat_get_record_offset: " + "empty extents btree\n"); return 0; } - leafsize = tsk_getu16(fs->endian, header.nodesize); // @@@ This should be hard coded - - /* start at root node */ - cur_node = tsk_getu32(fs->endian, header.root); - + if (tsk_verbose) - tsk_fprintf(stderr, "hfs_catalog_get_record_offset: starting at " - "root node %" PRIu32 "; header @ %" PRIu64 "; leafsize = %" - PRIu16 "\n", cur_node, off, leafsize); - - while (1) { + tsk_fprintf(stderr, "hfs_cat_get_record_offset: starting at " + "root node %" PRIu32 "; nodesize = %" + PRIu16 "\n", cur_node, nodesize); + + is_done = 0; + while (is_done == 0) { TSK_OFF_T cur_off; /* start address of cur_node */ - hfs_cat_key key; /* current key */ uint16_t num_rec; /* number of records in this node */ - TSK_DADDR_T recaddr; - uint16_t rec, recno; - char buf[4]; - int cmp; - hfs_btree_node node; /* data of the current node */ - - /* load node header */ - cur_off = hfs_cat_find_node_offset(hfs, cur_node); - if (cur_off == 0) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_catalog_get_record_offset: find catalog node %" PRIu32, - cur_node); - return 0; - } - if (hfs_checked_read_random(fs, (char *) &node, sizeof(node), - cur_off)) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_catalog_get_record_offset: read catalog node %" PRIu32 - " at %" PRIuDADDR, cur_node, cur_off); + ssize_t cnt; + hfs_btree_node *node_desc; + + cur_off = cur_node * nodesize; + + cnt = tsk_fs_attr_read(hfs->catalog_attr, cur_off, + node, nodesize, 0); + if (cnt != nodesize) { + // @@@ return 0; } - num_rec = tsk_getu16(fs->endian, node.num_rec); - + + node_desc = (hfs_btree_node *) node; + + num_rec = tsk_getu16(fs->endian, node_desc->num_rec); + if (tsk_verbose) - tsk_fprintf(stderr, "hfs_catalog_get_record_offset: node %" PRIu32 - " @ %" PRIu64 " has %" PRIu16 " records\n", - cur_node, cur_off, num_rec); - + tsk_fprintf(stderr, "hfs_cat_get_record_offset: node %" PRIu32 + " @ %" PRIu64 " has %" PRIu16 " records\n", + cur_node, cur_off, num_rec); + if (num_rec == 0) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_catalog_get_record_offset: zero records in node %" PRIu32, - cur_node); + "hfs_cat_get_record_offset: zero records in node %" + PRIu32, cur_node); return 0; } - - /* find largest key smaller than or equal to our key */ - recno = 0; - recaddr = 0; - for (rec = 0; rec < num_rec; rec++) { - - off = hfs_get_bt_rec_off(hfs, cur_off, leafsize, rec); - if (off == 0) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_catalog_get_record_offset: finding record %" PRIu16 - " in node %" PRIu32, rec, cur_node); - return 0; - } - off = - hfs_read_key(hfs, &header, off, (char *) &key, - sizeof(hfs_cat_key), 1); - if (off == 0) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_catalog_get_record_offset: reading record %" PRIu16 - " in node %" PRIu32, rec, cur_node); - return 0; - } - cmp = hfs_compare_catalog_keys(hfs, &key, needle); - - if (tsk_verbose) - tsk_fprintf(stderr, - "hfs_catalog_get_record_offset: record %" PRIu16 " @ %" - PRIu64 "; keylen %" PRIu16 " (%" PRIu32 ", %" PRIu16 - "); compare: %d\n", rec, off, tsk_getu16(fs->endian, - key.key_len), tsk_getu32(fs->endian, - key.parent_cnid), tsk_getu16(fs->endian, - key.name.length), cmp); - - /* find the largest key less than or equal to our key */ - /* if all keys are larger than our key, select the leftmost key */ - if ((cmp <= 0) || (recaddr == 0)) { - recaddr = off; - recno = rec; + + if (node_desc->kind == HFS_BTREE_INDEX_NODE) { + uint32_t next_node = 0; + int rec; + + /* find largest key smaller than or equal to cnid */ + for (rec = 0; rec < num_rec; rec++) { + size_t rec_off; + hfs_cat_key *key; + + // get the record offset in the node + rec_off = + tsk_getu16(fs->endian, + &node[nodesize - (rec + 1) * 2]); + if (rec_off > nodesize) { + // @@@ ERROR + return TSK_ERR; + } + key = (hfs_cat_key *) & node[rec_off]; + + if (tsk_verbose) + tsk_fprintf(stderr, + "hfs_cat_get_record_offset: record %" PRIu16 + " ; keylen %" PRIu16 " (%" PRIu32")\n", rec, + tsk_getu16(fs->endian, key->key_len), + tsk_getu32(fs->endian, key->parent_cnid)); + + /* find the largest key less than or equal to our key */ + /* if all keys are larger than our key, select the leftmost key */ + if ((hfs_cat_compare_keys(hfs, key, needle) <= 0) || (next_node == 0)) { + int keylen = tsk_getu16(fs->endian, key->key_len) + 2; + if (rec_off + keylen > nodesize) { + // @@@ ERROR + return TSK_ERR; + } + next_node = + tsk_getu32(fs->endian, &node[rec_off + keylen]); + } + else { + break; + } } - if (cmp >= 0) + if (next_node == 0) { + // @@@@ + is_done = 1; break; - } - - if (node.kind == HFS_BTREE_INDEX_NODE) { - /* replace cur node number with the node number referenced - * by the found key, continue */ - if (hfs_checked_read_random(fs, buf, 4, recaddr)) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_catalog_get_record_offset: reading pointer in record %" - PRIu16 " in node %" PRIu32, rec, cur_node); - return 0; } - cur_node = tsk_getu32(fs->endian, buf); + cur_node = next_node; } - else if (node.kind == HFS_BTREE_LEAF_NODE) { - rec = recno; - - /* reget key */ - off = hfs_get_bt_rec_off(hfs, cur_off, leafsize, rec); - if (off == 0) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_catalog_get_record_offset: finding record %" PRIu16 - " in node %" PRIu32, rec, cur_node); - return 0; - } - off = - hfs_read_key(hfs, &header, off, (char *) &key, - sizeof(hfs_ext_key), 1); - if (off == 0) { - snprintf(tsk_errstr2, TSK_ERRSTR_L, - "hfs_catalog_get_record_offset: reading record %" PRIu16 - " in node %" PRIu32, rec, cur_node); - return 0; + + else if (node_desc->kind == HFS_BTREE_LEAF_NODE) { + int rec; + + for (rec = 0; rec < num_rec; rec++) { + size_t rec_off; + hfs_cat_key *key; + size_t rec_off2; + int diff; + + // get the record offset in the node + rec_off = + tsk_getu16(fs->endian, + &node[nodesize - (rec + 1) * 2]); + if (rec_off > nodesize) { + // @@@ ERROR + return 0; + } + key = (hfs_cat_key *) & node[rec_off]; + + if (tsk_verbose) + tsk_fprintf(stderr, + "hfs_cat_get_record_offset: record %" PRIu16 + "; keylen %" PRIu16 " (%" PRIu32")\n", rec, + tsk_getu16(fs->endian, key->key_len), + tsk_getu32(fs->endian, key->parent_cnid)); + + // rec_cnid = tsk_getu32(fs->endian, key->file_id); + + diff = hfs_cat_compare_keys(hfs, key, needle); + + // see if this record is for our file or if we passed the interesting entries + if (diff < 0) { + continue; + } + else if (diff > 0) { + is_done = 1; + break; + } + + rec_off2 = rec_off + 2 + tsk_getu16(fs->endian, key->key_len); + if (rec_off2 > nodesize) { + // @@@ ERROR + return 0; + } + + return cur_off + rec_off2; } - - if (hfs_compare_catalog_keys(hfs, &key, needle) == 0) - return off; - return 0; /* this key not found */ - } else { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_catalog_get_record_offset: btree node %" PRIu32 - " (%" PRIu64 ") is neither index nor leaf (%" PRIu8 ")", - cur_node, cur_off, node.kind); + "hfs_cat_get_record_offset: btree node %" PRIu32 + " (%" PRIu64 ") is neither index nor leaf (%" PRIu8 ")", + cur_node, cur_off, node_desc->kind); return 0; } } + return 0; } -/* Thread records are variable-length. This function reads in from disk only that - * data actually contained within the thread record into a fixed-size (maximum-size) - * hfs_thread structure, zeroing the remainder of the structure - * Returns 0 on success, 1 on failure; sets up to error string 1 */ + + + +/** \internal + * Given a byte offset to a leaf record in teh catalog file, read the data as + * a thread record. This will zero the buffer and read in the size of the thread + * data. + * @param hfs File System + * @param off Byte offset of record in catalog file (not including key) + * @param thread [out] Buffer to write thread data into. + * @returns 0 on success, 1 on failure; sets up to error string 1 */ uint8_t -hfs_read_thread_record(HFS_INFO * hfs, TSK_DADDR_T addr, +hfs_cat_read_thread_record(HFS_INFO * hfs, TSK_OFF_T off, hfs_thread * thread) { TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info); uint16_t uni_len; + size_t cnt; memset(thread, 0, sizeof(hfs_thread)); - if (hfs_checked_read_random(fs, (char *) thread, 10, addr)) + cnt = tsk_fs_attr_read(hfs->catalog_attr, off, (char *)thread, 10, 0); + if (cnt != 10) { + // @@@ return 1; + } if ((tsk_getu16(fs->endian, thread->record_type) != HFS_FOLDER_THREAD) && (tsk_getu16(fs->endian, thread->record_type) != HFS_FILE_THREAD)) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_read_thread_record: unexpected record type %" PRIu16, + "hfs_cat_read_thread_record: unexpected record type %" PRIu16, tsk_getu16(fs->endian, thread->record_type)); return 1; } @@ -1520,14 +1361,16 @@ hfs_read_thread_record(HFS_INFO * hfs, TSK_DADDR_T addr, if (uni_len > 255) { tsk_errno = TSK_ERR_FS_INODE_COR; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_read_thread_record: invalid string length (%" PRIu16 ")", + "hfs_cat_read_thread_record: invalid string length (%" PRIu16 ")", uni_len); return 1; } - if (hfs_checked_read_random(fs, (char *) thread->name.unicode, - uni_len * 2, addr + 10)) + cnt = tsk_fs_attr_read(hfs->catalog_attr, off + 10, (char *)thread->name.unicode, uni_len*2, 0); + if (cnt != uni_len*2) { + // @@@ return 1; + } return 0; } @@ -1536,35 +1379,43 @@ hfs_read_thread_record(HFS_INFO * hfs, TSK_DADDR_T addr, * Read a catalog record into a local data structure. This reads the * correct amount, depending on if it is a file or folder. * @param hfs File system being analyzed - * @param off Byte offset (in disk) of record + * @param off Byte offset (in catalog file) of record (not including key) * @param record [out] Structure to read data into * @returns 1 on error */ uint8_t -hfs_read_file_folder_record(HFS_INFO * hfs, TSK_OFF_T off, +hfs_cat_read_file_folder_record(HFS_INFO * hfs, TSK_OFF_T off, hfs_file_folder * record) { TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info); + size_t cnt; memset(record, 0, sizeof(hfs_file_folder)); - if (hfs_checked_read_random(fs, (char *) record, 2, off)) + cnt = tsk_fs_attr_read(hfs->catalog_attr, off, (char *)record, 2, 0); + if (cnt != 2) { + // @@@ return 1; - + } + if (tsk_getu16(fs->endian, record->file.rec_type) == HFS_FOLDER_RECORD) { - if (hfs_checked_read_random(fs, ((char *) record) + 2, - sizeof(hfs_folder) - 2, off + 2)) + cnt = tsk_fs_attr_read(hfs->catalog_attr, off, (char *)record, sizeof(hfs_folder), 0); + if (cnt != sizeof(hfs_folder)) { + // @@@ return 1; + } } else if (tsk_getu16(fs->endian, record->file.rec_type) == HFS_FILE_RECORD) { - if (hfs_checked_read_random(fs, ((char *) record) + 2, - sizeof(hfs_file) - 2, off + 2)) + cnt = tsk_fs_attr_read(hfs->catalog_attr, off, (char *)record, sizeof(hfs_file), 0); + if (cnt != sizeof(hfs_file)) { + // @@@ return 1; + } } else { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, - "hfs_read_file_folder_record: unexpected record type %" PRIu16, + "hfs_cat_read_file_folder_record: unexpected record type %" PRIu16, tsk_getu16(fs->endian, record->file.rec_type)); return 1; } @@ -1582,23 +1433,19 @@ hfs_read_file_folder_record(HFS_INFO * hfs, TSK_OFF_T off, * to differentiate between error and not found. */ static uint8_t -hfs_catalog_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry) +hfs_cat_file_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry) { TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info); hfs_cat_key key; /* current catalog key */ - uint32_t cnid; /* catalog node ID of the entry (= inum) */ hfs_thread thread; /* thread record */ hfs_file_folder record; /* file/folder record */ TSK_OFF_T off; - char fname[HFS_MAXNAMLEN + 1]; - uint32_t *temp_32ptr; - tsk_error_reset(); if (tsk_verbose) tsk_fprintf(stderr, - "hfs_catalog_lookup: called for inum %" PRIuINUM "\n", inum); + "hfs_cat_file_lookup: called for inum %" PRIuINUM "\n", inum); // Test if this is a special file that is not located in the catalog if ((inum == HFS_EXTENTS_FILE_ID) || @@ -1610,61 +1457,43 @@ hfs_catalog_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry) return 1; } - /* first look up the thread record for the item we're searching for */ - + /* set up the thread record key */ - cnid = (uint32_t) inum; memset((char *) &key, 0, sizeof(hfs_cat_key)); - + cnid_to_array((uint32_t)inum, key.parent_cnid); - temp_32ptr = (uint32_t *) (key.parent_cnid); - // @@@ Why is this needed, cnid is inum, which is local ordering... - // I think the goal is to put it back into BE ordering, but that seems to not work.. - *temp_32ptr = tsk_getu32(fs->endian, (char *) &cnid); - /* look up the thread record */ - off = hfs_catalog_get_record_offset(hfs, &key); + off = hfs_cat_get_record_offset(hfs, &key); if (off == 0) return 1; /* read the thread record */ - if (hfs_read_thread_record(hfs, off, &thread)) - return 1; - - if (hfs_uni2ascii(fs, thread.name.unicode, - tsk_getu16(fs->endian, thread.name.length), - fname, HFS_MAXNAMLEN + 1)) + if (hfs_cat_read_thread_record(hfs, off, &thread)) return 1; - if (tsk_verbose) - fprintf(stderr, - "hfs_catalog_lookup: parent cnid %" PRIu32 " node name (%" - PRIu16 ") %s\n", tsk_getu32(fs->endian, thread.parent_cnid), - tsk_getu16(fs->endian, thread.name.length), fname); - /* now look up the actual file/folder record */ /* build key */ memset((char *) &key, 0, sizeof(hfs_cat_key)); - memcpy(((char *) &key) + 2, ((char *) &thread) + 4, - sizeof(hfs_cat_key) - 2); + memcpy((char *)key.parent_cnid, (char *)thread.parent_cnid, sizeof(key.parent_cnid)); + memcpy((char *)&key.name, (char *)&thread.name, sizeof(key.name)); /* look up the record */ - off = hfs_catalog_get_record_offset(hfs, &key); + off = hfs_cat_get_record_offset(hfs, &key); if (off == 0) return 1; /* read the record */ - if (hfs_read_file_folder_record(hfs, off, &record)) + if (hfs_cat_read_file_folder_record(hfs, off, &record)) return 1; /* these memcpy can be gotten rid of, really */ if (tsk_getu16(fs->endian, record.file.rec_type) == HFS_FOLDER_RECORD) { if (tsk_verbose) fprintf(stderr, - "hfs_catalog_lookup: found folder record valence %" PRIu32 + "hfs_cat_file_lookup: found folder record valence %" PRIu32 ", cnid %" PRIu32 "\n", tsk_getu32(fs->endian, record.folder.valence), tsk_getu32(fs->endian, record.folder.cnid)); @@ -1674,11 +1503,11 @@ hfs_catalog_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry) record.file.rec_type) == HFS_FILE_RECORD) { if (tsk_verbose) fprintf(stderr, - "hfs_catalog_lookup: found file record cnid %" PRIu32 "\n", + "hfs_cat_file_lookup: found file record cnid %" PRIu32 "\n", tsk_getu32(fs->endian, record.file.cnid)); memcpy((char *) &entry->cat, (char *) &record, sizeof(hfs_file)); } - /* other cases already caught by hfs_read_file_folder_record */ + /* other cases already caught by hfs_cat_read_file_folder_record */ memcpy((char *) &entry->thread, (char *) &thread, sizeof(hfs_thread)); @@ -1686,80 +1515,37 @@ hfs_catalog_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry) entry->inum = inum; if (tsk_verbose) - tsk_fprintf(stderr, "hfs_catalog_lookup exited\n"); + tsk_fprintf(stderr, "hfs_cat_file_lookup exited\n"); return 0; } -/* hfs_load_blockmap - This function will allocate a bitmap of blocks which - * are allocated. - */ -static int -hfs_load_blockmap(HFS_INFO * hfs) +/** \internal +* Returns the largest inode number in file system +* @param hfs File system being analyzed +* @returns largest metadata address +*/ +static TSK_INUM_T +hfs_find_highest_inum(HFS_INFO * hfs) { + // @@@ get actual number from Catalog file + /* I haven't gotten looking at the end of the Catalog B-Tree to work + properly. A fast method: if HFS_BIT_VOLUME_CNIDS_REUSED is set, then + the maximum CNID is 2^32-1; if it's not set, then nextCatalogId is + supposed to be larger than all CNIDs on disk. + */ + TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info); - hfs_ext_desc *extents; - int i; - uint8_t *ptr; - uint32_t bytes_remaining; - - if (tsk_verbose) - tsk_fprintf(stderr, "hfs_load_blockmap: called\n"); - - /* Note: the allocation file can be larger than the number of bytes - computed below. According to TN1150, all extra bits must be set to 0. - We avoid storing those empty bits; a consistency checker may want to - actually load the whole allocation file and check that these bits - are in fact empty. */ - - hfs->block_map_size = - (uint32_t) roundup(fs->block_count / 8, fs->block_size); - if ((hfs->block_map = - (uint8_t *) tsk_malloc(hfs->block_map_size)) == NULL) - return 1; - - memset(hfs->block_map, 0, hfs->block_map_size); - - extents = - hfs_ext_find_extent_record(hfs, HFS_ALLOCATION_FILE_ID, - hfs->fs->alloc_file.extents); - if (extents == NULL) { - tsk_fprintf(stderr, - "hfs_load_blockmap: failed to find extents for allocation file\n"); - return 1; - } - - i = 0; - ptr = hfs->block_map; - bytes_remaining = hfs->block_map_size; - while (bytes_remaining > 0) { - uint32_t blocks; - uint32_t bytes; - TSK_OFF_T offset; - - blocks = tsk_getu32(fs->endian, extents[i].blk_cnt); - if (blocks == 0) { - tsk_fprintf(stderr, - "hfs_load_blockmap: ran out of data for allocation file\n"); - free(extents); - return 1; - } + + if (tsk_getu32(fs->endian, + hfs->fs->attr) & HFS_BIT_VOLUME_CNIDS_REUSED) + return (TSK_INUM_T) 0xffffffff; + else + return (TSK_INUM_T) tsk_getu32(fs->endian, + hfs->fs->next_cat_id) - 1; +} - bytes = (bytes_remaining < blocks * fs->block_size) ? bytes_remaining : blocks * fs->block_size; - offset = - (TSK_OFF_T) tsk_getu32(fs->endian, - extents[i].start_blk) * fs->block_size; - if (hfs_checked_read_random(fs, (char *) ptr, bytes, offset)) { - free(extents); - return 1; - } - bytes_remaining -= bytes; - ptr += bytes; - } - free(extents); - return 0; -} static TSK_FS_META_MODE_ENUM hfsmode2tskmode(uint16_t a_mode) @@ -1979,6 +1765,88 @@ hfs_make_extents(HFS_INFO * hfs, TSK_FS_FILE * fs_file) return 0; } + +/** +* \internal + * Create an FS_INODE structure for the blockmap / allocation file. + * + * @param hfs File system to analyze + * @param fs_file Structure to copy file information into. + * @return 1 on error and 0 on success + */ +static uint8_t +hfs_make_blockmap(HFS_INFO * hfs, TSK_FS_FILE * fs_file) +{ + TSK_FS_INFO *fs = (TSK_FS_INFO *) hfs; + TSK_FS_ATTR *fs_attr; + TSK_FS_ATTR_RUN *attr_run; + + fs_file->meta->type = TSK_FS_META_TYPE_VIRT; + fs_file->meta->mode = 0; + fs_file->meta->nlink = 1; + fs_file->meta->addr = HFS_ALLOCATION_FILE_ID; + fs_file->meta->flags = (TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_ALLOC); + fs_file->meta->uid = fs_file->meta->gid = 0; + fs_file->meta->mtime = fs_file->meta->atime = fs_file->meta->ctime = fs_file->meta->crtime = 0; + + if (fs_file->meta->name2 == NULL) { + if ((fs_file->meta->name2 = (TSK_FS_META_NAME_LIST *) + tsk_malloc(sizeof(TSK_FS_META_NAME_LIST))) == NULL) + return 1; + fs_file->meta->name2->next = NULL; + } + strncpy(fs_file->meta->name2->name, HFS_ALLOCATIONNAME, + TSK_FS_META_NAME_LIST_NSIZE); + + fs_file->meta->size = tsk_getu64(fs->endian, hfs->fs->alloc_file.logic_sz); + + + if (fs_file->meta->attr != NULL) { + tsk_fs_attrlist_markunused(fs_file->meta->attr); + } + else { + fs_file->meta->attr = tsk_fs_attrlist_alloc(); + } + + if ((attr_run = hfs_extents_to_attr(fs, hfs->fs->alloc_file.extents, 0)) == NULL) { + strncat(tsk_errstr2, " - hfs_make_catalog", + TSK_ERRSTR_L - strlen(tsk_errstr2)); + return 1; + } + + if ((fs_attr = tsk_fs_attrlist_getnew(fs_file->meta->attr, TSK_FS_ATTR_NONRES)) == NULL) { + strncat(tsk_errstr2, " - hfs_make_catalog", + TSK_ERRSTR_L - strlen(tsk_errstr2)); + tsk_fs_attr_run_free(attr_run); + return 1; + } + + // initialize the data run + 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, hfs->fs->alloc_file.logic_sz), + tsk_getu64(fs->endian, hfs->fs->alloc_file.logic_sz), 0, 0)) { + strncat(tsk_errstr2, " - hfs_make_catalog", + TSK_ERRSTR_L - strlen(tsk_errstr2)); + tsk_fs_attr_free(fs_attr); + tsk_fs_attr_run_free(attr_run); + return 1; + } + + // see if catalog file has additional runs + if (hfs_ext_find_extent_record_attr(hfs, HFS_ALLOCATION_FILE_ID, + fs_attr)) { + strncat(tsk_errstr2, " - hfs_make_catalog", + TSK_ERRSTR_L - strlen(tsk_errstr2)); + fs_file->meta->attr_state = TSK_FS_META_ATTR_ERROR; + return 1; + } + + fs_file->meta->attr_state = TSK_FS_META_ATTR_STUDIED; + return 0; +} + + /* * Copy the inode into the generic structure * Returns 1 on error. @@ -2106,7 +1974,10 @@ hfs_inode_lookup(TSK_FS_INFO * fs, TSK_FS_FILE * a_fs_file, return 0; } else if (inum == HFS_ALLOCATION_FILE_ID) { - // @@@ + if (hfs_make_blockmap(hfs, a_fs_file)) + return 1; + else + return 0; } else if (inum == HFS_STARTUP_FILE_ID) { // @@@ @@ -2116,7 +1987,7 @@ hfs_inode_lookup(TSK_FS_INFO * fs, TSK_FS_FILE * a_fs_file, } /* Lookup inode and store it in the HFS structure */ - if (hfs_catalog_lookup(hfs, inum, &entry)) + if (hfs_cat_file_lookup(hfs, inum, &entry)) return 1; /* Copy the structure in hfs to generic fs_inode */ @@ -2179,7 +2050,7 @@ 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_catalog_lookup(hfs, fs_file->meta->addr, &entry)) + 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 @@ -2236,10 +2107,75 @@ hfs_make_data_run(TSK_FS_FILE * fs_file) } + + +/** \internal +* Get allocation status of file system block. +* adapted from IsAllocationBlockUsed from: +* http://developer.apple.com/technotes/tn/tn1150.html +* +* @param hfs File system being analyzed +* @param b Block address +* @returns 1 if allocated, 0 if not, -1 on error +*/ +static int8_t +hfs_block_is_alloc(HFS_INFO * hfs, TSK_DADDR_T a_addr) +{ + TSK_FS_INFO *fs = &(hfs->fs_info); + int b; + int b2; + + // lazy loading + if (hfs->blockmap_file == NULL) { + if ((hfs->blockmap_file = + tsk_fs_file_open_meta(fs, NULL, HFS_ALLOCATION_FILE_ID)) == NULL) { + strncat(tsk_errstr2, " - Loading blockmap file", + TSK_ERRSTR_L - strlen(tsk_errstr2)); + return -1; + } + + /* cache the data attribute */ + hfs->blockmap_attr = + tsk_fs_attrlist_get(hfs->blockmap_file->meta->attr, TSK_FS_ATTR_TYPE_DEFAULT); + if (!hfs->blockmap_attr) { + strncat(tsk_errstr2, " - Data Attribute not found in Blockmap File", + TSK_ERRSTR_L - strlen(tsk_errstr2)); + return -1; + } + hfs->blockmap_cache_start = -1; + } + + // get the byte offset + b = (int)a_addr / 8; + if (b > hfs->blockmap_file->meta->size) { + tsk_errno = TSK_ERR_FS_CORRUPT; + snprintf(tsk_errstr, TSK_ERRSTR_L, + "hfs_block_is_alloc: block %" PRIuDADDR + " is too large for bitmap (%"PRIuOFF")", a_addr, hfs->blockmap_file->meta->size); + return -1; + } + + // see if it is in the cache + if ((hfs->blockmap_cache_start == -1) || (hfs->blockmap_cache_start > b) + || (hfs->blockmap_cache_start + sizeof(hfs->blockmap_cache) <= b)) { + size_t cnt = tsk_fs_attr_read(hfs->blockmap_attr, b, + hfs->blockmap_cache, + sizeof(hfs->blockmap_cache), 0); + if (cnt != sizeof(hfs->blockmap_cache)) { + // @@@ + return -1; + } + hfs->blockmap_cache_start = b; + } + b2 = b - hfs->blockmap_cache_start; + return (hfs->blockmap_cache[b2] & (1 << (7 - (a_addr % 8)))) != 0; +} + + TSK_FS_BLOCK_FLAG_ENUM hfs_block_getflags(TSK_FS_INFO * a_fs, TSK_DADDR_T a_addr) { - return hfs_is_block_alloc((HFS_INFO *) a_fs, a_addr) ? + return (hfs_block_is_alloc((HFS_INFO *) a_fs, a_addr) == 1) ? TSK_FS_BLOCK_FLAG_ALLOC : TSK_FS_BLOCK_FLAG_UNALLOC; } @@ -2267,13 +2203,15 @@ hfs_block_walk(TSK_FS_INFO * fs, TSK_DADDR_T start_blk, * Sanity checks. */ if (start_blk < fs->first_block || start_blk > fs->last_block) { - tsk_fprintf(stderr, + tsk_errno = TSK_ERR_FS_WALK_RNG; + snprintf(tsk_errstr, TSK_ERRSTR_L, "%s: invalid start block number: %" PRIuDADDR "", myname, start_blk); return 1; } if (end_blk < fs->first_block || end_blk > fs->last_block) { - tsk_fprintf(stderr, + tsk_errno = TSK_ERR_FS_WALK_RNG; + snprintf(tsk_errstr, TSK_ERRSTR_L, "%s: invalid last block number: %" PRIuDADDR "", myname, end_blk); return 1; @@ -2307,7 +2245,7 @@ hfs_block_walk(TSK_FS_INFO * fs, TSK_DADDR_T start_blk, int myflags; /* identify if the block is allocated or not */ - myflags = hfs_is_block_alloc(hfs, addr) ? + myflags = hfs_block_is_alloc(hfs, addr) ? TSK_FS_BLOCK_FLAG_ALLOC : TSK_FS_BLOCK_FLAG_UNALLOC; // test if we should call the callback with this one @@ -2320,9 +2258,7 @@ hfs_block_walk(TSK_FS_INFO * fs, TSK_DADDR_T start_blk, if (tsk_fs_block_get(fs, fs_block, addr) == NULL) { - tsk_fprintf(stderr, - "hfs_block_walk: Error reading block %" PRIuDADDR - ": %m", addr); + tsk_fs_block_free(fs_block); return 1; } @@ -2399,7 +2335,7 @@ hfs_inode_walk(TSK_FS_INFO * fs, TSK_INUM_T start_inum, * but reuses a single malloc'ed fs_inode */ - if (hfs_catalog_lookup(hfs, inum, &entry)) { + if (hfs_cat_file_lookup(hfs, inum, &entry)) { if (tsk_errno == 0) continue; else @@ -2440,7 +2376,7 @@ print_inode_name(FILE * hFile, TSK_FS_INFO * fs, TSK_INUM_T inum) char fn[HFS_MAXNAMLEN + 1]; HFS_ENTRY entry; - if (hfs_catalog_lookup(hfs, inum, &entry)) + if (hfs_cat_file_lookup(hfs, inum, &entry)) return 1; if (hfs_uni2ascii(fs, entry.thread.name.unicode, @@ -2474,7 +2410,7 @@ print_parent_path(FILE * hFile, TSK_FS_INFO * fs, TSK_INUM_T inum) return 1; } - if (hfs_catalog_lookup(hfs, inum, &entry)) + if (hfs_cat_file_lookup(hfs, inum, &entry)) return 1; if (hfs_uni2ascii(fs, entry.thread.name.unicode, @@ -2749,7 +2685,7 @@ hfs_istat(TSK_FS_INFO * fs, FILE * hFile, TSK_INUM_T inum, ctime(&fs_file->meta->time2.hfs.bkup_time)); - if (hfs_catalog_lookup(hfs, inum, &entry) == 0) { + if (hfs_cat_file_lookup(hfs, inum, &entry) == 0) { tsk_fprintf(hFile, "Owner-ID:\t%" PRIu32 "\n", tsk_getu32(fs->endian, entry.cat.perm.owner)); tsk_fprintf(hFile, "Group-ID:\t%" PRIu32 "\n", tsk_getu32(fs->endian, @@ -2840,9 +2776,13 @@ hfs_close(TSK_FS_INFO * fs) free(hfs->fs); tsk_fs_file_close(hfs->catalog_file); + hfs->catalog_attr = NULL; - if (hfs->block_map != NULL) - free(hfs->block_map); + if (hfs->blockmap_file) { + tsk_fs_file_close(hfs->blockmap_file); + hfs->blockmap_attr = NULL; + } + free(hfs); } @@ -2953,9 +2893,9 @@ hfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset, fs->close = hfs_close; // lazy loading of block map - hfs->block_map = NULL; - hfs->block_map_size = 0; - + hfs->blockmap_file = NULL; + hfs->blockmap_attr = NULL; + hfs->blockmap_cache_start = -1; fs->first_inum = HFS_ROOT_INUM; fs->root_inum = HFS_ROOT_INUM; diff --git a/tsk3/fs/hfs_dent.c b/tsk3/fs/hfs_dent.c index 4d79ed5a8440444ce8aec43bce0fa9e43870399f..9fc569831d363fde780b0dd3b936589b5db00603 100644 --- a/tsk3/fs/hfs_dent.c +++ b/tsk3/fs/hfs_dent.c @@ -339,7 +339,7 @@ hfs_dir_open_meta3(TSK_FS_INFO * fs, TSK_FS_DIR ** a_fs_dir, " in node %" PRIu32, rec, cur_node); return 0; } - cmp = hfs_compare_catalog_keys(hfs, &key, &needle); + cmp = hfs_cat_compare_keys(hfs, &key, &needle); if (tsk_verbose >= 2) tsk_fprintf(stderr, "hfs_dir_open_meta: record %" PRIu16 @@ -392,7 +392,7 @@ hfs_dir_open_meta3(TSK_FS_INFO * fs, TSK_FS_DIR ** a_fs_dir, return 1; } - if (hfs_compare_catalog_keys(hfs, &key, &needle) == 0) { + if (hfs_cat_compare_keys(hfs, &key, &needle) == 0) { /*** thread record found ***/ diff --git a/tsk3/fs/tsk_hfs.h b/tsk3/fs/tsk_hfs.h index 313cf520ef7ad1e3dc2339cb681523e78b13a25a..f67c5e972f6016507a06e113c9f12dc1bde90345 100644 --- a/tsk3/fs/tsk_hfs.h +++ b/tsk3/fs/tsk_hfs.h @@ -149,6 +149,7 @@ #define HFS_CATALOGNAME "$CatalogFile" #define HFS_EXTENTSNAME "$ExtentsFile" +#define HFS_ALLOCATIONNAME "$BitMap" /* * HFS structures @@ -384,11 +385,14 @@ typedef struct { hfs_sb *fs; /* cached superblock */ hfs_ext_desc *cat_extents; /* full extents of the Catalog file */ - uint8_t *block_map; /* cached block allocation bitmap */ - uint32_t block_map_size; 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; @@ -434,6 +438,7 @@ extern uint8_t hfs_jblk_walk(TSK_FS_INFO *, TSK_DADDR_T, TSK_DADDR_T, int, extern uint8_t hfs_jentry_walk(TSK_FS_INFO *, int, TSK_FS_JENTRY_WALK_CB, void *); +/* extern TSK_OFF_T hfs_cat_find_node_offset(HFS_INFO *, uint32_t); extern TSK_OFF_T hfs_get_bt_rec_off(HFS_INFO *, TSK_OFF_T, uint16_t, uint16_t); @@ -441,11 +446,12 @@ extern TSK_OFF_T hfs_read_key(HFS_INFO *, hfs_btree_header_record *, TSK_OFF_T, char *, int, uint8_t); extern int hfs_compare_catalog_keys(HFS_INFO *, hfs_cat_key *, hfs_cat_key *); -extern uint8_t hfs_read_thread_record(HFS_INFO *, TSK_DADDR_T, + +extern uint8_t hfs_read_thread_record(HFS_INFO *, TSK_OFF_T, hfs_thread *); extern uint32_t hfs_cat_next_record(HFS_INFO *, uint16_t *, uint16_t *, hfs_btree_node *, uint32_t *, TSK_OFF_T *, hfs_btree_header_record *); extern uint8_t hfs_read_file_folder_record(HFS_INFO *, TSK_OFF_T, hfs_file_folder *); - +*/ #endif diff --git a/xcode/sleuthkit.xcodeproj/project.pbxproj b/xcode/sleuthkit.xcodeproj/project.pbxproj index ad0954fb973b3b3b1fc37c62cfeb90943ef3fda9..e531c90434340edc61254f5aa1caaef6cb650115 100644 --- a/xcode/sleuthkit.xcodeproj/project.pbxproj +++ b/xcode/sleuthkit.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 02260C770D64895B0027BE02 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; }; 02260C780D64895B0027BE02 /* Makefile.am */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.am; sourceTree = "<group>"; }; 02260C790D64895B0027BE02 /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Makefile.in; sourceTree = "<group>"; }; + 0229714A0EBD0AC0001AC9C7 /* hfs_unicompare.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = hfs_unicompare.c; sourceTree = "<group>"; }; 022B139A0DB6486D00C4BE09 /* nofs_misc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = nofs_misc.c; sourceTree = "<group>"; }; 025328FF0E59B5ED000595D8 /* img_io.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = img_io.c; sourceTree = "<group>"; }; 025558630DA1C67E00A635EC /* fs_block.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = fs_block.c; sourceTree = "<group>"; }; @@ -303,6 +304,7 @@ 026FB4570D19C868000434C7 /* hfs.c */, 026FB45A0D19C868000434C7 /* hfs_dent.c */, 026FB45D0D19C868000434C7 /* hfs_journal.c */, + 0229714A0EBD0AC0001AC9C7 /* hfs_unicompare.c */, 026FB4600D19C868000434C7 /* icat_lib.c */, 026FB4630D19C868000434C7 /* ifind_lib.c */, 026FB4660D19C868000434C7 /* ils_lib.c */,