int
hfsj_update_jl(PedFileSystem* fs, uint32_t block)
{
	uint8_t			buf[PED_SECTOR_SIZE_DEFAULT];
	PedSector		sector;
	uint64_t		offset;
	HfsPPrivateFSData* 	priv_data = (HfsPPrivateFSData*)
						    fs->type_specific;
	HfsJJournalInfoBlock*	jib;
	int			binsect;

	binsect = HFS_32_TO_CPU(priv_data->vh->block_size, is_le) / PED_SECTOR_SIZE_DEFAULT;
	sector = (PedSector) priv_data->jib_start_block * binsect;
	if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1))
		return 0;
	jib = (HfsJJournalInfoBlock*) buf;

	offset = (uint64_t)block * PED_SECTOR_SIZE_DEFAULT * binsect;
	jib->offset = HFS_CPU_TO_64(offset, is_le);

	if (!ped_geometry_write(priv_data->plus_geom, buf, sector, 1)
	    || !ped_geometry_sync(priv_data->plus_geom))
		return 0;

	priv_data->jl_start_block = block;
	return 1;
}
Beispiel #2
0
int
fat_write_sync_cluster (PedFileSystem* fs, char *buf, FatCluster cluster)
{
    if (!fat_write_cluster (fs, buf, cluster))
        return 0;
    if (!ped_geometry_sync (fs->geom))
        return 0;
    return 1;
}
Beispiel #3
0
int
fat_write_sync_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
                          FatFragment count)
{
    if (!fat_write_fragments (fs, buf, frag, count))
        return 0;
    if (!ped_geometry_sync (fs->geom))
        return 0;
    return 1;
}
Beispiel #4
0
int
fat_info_sector_write (const FatInfoSector* is, PedFileSystem *fs)
{
	FatSpecific*	fs_info = FAT_SPECIFIC (fs);

	PED_ASSERT (is != NULL);

	if (!ped_geometry_write (fs->geom, is, fs_info->info_sector_offset, 1))
		return 0;
	return ped_geometry_sync (fs->geom);
}
Beispiel #5
0
static int
write_root_dir (FatTraverseInfo* trav_info)
{
	FatSpecific*	fs_info = FAT_SPECIFIC (trav_info->fs);

	if (!ped_geometry_write (trav_info->fs->geom, trav_info->dir_entries,
				 fs_info->root_dir_offset,
				 fs_info->root_dir_sector_count))
		return 0;
	if (!ped_geometry_sync (trav_info->fs->geom))
		return 0;
	trav_info->dirty = 0;
	return 1;
}
Beispiel #6
0
/* So this is a non-issue */
static int
hfs_clobber (PedGeometry* geom)
{
	uint8_t	buf[PED_SECTOR_SIZE_DEFAULT];

	memset (buf, 0, PED_SECTOR_SIZE_DEFAULT);

	/* destroy boot blocks, mdb, alternate mdb ... */
	return	(!!ped_geometry_write (geom, buf, 0, 1)) &
		(!!ped_geometry_write (geom, buf, 1, 1)) &
		(!!ped_geometry_write (geom, buf, 2, 1)) &
		(!!ped_geometry_write (geom, buf, geom->length - 2, 1)) &
		(!!ped_geometry_write (geom, buf, geom->length - 1, 1)) &
		(!!ped_geometry_sync  (geom));
}
Beispiel #7
0
static int reiserfs_close(PedFileSystem *fs)
{
	dal_t *dal;

	PED_ASSERT(fs != NULL);

	dal = reiserfs_fs_host_dal(fs->type_specific);
	reiserfs_fs_close(fs->type_specific);

	geom_dal_free(dal);
	ped_geometry_sync(fs->geom);

	free(fs);
	return 1;
}
Beispiel #8
0
int
fat_boot_sector_write (const FatBootSector* bs, PedFileSystem* fs)
{
	FatSpecific*	fs_info = FAT_SPECIFIC (fs);

	PED_ASSERT (bs != NULL);

	if (!ped_geometry_write (fs->geom, bs, 0, 1))
		return 0;
	if (fs_info->fat_type == FAT_TYPE_FAT32) {
		if (!ped_geometry_write (fs->geom, bs,
					 fs_info->boot_sector_backup_offset, 1))
			return 0;
	}
	return ped_geometry_sync (fs->geom);
}
Beispiel #9
0
PyObject *py_ped_geometry_sync(PyObject *s, PyObject *args) {
    int ret = -1;
    PedGeometry *geom = NULL;

    geom = _ped_Geometry2PedGeometry(s);
    if (geom == NULL) {
        return NULL;
    }

    ret = ped_geometry_sync(geom);
    if (ret == 0) {
        PyErr_SetString(IOException, "Could not sync");
        return NULL;
    }

    if (ret) {
        Py_RETURN_TRUE;
    } else {
        Py_RETURN_FALSE;
    }
}
/* 1 => Success, the journal has been completly replayed, or don't need to */
int
hfsj_replay_journal(PedFileSystem* fs)
{
	uint8_t			buf[PED_SECTOR_SIZE_DEFAULT];
	PedSector		sector, length;
	HfsPPrivateFSData* 	priv_data = (HfsPPrivateFSData*)
						    fs->type_specific;
	HfsJJournalInfoBlock*	jib;
	HfsJJournalHeader*	jh;
	int			binsect;
	uint32_t		cksum;

	binsect = PED_BE32_TO_CPU(priv_data->vh->block_size) / PED_SECTOR_SIZE_DEFAULT;
	priv_data->jib_start_block =
		PED_BE32_TO_CPU(priv_data->vh->journal_info_block);
	sector  = (PedSector) priv_data->jib_start_block * binsect;
	if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1))
		return 0;
	jib = (HfsJJournalInfoBlock*) buf;

	if (    (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_IN_FS))
	    && !(jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_OTHER_DEV)) ) {
		priv_data->jl_start_block = HFS_64_TO_CPU(jib->offset, is_le)
					    / ( PED_SECTOR_SIZE_DEFAULT * binsect );
	}

	if (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_NEED_INIT))
		return 1;

	if (  !(jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_IN_FS))
	    || (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_OTHER_DEV)) ) {
		ped_exception_throw (
			PED_EXCEPTION_NO_FEATURE,
			PED_EXCEPTION_CANCEL,
			_("Journal stored outside of the volume are "
			  "not supported.  Try to desactivate the "
			  "journal and run Parted again."));
		return 0;
	}

	if (   (PED_BE64_TO_CPU(jib->offset) % PED_SECTOR_SIZE_DEFAULT)
	    || (PED_BE64_TO_CPU(jib->size)   % PED_SECTOR_SIZE_DEFAULT) ) {
		ped_exception_throw (
			PED_EXCEPTION_NO_FEATURE,
			PED_EXCEPTION_CANCEL,
			_("Journal offset or size is not multiple of "
			  "the sector size."));
		return 0;
	}

	sector = PED_BE64_TO_CPU(jib->offset) / PED_SECTOR_SIZE_DEFAULT;
	length = PED_BE64_TO_CPU(jib->size)   / PED_SECTOR_SIZE_DEFAULT;

	jib = NULL;
	if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1))
		return 0;
	jh = (HfsJJournalHeader*) buf;

	if (jh->endian == PED_LE32_TO_CPU(HFSJ_ENDIAN_MAGIC))
	    is_le = 1;

	if (   (jh->magic  != HFS_32_TO_CPU(HFSJ_HEADER_MAGIC, is_le))
	    || (jh->endian != HFS_32_TO_CPU(HFSJ_ENDIAN_MAGIC, is_le)) ) {
		ped_exception_throw (
			PED_EXCEPTION_ERROR,
			PED_EXCEPTION_CANCEL,
			_("Incorrect magic values in the journal header."));
		return 0;
	}

	if ( (HFS_64_TO_CPU(jh->size, is_le)%PED_SECTOR_SIZE_DEFAULT)
	  || (HFS_64_TO_CPU(jh->size, is_le)/PED_SECTOR_SIZE_DEFAULT
		  != (uint64_t)length) ) {
		ped_exception_throw (
			PED_EXCEPTION_ERROR,
			PED_EXCEPTION_CANCEL,
			_("Journal size mismatch between journal info block "
			  "and journal header."));
		return 0;
	}

	if (   (HFS_64_TO_CPU(jh->start, is_le) % PED_SECTOR_SIZE_DEFAULT)
	    || (HFS_64_TO_CPU(jh->end, is_le)   % PED_SECTOR_SIZE_DEFAULT)
	    || (HFS_32_TO_CPU(jh->blhdr_size, is_le) % PED_SECTOR_SIZE_DEFAULT)
	    || (HFS_32_TO_CPU(jh->jhdr_size, is_le)  % PED_SECTOR_SIZE_DEFAULT) ) {
		ped_exception_throw (
			PED_EXCEPTION_ERROR,
			PED_EXCEPTION_CANCEL,
			_("Some header fields are not multiple of the sector "
			  "size."));
		return 0;
	}

	if (HFS_32_TO_CPU(jh->jhdr_size, is_le) != PED_SECTOR_SIZE_DEFAULT) {
		ped_exception_throw (
			PED_EXCEPTION_ERROR,
			PED_EXCEPTION_CANCEL,
			_("The sector size stored in the journal is not 512 "
			  "bytes.  Parted only supports 512 bytes length "
			  "sectors."));
		return 0;
	}

	cksum = HFS_32_TO_CPU(jh->checksum, is_le);
	jh->checksum = 0;
	if (cksum != hfsj_calc_checksum((uint8_t*)jh, sizeof(*jh))) {
		ped_exception_throw (
			PED_EXCEPTION_ERROR,
			PED_EXCEPTION_CANCEL,
			_("Bad journal checksum."));
		return 0;
	}
	jh->checksum = HFS_CPU_TO_32(cksum, is_le);

	/* The 2 following test are in the XNU Darwin source code */
	/* so I assume they're needed */
	if (jh->start == jh->size)
		jh->start = HFS_CPU_TO_64(PED_SECTOR_SIZE_DEFAULT, is_le);
	if (jh->end   == jh->size)
		jh->start = HFS_CPU_TO_64(PED_SECTOR_SIZE_DEFAULT, is_le);

	if (jh->start == jh->end)
		return 1;

	if (ped_exception_throw (
		PED_EXCEPTION_WARNING,
		PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL,
		_("The journal is not empty.  Parted must replay the "
		  "transactions before opening the file system.  This will "
		  "modify the file system."))
			!= PED_EXCEPTION_FIX)
		return 0;

	while (jh->start != jh->end) {
		/* Replay one complete transaction */
		if (!hfsj_replay_transaction(fs, jh, sector, length))
			return 0;

		/* Recalculate cksum of the journal header */
		jh->checksum = 0; /* need to be 0 while calculating the cksum */
		cksum = hfsj_calc_checksum((uint8_t*)jh, sizeof(*jh));
		jh->checksum = HFS_CPU_TO_32(cksum, is_le);

		/* Update the Journal Header */
		if (!ped_geometry_write(priv_data->plus_geom, buf, sector, 1)
		    || !ped_geometry_sync(priv_data->plus_geom))
			return 0;
	}

	if (hfsj_vh_replayed) {
		/* probe could have reported incorrect info ! */
		/* is there a way to ask parted to quit ? */
		ped_exception_throw(
			PED_EXCEPTION_WARNING,
			PED_EXCEPTION_OK,
			_("The volume header or the master directory block has "
			  "changed while replaying the journal.  You should "
			  "restart Parted."));
		return 0;
	}

	return 1;
}
static int
hfsj_replay_transaction(PedFileSystem* fs, HfsJJournalHeader* jh,
			PedSector jsector, PedSector jlength)
{
	PedSector		start, sector;
	HfsPPrivateFSData* 	priv_data = (HfsPPrivateFSData*)
						fs->type_specific;
	HfsJBlockListHeader*	blhdr;
	uint8_t*		block;
	unsigned int		blhdr_nbsect;
	int			i, r;
	uint32_t		cksum, size;

	blhdr_nbsect = HFS_32_TO_CPU(jh->blhdr_size, is_le) / PED_SECTOR_SIZE_DEFAULT;
	blhdr = (HfsJBlockListHeader*)
		  ped_malloc (blhdr_nbsect * PED_SECTOR_SIZE_DEFAULT);
	if (!blhdr) return 0;

	start = HFS_64_TO_CPU(jh->start, is_le) / PED_SECTOR_SIZE_DEFAULT;
	do {
		start = hfsj_journal_read(priv_data->plus_geom, jh, jsector,
					  jlength, start, blhdr_nbsect, blhdr);
		if (!start) goto err_replay;

		cksum = HFS_32_TO_CPU(blhdr->checksum, is_le);
		blhdr->checksum = 0;
		if (cksum!=hfsj_calc_checksum((uint8_t*)blhdr, sizeof(*blhdr))){
			ped_exception_throw (
				PED_EXCEPTION_ERROR,
				PED_EXCEPTION_CANCEL,
				_("Bad block list header checksum."));
			goto err_replay;
		}
		blhdr->checksum = HFS_CPU_TO_32(cksum, is_le);

		for (i=1; i < HFS_16_TO_CPU(blhdr->num_blocks, is_le); ++i) {
			size = HFS_32_TO_CPU(blhdr->binfo[i].bsize, is_le);
			sector = HFS_64_TO_CPU(blhdr->binfo[i].bnum, is_le);
			if (!size) continue;
			if (size % PED_SECTOR_SIZE_DEFAULT) {
				ped_exception_throw(
					PED_EXCEPTION_ERROR,
					PED_EXCEPTION_CANCEL,
					_("Invalid size of a transaction "
					  "block while replaying the journal "
					  "(%i bytes)."),
					size);
				goto err_replay;
			}
			block = (uint8_t*) ped_malloc(size);
			if (!block) goto err_replay;
			start = hfsj_journal_read(priv_data->plus_geom, jh,
						  jsector, jlength, start,
						  size / PED_SECTOR_SIZE_DEFAULT,
						  block);
			if (!start) {
				free (block);
				goto err_replay;
			}
			/* the sector stored in the journal seems to be
			   relative to the begin of the block device which
			   contains the hfs+ journaled volume */
			if (sector != ~0LL)
				r = ped_geometry_write (fs->geom, block, sector,
							size / PED_SECTOR_SIZE_DEFAULT);
			else
				r = 1;
			free (block);
			/* check if wrapper mdb or vh with no wrapper has
			   changed */
			if (   (sector != ~0LL)
			    && (2 >= sector)
			    && (2 < sector + size / PED_SECTOR_SIZE_DEFAULT) )
				hfsj_vh_replayed = 1;
			/* check if vh of embedded hfs+ has changed */
			if (   (sector != ~0LL)
			    && (priv_data->plus_geom != fs->geom)
			    && (sector
			        + fs->geom->start
				- priv_data->plus_geom->start <= 2)
			    && (sector
			        + size / PED_SECTOR_SIZE_DEFAULT
				+ fs->geom->start
				- priv_data->plus_geom->start > 2) )
				hfsj_vh_replayed = 1;
			if (!r) goto err_replay;
		}
	} while (blhdr->binfo[0].next);

	jh->start = HFS_CPU_TO_64(start * PED_SECTOR_SIZE_DEFAULT, is_le);

	free (blhdr);
	return (ped_geometry_sync (fs->geom));

err_replay:
	free (blhdr);
	return 0;
}
Beispiel #12
0
/* 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;
}
Beispiel #13
0
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);
}
Beispiel #14
0
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);
}