Example #1
0
/* 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;
}
Example #2
0
/* -1 is ok because there can only be 2^32-1 blocks, so the max possible
   last one is 2^32-2 (and anyway it contains Alternate VH), so
   -1 (== 2^32-1[2^32]) never represent a valid block */
static int
hfsplus_effect_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock,
			    unsigned int *ptr_to_fblock, unsigned int size)
{
	HfsPPrivateFSData* 	priv_data = (HfsPPrivateFSData*)
						fs->type_specific;
	unsigned int		i, ok = 0;
	unsigned int		next_to_fblock;
	unsigned int		start, stop;

	PED_ASSERT (hfsp_block != NULL);
	PED_ASSERT (*ptr_to_fblock <= *ptr_fblock);
	/* quiet GCC */
	start = stop = 0;

/*
	Try to fit the extent AT or _BEFORE_ the wanted place,
	or then in the gap between dest and source.
	If failed try to fit the extent after source, for 2 pass relocation
	The extent is always copied in a non overlapping way
*/

	/* Backward search */
	/* 1 pass relocation AT or BEFORE *ptr_to_fblock */
	if (*ptr_to_fblock != *ptr_fblock) {
		start = stop = *ptr_fblock < *ptr_to_fblock+size ?
			       *ptr_fblock : *ptr_to_fblock+size;
		while (start && stop-start != size) {
			--start;
			if (TST_BLOC_OCCUPATION(priv_data->alloc_map,start))
				stop = start;
		}
		ok = (stop-start == size);
	}

	/* Forward search */
	/* 1 pass relocation in the gap merged with 2 pass reloc after source */
	if (!ok && *ptr_to_fblock != *ptr_fblock) {
		start = stop = *ptr_to_fblock+1;
		while (stop < PED_BE32_TO_CPU(priv_data->vh->total_blocks)
		       && stop-start != size) {
			if (TST_BLOC_OCCUPATION(priv_data->alloc_map,stop))
				start = stop + 1;
			++stop;
		}
		ok = (stop-start == size);
	}

	/* new non overlapping room has been found ? */
	if (ok) {
		/* enough room */
		PedSector	abs_sector;
		unsigned int	ai, j, block;
		unsigned int 	block_sz = (PED_BE32_TO_CPU (
					priv_data->vh->block_size)
					/ PED_SECTOR_SIZE_DEFAULT);

		if (stop > *ptr_to_fblock && stop <= *ptr_fblock)
			/* Fit in the gap */
			next_to_fblock = stop;
		else
			/* Before or after the gap */
			next_to_fblock = *ptr_to_fblock;

		/* move blocks */
		for (i = 0; i < size; /*i++*/) {
			j = size - i; j = (j < hfsp_block_count) ?
					   j : hfsp_block_count ;

			abs_sector = (PedSector) (*ptr_fblock + i) * block_sz;
			if (!ped_geometry_read (priv_data->plus_geom,
						hfsp_block, abs_sector,
						block_sz * j))
				return -1;

			abs_sector = (PedSector) (start + i) * block_sz;
			if (!ped_geometry_write (priv_data->plus_geom,
						 hfsp_block, abs_sector,
						 block_sz * j))
				return -1;

			for (ai = i+j; i < ai; i++) {
				/* free source block */
				block = *ptr_fblock + i;
				CLR_BLOC_OCCUPATION(priv_data->alloc_map,block);
				SET_BLOC_OCCUPATION(priv_data->dirty_alloc_map,
						    block/(PED_SECTOR_SIZE_DEFAULT*8));

				/* set dest block */
				block = start + i;
				SET_BLOC_OCCUPATION(priv_data->alloc_map,block);
				SET_BLOC_OCCUPATION(priv_data->dirty_alloc_map,
						    block/(PED_SECTOR_SIZE_DEFAULT*8));
			}
		}
		if (!ped_geometry_sync_fast (priv_data->plus_geom))
			return -1;

		*ptr_fblock += size;
		*ptr_to_fblock = next_to_fblock;
	} else {
		if (*ptr_fblock != *ptr_to_fblock)
			/* not enough room */
			ped_exception_throw (PED_EXCEPTION_WARNING,
			      PED_EXCEPTION_IGNORE,
			      _("An extent has not been relocated."));
		start = *ptr_fblock;
		*ptr_fblock = *ptr_to_fblock = start + size;
	}

	return start;
}
Example #3
0
File: hfs.c Project: Excito/parted
/* Update the HFS wrapper mdb and bad blocks file to reflect
   the new geometry of the embedded HFS+ volume */
