static int hfsplus_extract_file(const char* filename, HfsPPrivateFile* hfsp_file) { FILE* fout; unsigned int cp_sect; PedSector rem_sect; fout = fopen(filename, "w"); if (!fout) return 0; for (rem_sect = hfsp_file->sect_nb; rem_sect; rem_sect -= cp_sect) { cp_sect = rem_sect < BLOCK_MAX_BUFF ? rem_sect : BLOCK_MAX_BUFF; if (!hfsplus_file_read(hfsp_file, extract_buffer, hfsp_file->sect_nb - rem_sect, cp_sect)) goto err_close; if (!fwrite (extract_buffer, cp_sect * PED_SECTOR_SIZE_DEFAULT, 1, fout)) goto err_close; } return (fclose(fout) == 0 ? 1 : 0); err_close: fclose(fout); return 0; }
static int hfsplus_cache_from_attributes(HfsCPrivateCache* cache, PedFileSystem* fs, PedTimer* timer) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; uint8_t node_1[PED_SECTOR_SIZE_DEFAULT]; uint8_t* node; HfsPHeaderRecord* header; HfsPPrivateGenericKey* generic_key; HfsPForkDataAttr* fork_ext_data; HfsPExtDescriptor* extent; unsigned int leaf_node, record_number; unsigned int i, j, size, bsize; /* attributes file is facultative */ if (!priv_data->attributes_file->sect_nb) return 1; /* Search the extent starting at *ptr_block in the catalog file */ if (!hfsplus_file_read_sector (priv_data->attributes_file, node_1, 0)) return 0; header = ((HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC)); leaf_node = PED_BE32_TO_CPU (header->first_leaf_node); bsize = PED_BE16_TO_CPU (header->node_size); size = bsize / PED_SECTOR_SIZE_DEFAULT; PED_ASSERT(size < 256); node = (uint8_t*) ped_malloc(bsize); if (!node) return 0; HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node; for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) { if (!hfsplus_file_read (priv_data->attributes_file, node, (PedSector) leaf_node * size, size)) { free (node); return 0; } record_number = PED_BE16_TO_CPU (desc->rec_nb); for (i = 1; i <= record_number; i++) { unsigned int skip; generic_key = (HfsPPrivateGenericKey*) (node + PED_BE16_TO_CPU(*((uint16_t *) (node+(bsize - 2*i))))); skip = ( 2 + PED_BE16_TO_CPU (generic_key->key_length) + 1 ) & ~1; fork_ext_data = (HfsPForkDataAttr*) (((uint8_t*)generic_key) + skip); /* check for obvious error in FS */ if (((uint8_t*)generic_key - node < HFS_FIRST_REC) || ((uint8_t*)fork_ext_data - node >= (signed) bsize - 2 * (signed)(record_number+1))) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("The file system contains errors.")); free (node); return 0; } if (fork_ext_data->record_type == PED_CPU_TO_BE32 ( HFSP_ATTR_FORK ) ) { extent = fork_ext_data->fork_res.fork.extents; for (j = 0; j < HFSP_EXT_NB; ++j) { if (!extent[j].block_count) break; if (!hfsc_cache_add_extent( cache, PED_BE32_TO_CPU ( extent[j].start_block ), PED_BE32_TO_CPU ( extent[j].block_count ), leaf_node, (uint8_t*)extent-node, size, CR_BTREE_ATTR, j ) ) { free(node); return 0; } } } else if (fork_ext_data->record_type == PED_CPU_TO_BE32 ( HFSP_ATTR_EXTENTS ) ) { extent = fork_ext_data->fork_res.extents; for (j = 0; j < HFSP_EXT_NB; ++j) { if (!extent[j].block_count) break; if (!hfsc_cache_add_extent( cache, PED_BE32_TO_CPU ( extent[j].start_block ), PED_BE32_TO_CPU ( extent[j].block_count ), leaf_node, (uint8_t*)extent-node, size, CR_BTREE_ATTR, j ) ) { free(node); return 0; } } } else continue; } } free (node); return 1; }
static int hfsplus_cache_from_extent(HfsCPrivateCache* cache, PedFileSystem* fs, PedTimer* timer) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; uint8_t node_1[PED_SECTOR_SIZE_DEFAULT]; uint8_t* node; HfsPHeaderRecord* header; HfsPExtentKey* extent_key; HfsPExtDescriptor* extent; unsigned int leaf_node, record_number; unsigned int i, j, size, bsize; if (!priv_data->extents_file->sect_nb) { ped_exception_throw ( PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK, _("This HFS+ volume has no extents overflow " "file. This is quite unusual!")); return 1; } if (!hfsplus_file_read_sector (priv_data->extents_file, node_1, 0)) return 0; header = ((HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC)); leaf_node = PED_BE32_TO_CPU (header->first_leaf_node); bsize = PED_BE16_TO_CPU (header->node_size); size = bsize / PED_SECTOR_SIZE_DEFAULT; PED_ASSERT(size < 256); node = (uint8_t*) ped_malloc (bsize); if (!node) return -1; HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node; for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) { if (!hfsplus_file_read (priv_data->extents_file, node, (PedSector) leaf_node * size, size)) { free (node); return 0; } record_number = PED_BE16_TO_CPU (desc->rec_nb); for (i = 1; i <= record_number; i++) { uint8_t where; extent_key = (HfsPExtentKey*) (node + PED_BE16_TO_CPU(*((uint16_t *) (node+(bsize - 2*i))))); extent = (HfsPExtDescriptor*) (((uint8_t*)extent_key) + sizeof (HfsPExtentKey)); /* check for obvious error in FS */ if (((uint8_t*)extent_key - node < HFS_FIRST_REC) || ((uint8_t*)extent - node >= (signed)bsize - 2 * (signed)(record_number+1))) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("The file system contains errors.")); free (node); return -1; } switch (extent_key->file_ID) { case PED_CPU_TO_BE32 (HFS_XTENT_ID) : if (ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE_CANCEL, _("The extents overflow file should not" " contain its own extents! You should " "check the file system.")) != PED_EXCEPTION_IGNORE) return 0; where = CR_BTREE_EXT_EXT; break; case PED_CPU_TO_BE32 (HFS_CATALOG_ID) : where = CR_BTREE_EXT_CAT; break; case PED_CPU_TO_BE32 (HFSP_ALLOC_ID) : where = CR_BTREE_EXT_ALLOC; break; case PED_CPU_TO_BE32 (HFSP_STARTUP_ID) : where = CR_BTREE_EXT_START; break; case PED_CPU_TO_BE32 (HFSP_ATTRIB_ID) : where = CR_BTREE_EXT_ATTR; break; default : where = CR_BTREE_EXT_0; break; } for (j = 0; j < HFSP_EXT_NB; ++j) { if (!extent[j].block_count) break; if (!hfsc_cache_add_extent( cache, PED_BE32_TO_CPU(extent[j].start_block), PED_BE32_TO_CPU(extent[j].block_count), leaf_node, (uint8_t*)extent - node, size, where, j ) ) { free (node); return 0; } } } } free (node); return 1; }
static int hfsplus_cache_from_catalog(HfsCPrivateCache* cache, PedFileSystem* fs, PedTimer* timer) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; uint8_t node_1[PED_SECTOR_SIZE_DEFAULT]; uint8_t* node; HfsPHeaderRecord* header; HfsPCatalogKey* catalog_key; HfsPCatalog* catalog_data; HfsPExtDescriptor* extent; unsigned int leaf_node, record_number; unsigned int i, j, size, bsize; uint32_t jib = priv_data->jib_start_block, jl = priv_data->jl_start_block; if (!priv_data->catalog_file->sect_nb) { ped_exception_throw ( PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK, _("This HFS+ volume has no catalog file. " "This is very unusual!")); return 1; } /* Search the extent starting at *ptr_block in the catalog file */ if (!hfsplus_file_read_sector (priv_data->catalog_file, node_1, 0)) return 0; header = (HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC); leaf_node = PED_BE32_TO_CPU (header->first_leaf_node); bsize = PED_BE16_TO_CPU (header->node_size); size = bsize / PED_SECTOR_SIZE_DEFAULT; PED_ASSERT(size < 256); node = (uint8_t*) ped_malloc(bsize); if (!node) return 0; HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node; for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) { if (!hfsplus_file_read (priv_data->catalog_file, node, (PedSector) leaf_node * size, size)) { free (node); return 0; } record_number = PED_BE16_TO_CPU (desc->rec_nb); for (i = 1; i <= record_number; i++) { unsigned int skip; uint8_t where; catalog_key = (HfsPCatalogKey*) ( node + PED_BE16_TO_CPU (*((uint16_t *) (node+(bsize - 2*i)))) ); skip = ( 2 + PED_BE16_TO_CPU (catalog_key->key_length) + 1) & ~1; catalog_data = (HfsPCatalog*) (((uint8_t*)catalog_key) + skip); /* check for obvious error in FS */ if (((uint8_t*)catalog_key - node < HFS_FIRST_REC) || ((uint8_t*)catalog_data - node >= (signed) bsize - 2 * (signed)(record_number+1))) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("The file system contains errors.")); free (node); return 0; } if (PED_BE16_TO_CPU(catalog_data->type)!=HFS_CAT_FILE) continue; extent = catalog_data->sel.file.data_fork.extents; for (j = 0; j < HFSP_EXT_NB; ++j) { if (!extent[j].block_count) break; where = CR_BTREE_CAT; if ( PED_BE32_TO_CPU(extent[j].start_block) == jib ) { jib = 0; where = CR_BTREE_CAT_JIB; } else if ( PED_BE32_TO_CPU(extent[j].start_block) == jl ) { jl = 0; where = CR_BTREE_CAT_JL; } if (!hfsc_cache_add_extent( cache, PED_BE32_TO_CPU(extent[j].start_block), PED_BE32_TO_CPU(extent[j].block_count), leaf_node, (uint8_t*)extent - node, size, where, j ) ) { free (node); return 0; } } extent = catalog_data->sel.file.res_fork.extents; for (j = 0; j < HFSP_EXT_NB; ++j) { if (!extent[j].block_count) break; if (!hfsc_cache_add_extent( cache, PED_BE32_TO_CPU(extent[j].start_block), PED_BE32_TO_CPU(extent[j].block_count), leaf_node, (uint8_t*)extent - node, size, CR_BTREE_CAT, j ) ) { free (node); return 0; } } } } free (node); return 1; }
static int hfsplus_do_move (PedFileSystem* fs, unsigned int *ptr_src, unsigned int *ptr_dest, HfsCPrivateCache* cache, HfsCPrivateExtent* ref) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; HfsPPrivateFile* file; HfsPExtDescriptor* extent; HfsCPrivateExtent* move; int new_start; new_start = hfsplus_effect_move_extent (fs, ptr_src, ptr_dest, ref->ext_length); if (new_start == -1) return -1; if (ref->ext_start != (unsigned) new_start) { switch (ref->where) { /************ VH ************/ case CR_PRIM_CAT : priv_data->catalog_file ->first[ref->ref_index].start_block = PED_CPU_TO_BE32(new_start); goto CR_PRIM; case CR_PRIM_EXT : priv_data->extents_file ->first[ref->ref_index].start_block = PED_CPU_TO_BE32(new_start); goto CR_PRIM; case CR_PRIM_ATTR : priv_data->attributes_file ->first[ref->ref_index].start_block = PED_CPU_TO_BE32(new_start); goto CR_PRIM; case CR_PRIM_ALLOC : priv_data->allocation_file ->first[ref->ref_index].start_block = PED_CPU_TO_BE32(new_start); goto CR_PRIM; case CR_PRIM_START : /* No startup file opened */ CR_PRIM : extent = ( HfsPExtDescriptor* ) ( (uint8_t*)priv_data->vh + ref->ref_offset ); extent[ref->ref_index].start_block = PED_CPU_TO_BE32(new_start); if (!hfsplus_update_vh(fs)) return -1; break; /************** BTREE *************/ case CR_BTREE_CAT_JIB : if (!hfsj_update_jib(fs, new_start)) return -1; goto BTREE_CAT; case CR_BTREE_CAT_JL : if (!hfsj_update_jl(fs, new_start)) return -1; goto BTREE_CAT; BTREE_CAT: case CR_BTREE_CAT : file = priv_data->catalog_file; goto CR_BTREE; case CR_BTREE_ATTR : file = priv_data->attributes_file; goto CR_BTREE; case CR_BTREE_EXT_ATTR : if (priv_data->attributes_file ->cache[ref->ref_index].start_block == PED_CPU_TO_BE32(ref->ext_start)) priv_data->attributes_file ->cache[ref->ref_index].start_block = PED_CPU_TO_BE32(new_start); goto CR_BTREE_EXT; case CR_BTREE_EXT_CAT : if (priv_data->catalog_file ->cache[ref->ref_index].start_block == PED_CPU_TO_BE32(ref->ext_start)) priv_data->catalog_file ->cache[ref->ref_index].start_block = PED_CPU_TO_BE32(new_start); goto CR_BTREE_EXT; case CR_BTREE_EXT_ALLOC : if (priv_data->allocation_file ->cache[ref->ref_index].start_block == PED_CPU_TO_BE32(ref->ext_start)) priv_data->allocation_file ->cache[ref->ref_index].start_block = PED_CPU_TO_BE32(new_start); goto CR_BTREE_EXT; case CR_BTREE_EXT_START : /* No startup file opened */ CR_BTREE_EXT : case CR_BTREE_EXT_0 : file = priv_data->extents_file; CR_BTREE : PED_ASSERT(PED_SECTOR_SIZE_DEFAULT * ref->sect_by_block > ref->ref_offset); if (!hfsplus_file_read(file, hfsp_block, (PedSector)ref->ref_block * ref->sect_by_block, ref->sect_by_block)) return -1; extent = ( HfsPExtDescriptor* ) ( hfsp_block + ref->ref_offset ); extent[ref->ref_index].start_block = PED_CPU_TO_BE32(new_start); if (!hfsplus_file_write(file, hfsp_block, (PedSector)ref->ref_block * ref->sect_by_block, ref->sect_by_block) || !ped_geometry_sync_fast (priv_data->plus_geom)) return -1; break; /********** BUG *********/ default : ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("A reference to an extent comes from a place " "it should not. You should check the file " "system!")); return -1; break; } move = hfsc_cache_move_extent(cache, ref->ext_start, new_start); if (!move) return -1; PED_ASSERT(move == ref); } return new_start; }
PedFileSystem* hfsplus_open (PedGeometry* geom) { uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; PedFileSystem* fs; HfsPVolumeHeader* vh; HfsPPrivateFSData* priv_data; PedGeometry* wrapper_geom; unsigned int map_sectors; if (!hfsc_can_use_geom (geom)) return NULL; fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem)); if (!fs) goto hpo; vh = (HfsPVolumeHeader*) ped_malloc (sizeof (HfsPVolumeHeader)); if (!vh) goto hpo_fs; priv_data = (HfsPPrivateFSData*)ped_malloc (sizeof (HfsPPrivateFSData)); if (!priv_data) goto hpo_vh; fs->geom = ped_geometry_duplicate (geom); if (!fs->geom) goto hpo_pd; fs->type_specific = (void*) priv_data; if ((wrapper_geom = hfs_and_wrapper_probe (geom))) { HfsPrivateFSData* hfs_priv_data; PedSector abs_sect, length; unsigned int bs; ped_geometry_destroy (wrapper_geom); priv_data->wrapper = hfs_open(geom); if (!priv_data->wrapper) goto hpo_gm; hfs_priv_data = (HfsPrivateFSData*) priv_data->wrapper->type_specific; bs = PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size) / PED_SECTOR_SIZE_DEFAULT; abs_sect = (PedSector) geom->start + (PedSector) PED_BE16_TO_CPU ( hfs_priv_data->mdb->start_block) + (PedSector) PED_BE16_TO_CPU ( hfs_priv_data->mdb->old_new .embedded.location.start_block ) * bs; length = (PedSector) PED_BE16_TO_CPU ( hfs_priv_data->mdb->old_new .embedded.location.block_count) * bs; priv_data->plus_geom = ped_geometry_new (geom->dev, abs_sect, length); if (!priv_data->plus_geom) goto hpo_wr; priv_data->free_geom = 1; } else { priv_data->wrapper = NULL; priv_data->plus_geom = fs->geom; priv_data->free_geom = 0; } if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1)) goto hpo_pg; memcpy (vh, buf, sizeof (HfsPVolumeHeader)); priv_data->vh = vh; if (vh->signature != PED_CPU_TO_BE16(HFSP_SIGNATURE) && vh->signature != PED_CPU_TO_BE16(HFSX_SIGNATURE)) { ped_exception_throw ( PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL, _("No valid HFS[+X] signature has been found while " "opening.")); goto hpo_pg; } if (vh->signature == PED_CPU_TO_BE16(HFSP_SIGNATURE) && vh->version != PED_CPU_TO_BE16(HFSP_VERSION)) { if (ped_exception_throw ( PED_EXCEPTION_NO_FEATURE, PED_EXCEPTION_IGNORE_CANCEL, _("Version %d of HFS+ isn't supported."), PED_BE16_TO_CPU(vh->version)) != PED_EXCEPTION_IGNORE) goto hpo_pg; } if (vh->signature == PED_CPU_TO_BE16(HFSX_SIGNATURE) && vh->version != PED_CPU_TO_BE16(HFSX_VERSION)) { if (ped_exception_throw ( PED_EXCEPTION_NO_FEATURE, PED_EXCEPTION_IGNORE_CANCEL, _("Version %d of HFSX isn't supported."), PED_BE16_TO_CPU(vh->version)) != PED_EXCEPTION_IGNORE) goto hpo_pg; } priv_data->jib_start_block = 0; priv_data->jl_start_block = 0; if (vh->attributes & PED_CPU_TO_BE32(1<<HFSP_JOURNALED)) { if (!hfsj_replay_journal(fs)) goto hpo_pg; } priv_data->bad_blocks_loaded = 0; priv_data->bad_blocks_xtent_nb = 0; priv_data->bad_blocks_xtent_list = NULL; priv_data->extents_file = hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_XTENT_ID), vh->extents_file.extents, PED_BE64_TO_CPU ( vh->extents_file.logical_size ) / PED_SECTOR_SIZE_DEFAULT); if (!priv_data->extents_file) goto hpo_pg; priv_data->catalog_file = hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_CATALOG_ID), vh->catalog_file.extents, PED_BE64_TO_CPU ( vh->catalog_file.logical_size ) / PED_SECTOR_SIZE_DEFAULT); if (!priv_data->catalog_file) goto hpo_ce; priv_data->attributes_file = hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ATTRIB_ID), vh->attributes_file.extents, PED_BE64_TO_CPU ( vh->attributes_file.logical_size) / PED_SECTOR_SIZE_DEFAULT); if (!priv_data->attributes_file) goto hpo_cc; map_sectors = ( PED_BE32_TO_CPU (vh->total_blocks) + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8); priv_data->dirty_alloc_map = (uint8_t*) ped_malloc ((map_sectors + 7) / 8); if (!priv_data->dirty_alloc_map) goto hpo_cl; memset(priv_data->dirty_alloc_map, 0, (map_sectors + 7) / 8); priv_data->alloc_map = (uint8_t*) ped_malloc (map_sectors * PED_SECTOR_SIZE_DEFAULT); if (!priv_data->alloc_map) goto hpo_dm; priv_data->allocation_file = hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ALLOC_ID), vh->allocation_file.extents, PED_BE64_TO_CPU ( vh->allocation_file.logical_size) / PED_SECTOR_SIZE_DEFAULT); if (!priv_data->allocation_file) goto hpo_am; if (!hfsplus_file_read (priv_data->allocation_file, priv_data->alloc_map, 0, map_sectors)) { hfsplus_close(fs); return NULL; } fs->type = &hfsplus_type; fs->checked = ((PED_BE32_TO_CPU (vh->attributes) >> HFS_UNMOUNTED) & 1) && !((PED_BE32_TO_CPU (vh->attributes) >> HFSP_INCONSISTENT) & 1); return fs; /*--- clean error handling ---*/ hpo_am: free(priv_data->alloc_map); hpo_dm: free(priv_data->dirty_alloc_map); hpo_cl: hfsplus_file_close (priv_data->attributes_file); hpo_cc: hfsplus_file_close (priv_data->catalog_file); hpo_ce: hfsplus_file_close (priv_data->extents_file); hpo_pg: if (priv_data->free_geom) ped_geometry_destroy (priv_data->plus_geom); hpo_wr: if (priv_data->wrapper) hfs_close(priv_data->wrapper); hpo_gm: ped_geometry_destroy (fs->geom); hpo_pd: free(priv_data); hpo_vh: free(vh); hpo_fs: free(fs); hpo: return NULL; }