reloc.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.h"
#include "advfs.h"
#include "cache.h"
#include "reloc.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 */
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 j;
unsigned int start_block =
unsigned int block_sz =
/* Fit in the gap */
else
/* Before or after the gap */
/* move blocks */
for (i = 0; i < size; /*i+=j*/) {
unsigned int ai;
j = size - i; j = (j < hfs_block_count) ?
j : hfs_block_count ;
block_sz * j))
return -1;
block_sz * j))
return -1;
/* free source block */
*ptr_fblock + i);
/* set dest block */
start + i);
}
}
return -1;
*ptr_fblock += size;
} else {
if (*ptr_fblock != *ptr_to_fblock)
/* not enough room, but try to continue */
_("An extent has not been relocated."));
start = *ptr_fblock;
}
return start;
}
/* Update MDB */
/* Return 0 if an error occurred */
/* Return 1 if everything ok */
int
{
return 0;
return 0;
return 1;
}
/* Generic relocator */
/* replace previous hfs_do_move_* */
static int
{
int new_start;
ref->ext_length);
/* Load, modify & save */
/******** MDB *********/
case CR_PRIM_CAT :
goto CR_PRIM;
case CR_PRIM_EXT :
CR_PRIM :
extent = ( HfsExtDescriptor* )
break;
/********* BTREE *******/
case CR_BTREE_EXT_CAT :
if (priv_data->catalog_file
case CR_BTREE_EXT_0 :
goto CR_BTREE;
case CR_BTREE_CAT :
return -1);
return -1;
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;
}
/* Update the cache */
}
return new_start;
}
/* 0 error, 1 ok */
static int
{
unsigned int map_sectors;
/ (PED_SECTOR_SIZE_DEFAULT * 8);
map_sectors) );
}
/* 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 */
/* Generic search thanks to the file system cache */
static int
unsigned int *ptr_to_fblock,
{
/* Reference search powered by the cache... */
/* This is the optimisation secret :) */
if (!ref) return 0; /* not found */
old_start = *ptr_fblock;
return -1;
}
/* allocation bitmap save is not atomic with data relocation */
/* so we only do it a few times, and without syncing */
/* The unmounted bit protect us anyway */
return 1;
}
static int
{
unsigned int j;
for (j = 0; j < HFS_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
0, /* unused for mdb */
j )
)
return 0;
}
for (j = 0; j < HFS_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
0,
1,
j )
)
return 0;
}
return 1;
}
static int
{
unsigned int leaf_node, record_number;
unsigned int i, j;
_("This HFS volume has no catalog file. "
"This is very unusual!"));
return 1;
}
return 0;
return 0;
for (i = 1; i <= record_number; ++i) {
/* undocumented alignement */
unsigned int skip;
+ skip );
/* check for obvious error in FS */
_("The file system contains errors."));
return 0;
}
for (j = 0; j < HFS_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
1, /* hfs => btree block = 512 b */
j )
)
return 0;
}
for (j = 0; j < HFS_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
1, /* hfs => btree block = 512 b */
j )
)
return 0;
}
}
}
return 1;
}
static int
{
unsigned int leaf_node, record_number;
unsigned int i, j;
_("This HFS volume has no extents overflow "
"file. This is quite unusual!"));
return 1;
}
return 0;
return 0;
for (i = 1; i <= record_number; i++) {
extent_key = (HfsExtentKey*)
/* size is cst */
+ sizeof (HfsExtentKey));
/* check for obvious error in FS */
_("The file system contains errors."));
return 0;
}
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;
default :
break;
}
for (j = 0; j < HFS_EXT_NB; ++j) {
if (!extent[j].block_count) break;
if (!hfsc_cache_add_extent(
1, /* hfs => btree block = 512 b */
j )
)
return 0;
}
}
}
return 1;
}
/* This function cache every extents start and length stored in any
fs structure into the adt defined in cache.[ch]
Returns NULL on failure */
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 (!hfs_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 (!hfs_block_count)
hfs_block_count = 1;
} else
/* If the cache code requests more space, give it to him */
if (!hfs_block)
goto error_cache;
if (!hfs_read_bad_blocks (fs)) {
_("Bad blocks list could not be loaded."));
goto error_alloc;
}
else if (ret == -1) {
_("An error occurred during extent "
"relocation."));
goto error_alloc;
}
} else {
fblock++;
}
}
return 1;
return 0;
}
#endif /* !DISCOVER_ONLY */