static int
hfsplus_wrapper_update (PedFileSystem* fs)
{
	uint8_t			node[PED_SECTOR_SIZE_DEFAULT];
	HfsCPrivateLeafRec	ref;
	HfsExtentKey		key;
	HfsNodeDescriptor*	node_desc = (HfsNodeDescriptor*) node;
	HfsExtentKey*		ret_key;
	HfsExtDescriptor*	ret_data;
	unsigned int		i;
	HfsPPrivateFSData* 	priv_data = (HfsPPrivateFSData*)
						fs->type_specific;
	HfsPrivateFSData* 	hfs_priv_data = (HfsPrivateFSData*)
					    priv_data->wrapper->type_specific;
	unsigned int		hfs_sect_block =
			PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
			/ PED_SECTOR_SIZE_DEFAULT ;
	PedSector		hfsplus_sect = (PedSector)
			PED_BE32_TO_CPU (priv_data->vh->total_blocks)
			* ( PED_BE32_TO_CPU (priv_data->vh->block_size)
			    / PED_SECTOR_SIZE_DEFAULT );
	unsigned int		hfs_blocks_embedded =
				    (hfsplus_sect + hfs_sect_block - 1)
				    / hfs_sect_block;
	unsigned int		hfs_blocks_embedded_old;

	/* update HFS wrapper MDB */
	hfs_blocks_embedded_old = PED_BE16_TO_CPU (
					hfs_priv_data->mdb->old_new
					.embedded.location.block_count );
	hfs_priv_data->mdb->old_new.embedded.location.block_count =
		PED_CPU_TO_BE16 (hfs_blocks_embedded);
	/* maybe macOS will boot with this */
	/* update : yes it does \o/ :) */
	hfs_priv_data->mdb->free_blocks =
	    PED_CPU_TO_BE16 ( PED_BE16_TO_CPU (hfs_priv_data->mdb->free_blocks)
	                    + hfs_blocks_embedded_old
			    - hfs_blocks_embedded );

	if (!hfs_update_mdb(priv_data->wrapper))
		return 0;

	/* force reload bad block list */
	if (hfs_priv_data->bad_blocks_loaded) {
		hfs_free_bad_blocks_list (hfs_priv_data->bad_blocks_xtent_list);
		hfs_priv_data->bad_blocks_xtent_list = NULL;
		hfs_priv_data->bad_blocks_xtent_nb = 0;
		hfs_priv_data->bad_blocks_loaded = 0;
	}

	/* clean HFS wrapper allocation map */
	for (i = PED_BE16_TO_CPU (
			hfs_priv_data->mdb->old_new.embedded
			.location.start_block )
		 + hfs_blocks_embedded;
	     i < PED_BE16_TO_CPU (
	    		hfs_priv_data->mdb->old_new.embedded
			.location.start_block )
		 + hfs_blocks_embedded_old;
	     i++ ) {
		CLR_BLOC_OCCUPATION(hfs_priv_data->alloc_map, i);
	}
	/* and save it */
	if (!ped_geometry_write (fs->geom, hfs_priv_data->alloc_map,
				 PED_BE16_TO_CPU (
				      hfs_priv_data->mdb->volume_bitmap_block ),
				 ( PED_BE16_TO_CPU (
				        hfs_priv_data->mdb->total_blocks )
				   + PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
				 / (PED_SECTOR_SIZE_DEFAULT * 8)))
		return 0;
	if (!ped_geometry_sync (fs->geom))
		return 0;

	/* search and update the bad blocks file */
	key.key_length = sizeof(key) - 1;
	key.type = HFS_DATA_FORK;
	key.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID);
	key.start = 0;
	if (!hfs_btree_search (hfs_priv_data->extent_file,
			       (HfsPrivateGenericKey*) &key, NULL, 0, &ref)) {
		ped_exception_throw (
			PED_EXCEPTION_ERROR,
			PED_EXCEPTION_CANCEL,
			_("An error occurred while looking for the mandatory "
			  "bad blocks file."));
		return 0;
	}
	if (!hfs_file_read_sector (hfs_priv_data->extent_file, node,
				   ref.node_number))
		return 0;
	ret_key = (HfsExtentKey*) (node + ref.record_pos);
	ret_data = (HfsExtDescriptor*) ( node + ref.record_pos
					 + sizeof (HfsExtentKey) );

	while (ret_key->type == key.type && ret_key->file_ID == key.file_ID) {
		for (i = 0; i < HFS_EXT_NB; i++) {
			if ( ret_data[i].start_block
			     == hfs_priv_data->mdb->old_new
			        .embedded.location.start_block) {
				ret_data[i].block_count =
				    hfs_priv_data->mdb->old_new
				    .embedded.location.block_count;
				/* found ! : update */
				if (!hfs_file_write_sector (
					  hfs_priv_data->extent_file,
					  node, ref.node_number)
				    || !ped_geometry_sync(fs->geom))
					return 0;
				return 1;
			}
		}

		if (ref.record_number < PED_BE16_TO_CPU (node_desc->rec_nb)) {
			ref.record_number++;
		} else {
			ref.node_number = PED_BE32_TO_CPU (node_desc->next);
			if (!ref.node_number
			    || !hfs_file_read_sector(hfs_priv_data->extent_file,
						     node, ref.node_number))
				goto bb_not_found;
			ref.record_number = 1;
		}

		ref.record_pos =
			PED_BE16_TO_CPU (*((uint16_t *)
				(node + (PED_SECTOR_SIZE_DEFAULT
				         - 2*ref.record_number))));
		ret_key = (HfsExtentKey*) (node + ref.record_pos);
		ret_data = (HfsExtDescriptor*) ( node + ref.record_pos
						 + sizeof (HfsExtentKey) );
	}

bb_not_found:
	/* not found : not a valid hfs+ wrapper : failure */
	ped_exception_throw (
		PED_EXCEPTION_ERROR,
		PED_EXCEPTION_CANCEL,
		_("It seems there is an error in the HFS wrapper: the bad "
		  "blocks file doesn't contain the embedded HFS+ volume."));
	return 0;
}