reloc_plus.c revision 7e7bd3dccbfe8f79e25e5c1554b5bc3a9aaca321
/*
libparted - a library for manipulating disk partitions
Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DISCOVER_ONLY
#include <config.h>
#include <stdint.h>
#if ENABLE_NLS
# include <libintl.h>
#else
#endif /* ENABLE_NLS */
#include "hfs.h"
#include "file_plus.h"
#include "advfs_plus.h"
#include "cache.h"
#include "journal.h"
#include "reloc_plus.h"
/* This function moves data of size blocks starting at block *ptr_fblock
to block *ptr_to_fblock */
/* return new start or -1 on failure */
/* -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
unsigned int *ptr_to_fblock, unsigned int size)
{
unsigned int i, ok = 0;
unsigned int next_to_fblock;
/* quiet GCC */
/*
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;
}
}
/* Forward search */
/* 1 pass relocation in the gap merged with 2 pass reloc after source */
++stop;
}
}
/* new non overlapping room has been found ? */
if (ok) {
/* enough room */
unsigned int block_sz = (PED_BE32_TO_CPU (
/* Fit in the gap */
else
/* Before or after the gap */
/* move blocks */
for (i = 0; i < size; /*i++*/) {
j = size - i; j = (j < hfsp_block_count) ?
j : hfsp_block_count ;
block_sz * j))
return -1;
block_sz * j))
return -1;
/* free source block */
block = *ptr_fblock + i;
/* set dest block */
}
}
return -1;
*ptr_fblock += size;
} else {
if (*ptr_fblock != *ptr_to_fblock)
/* not enough room */
_("An extent has not been relocated."));
start = *ptr_fblock;
}
return start;
}
/* Returns 0 on error */
/* 1 on succes */
int
{
return 0;
return 0;
return 1;
}
static int
{
int new_start;
ref->ext_length);
/************ VH ************/
case CR_PRIM_CAT :
goto CR_PRIM;
case CR_PRIM_EXT :
goto CR_PRIM;
case CR_PRIM_ATTR :
goto CR_PRIM;
case CR_PRIM_ALLOC :
goto CR_PRIM;
case CR_PRIM_START :
/* No startup file opened */
CR_PRIM :
extent = ( HfsPExtDescriptor* )
if (!hfsplus_update_vh(fs))
return -1;
break;
/************** BTREE *************/
case CR_BTREE_CAT_JIB :
return -1;
goto BTREE_CAT;
case CR_BTREE_CAT_JL :
return -1;
goto BTREE_CAT;
case CR_BTREE_CAT :
goto CR_BTREE;
case CR_BTREE_ATTR :
goto CR_BTREE;
case CR_BTREE_EXT_ATTR :
if (priv_data->attributes_file
goto CR_BTREE_EXT;
case CR_BTREE_EXT_CAT :
if (priv_data->catalog_file
goto CR_BTREE_EXT;
case CR_BTREE_EXT_ALLOC :
if (priv_data->allocation_file
goto CR_BTREE_EXT;
case CR_BTREE_EXT_START :
/* No startup file opened */
case CR_BTREE_EXT_0 :
CR_BTREE :
ref->sect_by_block))
return -1;
extent = ( HfsPExtDescriptor* )
return -1;
break;
/********** BUG *********/
default :
_("A reference to an extent comes from a place "
"it should not. You should check the file "
"system!"));
return -1;
break;
}
if (!move) return -1;
}
return new_start;
}
/* save any dirty sector of the allocation bitmap file */
static int
{
unsigned int map_sectors, i, j;
int ret = 1;
for (i = 0; i < map_sectors;) {
for (j = i;
++j)
if (j-i) {
i, j-i) && ret;
i = j;
} else
++i;
}
return ret;
}
/* This function moves an extent starting at block fblock
to block to_fblock if there's enough room */
/* Return 1 if everything was fine */
/* Return -1 if an error occurred */
/* Return 0 if no extent was found */
static int
unsigned int *ptr_to_fblock,
{
if (!ref) return 0;
old_start = *ptr_fblock;
return -1;
}
return 1;
}
static int
{
unsigned int j;
for (j = 0; j < HFSP_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
0, /* unused for vh */
1, /* load / save 1 sector */
j )
)
return 0;
}
for (j = 0; j < HFSP_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
0, /* unused for vh */
1, /* load / save 1 sector */
j )
)
return 0;
}
for (j = 0; j < HFSP_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
0, /* unused for vh */
1, /* load / save 1 sector */
j )
)
return 0;
}
for (j = 0; j < HFSP_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
0, /* unused for vh */
1, /* load / save 1 sector */
j )
)
return 0;
}
for (j = 0; j < HFSP_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
0, /* unused for vh */
1, /* load / save 1 sector */
j )
)
return 0;
}
return 1;
}
static int
{
unsigned int leaf_node, record_number;
_("This HFS+ volume has no catalog file. "
"This is very unusual!"));
return 1;
}
/* Search the extent starting at *ptr_block in the catalog file */
return 0;
if (!node) return 0;
return 0;
}
for (i = 1; i <= record_number; i++) {
unsigned int skip;
+ 1) & ~1;
catalog_data = (HfsPCatalog*)
/* check for obvious error in FS */
>= (signed) bsize
_("The file system contains errors."));
return 0;
}
continue;
for (j = 0; j < HFSP_EXT_NB; ++j) {
if (!extent[j].block_count) break;
== jib ) {
jib = 0;
} else
== jl ) {
jl = 0;
}
if (!hfsc_cache_add_extent(
size,
j )
) {
return 0;
}
}
for (j = 0; j < HFSP_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
size,
j )
) {
return 0;
}
}
}
}
return 1;
}
static int
{
unsigned int leaf_node, record_number;
_("This HFS+ volume has no extents overflow "
"file. This is quite unusual!"));
return 1;
}
return 0;
if (!node) return -1;
return 0;
}
for (i = 1; i <= record_number; i++) {
extent_key = (HfsPExtentKey*)
extent = (HfsPExtDescriptor*)
/* check for obvious error in FS */
>= (signed)bsize
_("The file system contains errors."));
return -1;
}
switch (extent_key->file_ID) {
case PED_CPU_TO_BE32 (HFS_XTENT_ID) :
if (ped_exception_throw (
_("The extents overflow file should not"
" contain its own extents! You should "
"check the file system."))
return 0;
break;
case PED_CPU_TO_BE32 (HFS_CATALOG_ID) :
break;
case PED_CPU_TO_BE32 (HFSP_ALLOC_ID) :
break;
case PED_CPU_TO_BE32 (HFSP_STARTUP_ID) :
break;
case PED_CPU_TO_BE32 (HFSP_ATTRIB_ID) :
break;
default :
break;
}
for (j = 0; j < HFSP_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
size,
j )
) {
return 0;
}
}
}
}
return 1;
}
static int
{
unsigned int leaf_node, record_number;
/* attributes file is facultative */
return 1;
/* Search the extent starting at *ptr_block in the catalog file */
return 0;
if (!node) return 0;
return 0;
}
for (i = 1; i <= record_number; i++) {
unsigned int skip;
+ 1 ) & ~1;
/* check for obvious error in FS */
>= (signed) bsize
_("The file system contains errors."));
return 0;
}
if (fork_ext_data->record_type
== PED_CPU_TO_BE32 ( HFSP_ATTR_FORK ) ) {
for (j = 0; j < HFSP_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
extent[j].start_block ),
extent[j].block_count ),
size,
j )
) {
return 0;
}
}
} else if (fork_ext_data->record_type
== PED_CPU_TO_BE32 ( HFSP_ATTR_EXTENTS ) ) {
for (j = 0; j < HFSP_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
extent[j].start_block ),
extent[j].block_count ),
size,
j )
) {
return 0;
}
}
} else continue;
}
}
return 1;
}
static HfsCPrivateCache*
{
unsigned int file_number, block_number;
_("Could not cache the file system in memory."));
return NULL;
}
return ret;
}
/* This function moves file's data to compact used and free space,
starting at fblock block */
/* return 0 on error */
int
{
int ret;
PED_ASSERT (!hfsp_block, return 0);
if (!cache)
return 0;
/* Calculate the size of the copy buffer :
* Takes BLOCK_MAX_BUFF HFS blocks, but if > BYTES_MAX_BUFF
* takes the maximum number of HFS blocks so that the buffer
* will remain smaller than or equal to BYTES_MAX_BUFF, with
* a minimum of 1 HFS block */
* (PedSector) BLOCK_MAX_BUFF;
if (bytes_buff > BYTES_MAX_BUFF) {
if (!hfsp_block_count)
hfsp_block_count = 1;
} else
/* If the cache code requests more space, give it to him */
if (!hfsp_block)
goto error_cache;
if (!hfsplus_read_bad_blocks (fs)) {
_("Bad blocks list could not be loaded."));
goto error_alloc;
}
/ PED_SECTOR_SIZE_DEFAULT ) ) {
else if (ret == -1) {
_("An error occurred during extent "
"relocation."));
goto error_alloc;
}
} else {
fblock++;
}
}
return 1;
return 0;
}
#endif /* !DISCOVER_ONLY */