/*
libparted - a library for manipulating disk partitions
Copyright (C) 2004-2005, 2007, 2009-2010 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 */
/* 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;
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
{
_("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
{
_("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
{
/* 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*
{
_("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 */