コード例 #1
0
ファイル: hfs.c プロジェクト: Excito/parted
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);
}
コード例 #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;
}
コード例 #3
0
ファイル: hfs.c プロジェクト: Excito/parted
int
hfs_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
{
	uint8_t			buf[PED_SECTOR_SIZE_DEFAULT];
	unsigned int		nblock, nfree;
	unsigned int		block, to_free;
	HfsPrivateFSData* 	priv_data;
	HfsMasterDirectoryBlock* mdb;
	int			resize = 1;
	unsigned int		hfs_sect_block;
	PedSector		hgee;

	/* check preconditions */
	PED_ASSERT (fs != NULL);
	PED_ASSERT (fs->geom != NULL);
	PED_ASSERT (geom != NULL);
#ifdef DEBUG
        PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0);
#else
        if ((hgee = hfs_get_empty_end(fs)) == 0)
                return 0;
#endif

	PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0);

	if (ped_geometry_test_equal(fs->geom, geom))
		return 1;

	priv_data = (HfsPrivateFSData*) fs->type_specific;
	mdb = priv_data->mdb;
	hfs_sect_block = PED_BE32_TO_CPU (mdb->block_size)
			 / PED_SECTOR_SIZE_DEFAULT;

	if (fs->geom->start != geom->start
	    || geom->length > fs->geom->length
	    || geom->length < hgee + 2) {
		ped_exception_throw (
			PED_EXCEPTION_NO_FEATURE,
			PED_EXCEPTION_CANCEL,
			_("Sorry, HFS cannot be resized that way yet."));
		return 0;
	}

	/* Flush caches */
	if (!ped_geometry_sync(fs->geom))
		return 0;

	/* Clear the unmounted bit */
	mdb->volume_attributes &= PED_CPU_TO_BE16 (~( 1 << HFS_UNMOUNTED ));
	if (!ped_geometry_read (fs->geom, buf, 2, 1))
		return 0;
	memcpy (buf, mdb, sizeof (HfsMasterDirectoryBlock));
	if (   !ped_geometry_write (fs->geom, buf, 2, 1)
	    || !ped_geometry_sync  (fs->geom))
		return 0;

	ped_timer_reset (timer);
	ped_timer_set_state_name(timer, _("shrinking"));
	ped_timer_update(timer, 0.0);
	/* relocate data */
	to_free = ( fs->geom->length - geom->length
		    + hfs_sect_block - 1 )
		  / hfs_sect_block ;
	block = hfs_find_start_pack (fs, to_free);
	if (!hfs_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_MDB;
	}

	/* Calculate new block number and other MDB field */
	nblock = ( geom->length - (PED_BE16_TO_CPU (mdb->start_block) + 2) )
		 / hfs_sect_block;
	nfree = PED_BE16_TO_CPU (mdb->free_blocks)
		- ( PED_BE16_TO_CPU (mdb->total_blocks) - nblock );

	/* Check that all block after future end are really free */
	for (block = nblock;
	     block < PED_BE16_TO_CPU (mdb->total_blocks);
	     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 in the end "
				  "of the volume."));
			goto write_MDB;
		}
	}

	/* Mark out of volume blocks as used
	(broken implementations compatibility) */
	for ( block = nblock; block < (1 << 16); ++block)
		SET_BLOC_OCCUPATION(priv_data->alloc_map,block);

	/* save the allocation map
	I do not write until start of allocation blocks
	but only until pre-resize end of bitmap blocks
	because the specifications do _not_ assert that everything
	until allocation blocks is boot, mdb and alloc */
	ped_geometry_write(fs->geom, priv_data->alloc_map,
		PED_BE16_TO_CPU (priv_data->mdb->volume_bitmap_block),
		( PED_BE16_TO_CPU (priv_data->mdb->total_blocks)
		  + PED_SECTOR_SIZE_DEFAULT * 8 - 1)
		/ (PED_SECTOR_SIZE_DEFAULT * 8));

	/* Update geometry */
	if (resize) {
		/* update in fs structure */
		if (PED_BE16_TO_CPU (mdb->next_allocation) >= nblock)
			mdb->next_allocation = PED_CPU_TO_BE16 (0);
		mdb->total_blocks = PED_CPU_TO_BE16 (nblock);
		mdb->free_blocks = PED_CPU_TO_BE16 (nfree);
		/* update parted structure */
		fs->geom->length = geom->length;
		fs->geom->end = fs->geom->start + geom->length - 1;
	}

	/* Set the unmounted bit */
	mdb->volume_attributes |= PED_CPU_TO_BE16 ( 1 << HFS_UNMOUNTED );

	/* Effective write */
    write_MDB:
	ped_timer_set_state_name(timer,_("writing HFS Master Directory Block"));

	if (!hfs_update_mdb(fs)) {
		ped_geometry_sync(geom);
		return 0;
	}

	if (!ped_geometry_sync(geom))
		return 0;

	ped_timer_update(timer, 1.0);

	return (resize);
}