/* save any dirty sector of the allocation bitmap file */ static int hfsplus_save_allocation(PedFileSystem *fs) { HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; unsigned int map_sectors, i, j; int ret = 1; map_sectors = ( PED_BE32_TO_CPU (priv_data->vh->total_blocks) + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8); for (i = 0; i < map_sectors;) { for (j = i; (TST_BLOC_OCCUPATION(priv_data->dirty_alloc_map,j)); ++j) CLR_BLOC_OCCUPATION(priv_data->dirty_alloc_map,j); if (j-i) { ret = hfsplus_file_write(priv_data->allocation_file, priv_data->alloc_map + i * PED_SECTOR_SIZE_DEFAULT, i, j-i) && ret; i = j; } else ++i; } return ret; }
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; }
static int hfsplus_volume_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer) { uint8_t buf[PED_SECTOR_SIZE_DEFAULT]; unsigned int nblock, nfree, mblock; unsigned int block, to_free, old_blocks; HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*) fs->type_specific; HfsPVolumeHeader* vh = priv_data->vh; int resize = 1; unsigned int hfsp_sect_block = ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT ); unsigned int map_sectors; old_blocks = PED_BE32_TO_CPU (vh->total_blocks); /* Flush caches */ if (!ped_geometry_sync(priv_data->plus_geom)) return 0; /* Clear the unmounted bit */ /* and set the implementation code (Apple Creator Code) */ vh->attributes &= PED_CPU_TO_BE32 (~( 1 << HFS_UNMOUNTED )); vh->last_mounted_version = PED_CPU_TO_BE32(HFSP_IMPL_Shnk); if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1)) return 0; memcpy (buf, vh, sizeof (HfsPVolumeHeader)); if ( !ped_geometry_write (priv_data->plus_geom, buf, 2, 1) || !ped_geometry_sync (priv_data->plus_geom)) return 0; ped_timer_reset (timer); ped_timer_set_state_name(timer, _("shrinking")); ped_timer_update(timer, 0.0); /* relocate data */ to_free = ( priv_data->plus_geom->length - geom->length + hfsp_sect_block - 1 ) / hfsp_sect_block; block = hfsplus_find_start_pack (fs, to_free); if (!hfsplus_pack_free_space_from_block (fs, block, timer, to_free)) { resize = 0; ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Data relocation has failed.")); goto write_VH; } /* Calculate new block number and other VH field */ /* nblock must be rounded _down_ */ nblock = geom->length / hfsp_sect_block; nfree = PED_BE32_TO_CPU (vh->free_blocks) - (old_blocks - nblock); /* free block readjustement is only needed when incorrect nblock was used by my previous implementation, so detect the case */ if (priv_data->plus_geom->length < old_blocks * ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT) ) { if (priv_data->plus_geom->length % hfsp_sect_block == 1) nfree++; } /* Check that all block after future end are really free */ mblock = ( priv_data->plus_geom->length - 2 ) / hfsp_sect_block; if (mblock > old_blocks - 1) mblock = old_blocks - 1; for ( block = nblock; block < mblock; block++ ) { if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) { resize = 0; ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Data relocation left some data at the end " "of the volume.")); goto write_VH; } } /* Mark out of volume blocks as used */ map_sectors = ( ( old_blocks + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8) ) * (PED_SECTOR_SIZE_DEFAULT * 8); for ( block = nblock; block < map_sectors; ++block) SET_BLOC_OCCUPATION(priv_data->alloc_map, block); /* Update geometry */ if (resize) { /* update in fs structure */ if (PED_BE32_TO_CPU (vh->next_allocation) >= nblock) vh->next_allocation = PED_CPU_TO_BE32 (0); vh->total_blocks = PED_CPU_TO_BE32 (nblock); vh->free_blocks = PED_CPU_TO_BE32 (nfree); /* update parted structure */ priv_data->plus_geom->length = geom->length; priv_data->plus_geom->end = priv_data->plus_geom->start + geom->length - 1; } /* Effective write */ write_VH: /* lasts two sectors are allocated by the alternate VH and a reserved sector, and last block is always reserved */ block = (priv_data->plus_geom->length - 1) / hfsp_sect_block; if (block < PED_BE32_TO_CPU (vh->total_blocks)) SET_BLOC_OCCUPATION(priv_data->alloc_map, block); block = (priv_data->plus_geom->length - 2) / hfsp_sect_block; if (block < PED_BE32_TO_CPU (vh->total_blocks)) SET_BLOC_OCCUPATION(priv_data->alloc_map, block); SET_BLOC_OCCUPATION(priv_data->alloc_map, PED_BE32_TO_CPU (vh->total_blocks) - 1); /* Write the _old_ area to set out of volume blocks as used */ map_sectors = ( old_blocks + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8); if (!hfsplus_file_write (priv_data->allocation_file, priv_data->alloc_map, 0, map_sectors)) { resize = 0; ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Error while writing the allocation file.")); } else { /* Write remaining part of allocation bitmap */ /* This is necessary to handle pre patch-11 and third party */ /* implementations */ memset(buf, 0xFF, PED_SECTOR_SIZE_DEFAULT); for (block = map_sectors; block < priv_data->allocation_file->sect_nb; ++block) { if (!hfsplus_file_write_sector ( priv_data->allocation_file, buf, block)) { ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE, _("Error while writing the " "compatibility part of the " "allocation file.")); break; } } } ped_geometry_sync (priv_data->plus_geom); if (resize) { /* Set the unmounted bit and clear the inconsistent bit */ vh->attributes |= PED_CPU_TO_BE32 ( 1 << HFS_UNMOUNTED ); vh->attributes &= ~ PED_CPU_TO_BE32 ( 1 << HFSP_INCONSISTENT ); } ped_timer_set_state_name(timer, _("writing HFS+ Volume Header")); if (!hfsplus_update_vh(fs)) { ped_geometry_sync(priv_data->plus_geom); return 0; } if (!ped_geometry_sync(priv_data->plus_geom)) return 0; ped_timer_update(timer, 1.0); return (resize); }