static uint8_t hfs_dir_open_meta_cb(HFS_INFO * hfs, int8_t level_type, const void *targ_data, const hfs_btree_key_cat * cur_key, TSK_OFF_T key_off, void *ptr) { uint32_t *cnid_p = (uint32_t *) targ_data; HFS_DIR_OPEN_META_INFO *info = (HFS_DIR_OPEN_META_INFO *) ptr; TSK_FS_INFO *fs = &hfs->fs_info; if (tsk_verbose) fprintf(stderr, "hfs_dir_open_meta_cb: want %" PRIu32 " vs got %" PRIu32 " (%s node)\n", *cnid_p, tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid), (level_type == HFS_BT_NODE_TYPE_IDX) ? "Index" : "Leaf"); if (level_type == HFS_BT_NODE_TYPE_IDX) { if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) < *cnid_p) { return HFS_BTREE_CB_IDX_LT; } else { return HFS_BTREE_CB_IDX_EQGT; } } else { uint8_t *rec_buf = (uint8_t *) cur_key; uint16_t rec_type; size_t rec_off2; if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) < *cnid_p) { return HFS_BTREE_CB_LEAF_GO; } else if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) > *cnid_p) { return HFS_BTREE_CB_LEAF_STOP; } rec_off2 = 2 + tsk_getu16(hfs->fs_info.endian, cur_key->key_len); // @@@ NEED TO REPLACE THIS SOMEHOW, but need to figure out the max length /* if (rec_off2 > nodesize) { tsk_error_set_errno(TSK_ERR_FS_GENFS); tsk_error_set_errstr( "hfs_dir_open_meta: offset of record+keylen %d in leaf node %d too large (%zu vs %" PRIu16 ")", rec, cur_node, rec_off2, nodesize); tsk_fs_name_free(fs_name); free(node); return TSK_COR; } */ rec_type = tsk_getu16(hfs->fs_info.endian, &rec_buf[rec_off2]); // Catalog entry is for a file if (rec_type == HFS_FILE_THREAD) { tsk_error_set_errno(TSK_ERR_FS_GENFS); tsk_error_set_errstr("hfs_dir_open_meta: Entry" " is a file, not a folder"); return HFS_BTREE_CB_ERR; } /* This will link the folder to its parent, which is the ".." entry */ else if (rec_type == HFS_FOLDER_THREAD) { hfs_thread *thread = (hfs_thread *) & rec_buf[rec_off2]; strcpy(info->fs_name->name, ".."); info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, thread->parent_cnid); info->fs_name->type = TSK_FS_NAME_TYPE_DIR; info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; } /* This is a folder in the folder */ else if (rec_type == HFS_FOLDER_RECORD) { hfs_folder *folder = (hfs_folder *) & rec_buf[rec_off2]; info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, folder->std.cnid); info->fs_name->type = TSK_FS_NAME_TYPE_DIR; info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; if (hfs_UTF16toUTF8(fs, (uint8_t *) cur_key->name.unicode, tsk_getu16(hfs->fs_info.endian, cur_key->name.length), info->fs_name->name, HFS_MAXNAMLEN + 1, HFS_U16U8_FLAG_REPLACE_SLASH)) { return HFS_BTREE_CB_ERR; } } /* This is a normal file in the folder */ else if (rec_type == HFS_FILE_RECORD) { hfs_file *file = (hfs_file *) & rec_buf[rec_off2]; // This could be a hard link. We need to test this CNID, and follow it if necessary. unsigned char is_err; TSK_INUM_T file_cnid = tsk_getu32(hfs->fs_info.endian, file->std.cnid); TSK_INUM_T target_cnid = hfs_follow_hard_link(hfs, file, &is_err); if (is_err > 1) { error_returned ("hfs_dir_open_meta_cb: trying to follow a possible hard link in the directory"); return HFS_BTREE_CB_ERR; } if (target_cnid != file_cnid) { HFS_ENTRY entry; uint8_t lkup; // lookup result // This is a hard link. We need to fill in the name->type and name->meta_addr from the target info->fs_name->meta_addr = target_cnid; // get the Catalog entry for the target CNID lkup = hfs_cat_file_lookup(hfs, target_cnid, &entry, FALSE); if (lkup != 0) { error_returned ("hfs_dir_open_meta_cb: retrieving the catalog entry for the target of a hard link"); return HFS_BTREE_CB_ERR; } info->fs_name->type = hfsmode2tsknametype(tsk_getu16(hfs->fs_info.endian, entry.cat.std.perm.mode)); } else { // This is NOT a hard link. info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, file->std.cnid); info->fs_name->type = hfsmode2tsknametype(tsk_getu16(hfs->fs_info.endian, file->std.perm.mode)); } info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; if (hfs_UTF16toUTF8(fs, (uint8_t *) cur_key->name.unicode, tsk_getu16(hfs->fs_info.endian, cur_key->name.length), info->fs_name->name, HFS_MAXNAMLEN + 1, HFS_U16U8_FLAG_REPLACE_SLASH)) { return HFS_BTREE_CB_ERR; } } else { tsk_error_set_errno(TSK_ERR_FS_GENFS); // @@@ MAY NEED TO IMPROVE BELOW MESSAGE tsk_error_set_errstr ("hfs_dir_open_meta: Unknown record type %d in leaf node", rec_type); return HFS_BTREE_CB_ERR; } if (tsk_fs_dir_add(info->fs_dir, info->fs_name)) { return HFS_BTREE_CB_ERR; } return HFS_BTREE_CB_LEAF_GO; } }
static uint8_t hfs_dir_open_meta_cb(HFS_INFO * hfs, int8_t level_type, const void *targ_data, const hfs_btree_key_cat * cur_key, TSK_OFF_T key_off, void *ptr) { uint32_t *cnid_p = (uint32_t *) targ_data; HFS_DIR_OPEN_META_INFO *info = (HFS_DIR_OPEN_META_INFO *) ptr; TSK_FS_INFO *fs = &hfs->fs_info; if (tsk_verbose) fprintf(stderr, "hfs_dir_open_meta_cb: want %" PRIu32 " vs got %" PRIu32 " (%s node)\n", *cnid_p, tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid), (level_type == HFS_BT_NODE_TYPE_IDX) ? "Index" : "Leaf"); if (level_type == HFS_BT_NODE_TYPE_IDX) { if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) < *cnid_p) return HFS_BTREE_CB_IDX_LT; else return HFS_BTREE_CB_IDX_EQGT; } else { uint8_t *rec_buf = (uint8_t *) cur_key; uint16_t rec_type; size_t rec_off2; if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) < *cnid_p) return HFS_BTREE_CB_LEAF_GO; else if (tsk_getu32(hfs->fs_info.endian, cur_key->parent_cnid) > *cnid_p) return HFS_BTREE_CB_LEAF_STOP; rec_off2 = 2 + tsk_getu16(hfs->fs_info.endian, cur_key->key_len); // @@@ NEED TO REPLACE THIS SOMEHOW, but need to figure out the max length /* if (rec_off2 > nodesize) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, "hfs_dir_open_meta: offset of record+keylen %d in leaf node %d too large (%zu vs %" PRIu16 ")", rec, cur_node, rec_off2, nodesize); tsk_fs_name_free(fs_name); free(node); return TSK_COR; } */ rec_type = tsk_getu16(hfs->fs_info.endian, &rec_buf[rec_off2]); // Catalog entry is for a file if (rec_type == HFS_FILE_THREAD) { tsk_errno = TSK_ERR_FS_GENFS; snprintf(tsk_errstr, TSK_ERRSTR_L, "hfs_dir_open_meta: Entry" " is a file, not a folder"); return HFS_BTREE_CB_ERR; } /* This will link the folder to its parent, which is the ".." entry */ else if (rec_type == HFS_FOLDER_THREAD) { hfs_thread *thread = (hfs_thread *) & rec_buf[rec_off2]; strcpy(info->fs_name->name, ".."); info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, thread->parent_cnid); info->fs_name->type = TSK_FS_NAME_TYPE_DIR; info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; } /* This is a folder in the folder */ else if (rec_type == HFS_FOLDER_RECORD) { hfs_folder *folder = (hfs_folder *) & rec_buf[rec_off2]; info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, folder->std.cnid); info->fs_name->type = TSK_FS_NAME_TYPE_DIR; info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; if (hfs_uni2ascii(fs, (uint8_t *) cur_key->name.unicode, tsk_getu16(hfs->fs_info.endian, cur_key->name.length), info->fs_name->name, HFS_MAXNAMLEN + 1)) { return HFS_BTREE_CB_ERR; } } /* This is a normal file in the folder */ else if (rec_type == HFS_FILE_RECORD) { hfs_file *file = (hfs_file *) & rec_buf[rec_off2]; info->fs_name->meta_addr = tsk_getu32(hfs->fs_info.endian, file->std.cnid); info->fs_name->type = hfsmode2tsknametype(tsk_getu16(hfs->fs_info.endian, file->std.perm.mode)); info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; if (hfs_uni2ascii(fs, (uint8_t *) cur_key->name.unicode, tsk_getu16(hfs->fs_info.endian, cur_key->name.length), info->fs_name->name, HFS_MAXNAMLEN + 1)) { return HFS_BTREE_CB_ERR; } } else { tsk_errno = TSK_ERR_FS_GENFS; // @@@ MAY NEED TO IMPROVE BELOW MESSAGE snprintf(tsk_errstr, TSK_ERRSTR_L, "hfs_dir_open_meta: Unknown record type %d in leaf node", rec_type); return HFS_BTREE_CB_ERR; } if (tsk_fs_dir_add(info->fs_dir, info->fs_name)) { return HFS_BTREE_CB_ERR; } return HFS_BTREE_CB_LEAF_GO; } }