hfs.c revision 7e7bd3dccbfe8f79e25e5c1554b5bc3a9aaca321
/*
libparted - a library for manipulating disk partitions
Copyright (C) 2000, 2003, 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/>.
*/
/*
Author : Guillaume Knispel <k_guillaume@libertysurf.fr>
Report bug to <bug-parted@gnu.org>
*/
#include <config.h>
#include <stdint.h>
#if ENABLE_NLS
# include <libintl.h>
#else
#endif /* ENABLE_NLS */
#include "hfs.h"
#include "probe.h"
unsigned hfs_block_count;
unsigned hfsp_block_count;
#ifndef DISCOVER_ONLY
#include "file.h"
#include "reloc.h"
#include "advfs.h"
static PedFileSystemType hfs_type;
static PedFileSystemType hfsplus_type;
/* ----- HFS ----- */
/* This is a very unundoable operation */
/* Maybe I shouldn't touch the alternate MDB ? */
/* Anyway clobber is call before other fs creation */
/* So this is a non-issue */
static int
{
/* destroy boot blocks, mdb, alternate mdb ... */
(!!ped_geometry_sync (geom));
}
static PedFileSystem*
{
if (!hfsc_can_use_geom (geom))
return NULL;
/* Read MDB */
return NULL;
/* Allocate memory */
ped_malloc (sizeof (HfsMasterDirectoryBlock));
ped_malloc (sizeof (HfsPrivateFSData));
/* init structures */
priv_data->bad_blocks_loaded = 0;
priv_data->bad_blocks_xtent_nb = 0;
/* Read allocation blocks */
/ (PED_SECTOR_SIZE_DEFAULT * 8) ) )
goto ho_cf;
>> HFS_UNMOUNTED ) & 1;
return fs;
/*--- clean error handling ---*/
}
static int
{
if (priv_data->bad_blocks_loaded)
return 1;
}
static PedConstraint*
{
return NULL;
return NULL;
return NULL;
/* 2 = last two sectors (alternate MDB and unused sector) */
}
static int
{
int resize = 1;
unsigned int hfs_sect_block;
/* check preconditions */
#ifdef DEBUG
#else
return 0;
#endif
return 1;
_("Sorry, HFS cannot be resized that way yet."));
return 0;
}
/* Flush caches */
return 0;
/* Clear the unmounted bit */
return 0;
return 0;
/* relocate data */
+ hfs_sect_block - 1 )
/ hfs_sect_block ;
resize = 0;
_("Data relocation has failed."));
goto write_MDB;
}
/* Calculate new block number and other MDB field */
/* Check that all block after future end are really free */
block++) {
resize = 0;
_("Data relocation left some data in the end "
"of the volume."));
goto write_MDB;
}
}
/* Mark out of volume blocks as used
(broken implementations compatibility) */
/* 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_SECTOR_SIZE_DEFAULT * 8));
/* Update geometry */
if (resize) {
/* update in fs structure */
/* update parted structure */
}
/* Set the unmounted bit */
/* Effective write */
if (!hfs_update_mdb(fs)) {
return 0;
}
if (!ped_geometry_sync(geom))
return 0;
return (resize);
}
/* ----- HFS+ ----- */
#include "file_plus.h"
#include "advfs_plus.h"
#include "reloc_plus.h"
#include "journal.h"
static int
{
unsigned int i = 1;
return 0;
/* embedded hfs+ */
+ (PedSector) PED_BE16_TO_CPU (
if (!embedded) i = 0;
else {
i = hfs_clobber (embedded);
}
}
/* non-embedded or envelop destroy as hfs */
return ( hfs_clobber (geom) && i );
}
static int
{
if (priv_data->bad_blocks_loaded)
return 1;
}
static PedFileSystem*
{
unsigned int map_sectors;
if (!hfsc_can_use_geom (geom))
return NULL;
unsigned int bs;
+ (PedSector) PED_BE16_TO_CPU (
+ (PedSector) PED_BE16_TO_CPU (
* bs;
* bs;
length);
} else {
}
_("No valid HFS[+X] signature has been found while "
"opening."));
goto hpo_pg;
}
if (ped_exception_throw (
_("Version %d of HFS+ isn't supported."),
goto hpo_pg;
}
if (ped_exception_throw (
_("Version %d of HFSX isn't supported."),
goto hpo_pg;
}
priv_data->jib_start_block = 0;
priv_data->jl_start_block = 0;
if (!hfsj_replay_journal(fs))
goto hpo_pg;
}
priv_data->bad_blocks_loaded = 0;
priv_data->bad_blocks_xtent_nb = 0;
/ (PED_SECTOR_SIZE_DEFAULT * 8);
return NULL;
}
return fs;
/*--- clean error handling ---*/
}
static PedConstraint*
{
return NULL;
return NULL;
return NULL;
}
static int
{
int resize = 1;
unsigned int hfsp_sect_block =
unsigned int map_sectors;
/* Flush caches */
return 0;
/* Clear the unmounted bit */
/* and set the implementation code (Apple Creator Code) */
return 0;
return 0;
/* relocate data */
- 1 ) / hfsp_sect_block;
resize = 0;
_("Data relocation has failed."));
goto write_VH;
}
/* Calculate new block number and other VH field */
/* nblock must be rounded _down_ */
- (old_blocks - nblock);
/* free block readjustement is only needed when incorrect nblock
was used by my previous implementation, so detect the case */
/ PED_SECTOR_SIZE_DEFAULT) ) {
nfree++;
}
/* Check that all block after future end are really free */
block++ ) {
resize = 0;
_("Data relocation left some data at the end "
"of the volume."));
goto write_VH;
}
}
/* Mark out of volume blocks as used */
/ (PED_SECTOR_SIZE_DEFAULT * 8) )
* (PED_SECTOR_SIZE_DEFAULT * 8);
/* Update geometry */
if (resize) {
/* update in fs structure */
/* update parted structure */
}
/* Effective write */
/* lasts two sectors are allocated by the alternate VH
and a reserved sector, and last block is always reserved */
/* Write the _old_ area to set out of volume blocks as used */
/ (PED_SECTOR_SIZE_DEFAULT * 8);
resize = 0;
_("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 */
for (block = map_sectors;
++block) {
if (!hfsplus_file_write_sector (
_("Error while writing the "
"compatibility part of the "
"allocation file."));
break;
}
}
}
if (resize) {
/* Set the unmounted bit and clear the inconsistent bit */
}
if (!hfsplus_update_vh(fs)) {
return 0;
}
return 0;
return (resize);
}
/* Update the HFS wrapper mdb and bad blocks file to reflect
the new geometry of the embedded HFS+ volume */
static int
{
unsigned int i;
unsigned int hfs_sect_block =
unsigned int hfs_blocks_embedded =
unsigned int hfs_blocks_embedded_old;
/* update HFS wrapper MDB */
/* maybe macOS will boot with this */
/* update : yes it does \o/ :) */
- hfs_blocks_embedded );
return 0;
/* force reload bad block list */
if (hfs_priv_data->bad_blocks_loaded) {
}
/* clean HFS wrapper allocation map */
for (i = PED_BE16_TO_CPU (
i < PED_BE16_TO_CPU (
i++ ) {
}
/* and save it */
( PED_BE16_TO_CPU (
/ (PED_SECTOR_SIZE_DEFAULT * 8)))
return 0;
return 0;
/* search and update the bad blocks file */
_("An error occurred while looking for the mandatory "
"bad blocks file."));
return 0;
}
return 0;
+ sizeof (HfsExtentKey) );
for (i = 0; i < HFS_EXT_NB; i++) {
if ( ret_data[i].start_block
ret_data[i].block_count =
/* found ! : update */
if (!hfs_file_write_sector (
return 0;
return 1;
}
}
ref.record_number++;
} else {
if (!ref.node_number
goto bb_not_found;
}
PED_BE16_TO_CPU (*((uint16_t *)
+ sizeof (HfsExtentKey) );
}
/* not found : not a valid hfs+ wrapper : failure */
_("It seems there is an error in the HFS wrapper: the bad "
"blocks file doesn't contain the embedded HFS+ volume."));
return 0;
}
static int
{
/* check preconditions */
#ifdef DEBUG
#else
return 0;
#endif
return 1;
_("Sorry, HFS+ cannot be resized that way yet."));
return 0;
}
unsigned int hfs_sect_block =
/* There is a wrapper so we must calculate the new geometry
of the embedded HFS+ volume */
/ hfs_sect_block ) * hfs_sect_block;
/* Can't we shrink the hfs+ volume by the desired size ? */
if (!hgee) return 0;
/* No, shrink hfs+ by the greatest possible value */
}
- red);
/* There is a wrapper so the resize process is a two stages
process (embedded resizing then wrapper resizing) :
we create a sub timer */
_("shrinking embedded HFS+ volume"));
} else {
/* No wrapper : the desired geometry is the desired
HFS+ volume geometry */
timer_plus = timer;
}
/* Resize the HFS+ volume */
_("Resizing the HFS+ volume has failed."));
return 0;
}
/* There's a wrapper : second stage = resizing it */
if (!hfsplus_wrapper_update (fs)
_("Updating the HFS wrapper has failed."));
return 0;
}
}
return 1;
}
#ifdef HFS_EXTRACT_FS
/* The following is for debugging purpose only, NOT for packaging */
#include <stdio.h>
static int
{
if (!fout) return 0;
goto err_close;
goto err_close;
}
return 0;
}
static int
{
unsigned int count;
if (!fout) return 0;
goto err_close;
1, fout))
goto err_close;
}
return 0;
}
static int
{
if (!fout) return 0;
goto err_close;
goto err_close;
return 0;
}
static int
{
_("This is not a real %s check. This is going to extract "
"special low level files for debugging purposes."),
"HFS");
if (!extract_buffer) return 0;
return 0; /* nothing has been fixed by us ! */
}
static int
{
unsigned int cp_sect;
if (!fout) return 0;
goto err_close;
1, fout))
goto err_close;
}
return 0;
}
static int
{
if (!fout) return 0;
goto err_close;
goto err_close;
return 0;
}
/* TODO : use the timer to report what is happening */
/* TODO : use exceptions to report errors */
static int
{
/* TODO : create nested timer */
}
_("This is not a real %s check. This is going to extract "
"special low level files for debugging purposes."),
"HFS+");
if (!extract_buffer) return 0;
if (startup_file) {
}
return 0; /* nothing has been fixed by us ! */
}
#endif /* HFS_EXTRACT_FS */
#endif /* !DISCOVER_ONLY */
static PedFileSystemOps hfs_ops = {
#ifndef DISCOVER_ONLY
.clobber = hfs_clobber,
#ifndef HFS_EXTRACT_FS
#else
.check = hfs_extract,
#endif
.resize = hfs_resize,
#else /* DISCOVER_ONLY */
#endif /* DISCOVER_ONLY */
};
static PedFileSystemOps hfsplus_ops = {
.probe = hfsplus_probe,
#ifndef DISCOVER_ONLY
.open = hfsplus_open,
.close = hfsplus_close,
#ifndef HFS_EXTRACT_FS
#else
.check = hfsplus_extract,
#endif
.resize = hfsplus_resize,
#else /* DISCOVER_ONLY */
#endif /* DISCOVER_ONLY */
};
static PedFileSystemOps hfsx_ops = {
.probe = hfsx_probe,
#ifndef DISCOVER_ONLY
HFSX can't be embedded */
.open = hfsplus_open,
.close = hfsplus_close,
#ifndef HFS_EXTRACT_FS
#else
.check = hfsplus_extract,
#endif
.resize = hfsplus_resize,
#else /* DISCOVER_ONLY */
#endif /* DISCOVER_ONLY */
};
static PedFileSystemType hfs_type = {
.name = "hfs",
};
static PedFileSystemType hfsplus_type = {
.ops = &hfsplus_ops,
.name = "hfs+",
};
static PedFileSystemType hfsx_type = {
.name = "hfsx",
};
void
{
}
void
{
}