pmt: revert 7f8090b
This commit is contained in:
@@ -1,332 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "file.h"
|
||||
|
||||
#include "advfs.h"
|
||||
|
||||
/* - if a < b, 0 if a == b, + if a > b */
|
||||
/* Comparaison is done in the following order : */
|
||||
/* CNID, then fork type, then start block */
|
||||
/* Note that HFS implementation in linux has a bug */
|
||||
/* in this function */
|
||||
static int
|
||||
hfs_extent_key_cmp(HfsPrivateGenericKey* a, HfsPrivateGenericKey* b)
|
||||
{
|
||||
HfsExtentKey* key1 = (HfsExtentKey*) a;
|
||||
HfsExtentKey* key2 = (HfsExtentKey*) b;
|
||||
|
||||
/* do NOT use a substraction, because */
|
||||
/* 0xFFFFFFFF - 1 = 0xFFFFFFFE so this */
|
||||
/* would return -2, despite the fact */
|
||||
/* 0xFFFFFFFF > 1 !!! (this is the 2.4 bug) */
|
||||
if (key1->file_ID != key2->file_ID)
|
||||
return PED_BE32_TO_CPU(key1->file_ID) <
|
||||
PED_BE32_TO_CPU(key2->file_ID) ?
|
||||
-1 : +1;
|
||||
|
||||
if (key1->type != key2->type)
|
||||
return (int)(key1->type - key2->type);
|
||||
|
||||
if (key1->start == key2->start)
|
||||
return 0;
|
||||
/* the whole thing wont work with 16 bits ints */
|
||||
/* anyway */
|
||||
return (int)( PED_BE16_TO_CPU(key1->start) -
|
||||
PED_BE16_TO_CPU(key2->start) );
|
||||
}
|
||||
|
||||
/* do a B-Tree lookup */
|
||||
/* read the first record immediatly inferior or egal to the given key */
|
||||
/* return 0 on error */
|
||||
/* record_out _must_ be large enough to receive record_size bytes */
|
||||
/* WARNING : the compare function called only handle Extents BTree */
|
||||
/* so modify this function if you want to do lookup in */
|
||||
/* other BTrees has well */
|
||||
int
|
||||
hfs_btree_search (HfsPrivateFile* b_tree_file, HfsPrivateGenericKey* key,
|
||||
void *record_out, unsigned int record_size,
|
||||
HfsCPrivateLeafRec* record_ref)
|
||||
{
|
||||
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
|
||||
HfsHeaderRecord* header;
|
||||
HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
|
||||
HfsPrivateGenericKey* record_key = NULL;
|
||||
unsigned int node_number, record_number;
|
||||
int i;
|
||||
uint16_t record_pos;
|
||||
|
||||
/* Read the header node */
|
||||
if (!hfs_file_read_sector(b_tree_file, node, 0))
|
||||
return 0;
|
||||
uint16_t offset;
|
||||
memcpy(&offset, node+(PED_SECTOR_SIZE_DEFAULT-2), sizeof(uint16_t));
|
||||
header = (HfsHeaderRecord*) (node + PED_BE16_TO_CPU(offset));
|
||||
|
||||
/* Get the node number of the root */
|
||||
node_number = PED_BE32_TO_CPU(header->root_node);
|
||||
if (!node_number)
|
||||
return 0;
|
||||
|
||||
/* Read the root node */
|
||||
if (!hfs_file_read_sector(b_tree_file, node, node_number))
|
||||
return 0;
|
||||
|
||||
/* Follow the white rabbit */
|
||||
while (1) {
|
||||
record_number = PED_BE16_TO_CPU (desc->rec_nb);
|
||||
for (i = record_number; i; i--) {
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(PED_SECTOR_SIZE_DEFAULT - (2*i)), sizeof(uint16_t));
|
||||
record_pos = PED_BE16_TO_CPU(value);
|
||||
record_key = (HfsPrivateGenericKey*) (node + record_pos);
|
||||
/* check for obvious error in FS */
|
||||
if ((record_pos< HFS_FIRST_REC)
|
||||
|| (record_pos>= PED_SECTOR_SIZE_DEFAULT
|
||||
- 2 * (signed)(record_number+1))) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("The file system contains errors."));
|
||||
return 0;
|
||||
}
|
||||
if (hfs_extent_key_cmp(record_key, key) <= 0)
|
||||
break;
|
||||
}
|
||||
if (!i) return 0;
|
||||
if (desc->type == HFS_IDX_NODE) {
|
||||
unsigned int skip;
|
||||
|
||||
skip = (1 + record_key->key_length + 1) & ~1;
|
||||
uint32_t value;
|
||||
memcpy(&value, node+record_pos+skip, sizeof(uint32_t));
|
||||
node_number = PED_BE32_TO_CPU(value);
|
||||
if (!hfs_file_read_sector(b_tree_file, node,
|
||||
node_number))
|
||||
return 0;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
/* copy the result if needed */
|
||||
if (record_size)
|
||||
memcpy (record_out, record_key, record_size);
|
||||
|
||||
/* send record reference if needed */
|
||||
if (record_ref) {
|
||||
record_ref->node_size = 1; /* in sectors */
|
||||
record_ref->node_number = node_number;
|
||||
record_ref->record_pos = record_pos;
|
||||
record_ref->record_number = i;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* free the bad blocks linked list */
|
||||
void
|
||||
hfs_free_bad_blocks_list(HfsPrivateLinkExtent* first)
|
||||
{
|
||||
HfsPrivateLinkExtent* next;
|
||||
|
||||
while (first) {
|
||||
next = first->next;
|
||||
free (first);
|
||||
first = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function reads bad blocks extents in the extents file
|
||||
and store it in f.s. specific data of fs */
|
||||
int
|
||||
hfs_read_bad_blocks (const PedFileSystem *fs)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
|
||||
if (priv_data->bad_blocks_loaded)
|
||||
return 1;
|
||||
|
||||
{
|
||||
uint8_t record[sizeof (HfsExtentKey)
|
||||
+ sizeof (HfsExtDataRec)];
|
||||
HfsExtentKey search;
|
||||
HfsExtentKey* ret_key = (HfsExtentKey*) record;
|
||||
HfsExtDescriptor* ret_cache = (HfsExtDescriptor*)
|
||||
(record + sizeof (HfsExtentKey));
|
||||
unsigned int block, last_start, first_pass = 1;
|
||||
|
||||
search.key_length = sizeof (HfsExtentKey) - 1;
|
||||
search.type = HFS_DATA_FORK;
|
||||
search.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID);
|
||||
|
||||
last_start = -1; block = 0;
|
||||
while (1) {
|
||||
int i;
|
||||
|
||||
search.start = PED_CPU_TO_BE16 (block);
|
||||
if (!hfs_btree_search (priv_data->extent_file,
|
||||
(HfsPrivateGenericKey*) &search,
|
||||
record, sizeof (record), NULL)
|
||||
|| ret_key->file_ID != search.file_ID
|
||||
|| ret_key->type != search.type) {
|
||||
if (first_pass)
|
||||
break;
|
||||
else
|
||||
goto errbb;
|
||||
}
|
||||
if (PED_BE16_TO_CPU (ret_key->start) == last_start)
|
||||
break;
|
||||
|
||||
last_start = PED_BE16_TO_CPU (ret_key->start);
|
||||
for (i = 0; i < HFS_EXT_NB; i++) {
|
||||
if (ret_cache[i].block_count) {
|
||||
HfsPrivateLinkExtent* new_xt =
|
||||
(HfsPrivateLinkExtent*) ped_malloc (
|
||||
sizeof (HfsPrivateLinkExtent));
|
||||
if (!new_xt)
|
||||
goto errbb;
|
||||
new_xt->next = priv_data->bad_blocks_xtent_list;
|
||||
memcpy(&(new_xt->extent), ret_cache+i,
|
||||
sizeof (HfsExtDescriptor));
|
||||
priv_data->bad_blocks_xtent_list = new_xt;
|
||||
priv_data->bad_blocks_xtent_nb++;
|
||||
block += PED_BE16_TO_CPU (
|
||||
ret_cache[i].block_count);
|
||||
}
|
||||
}
|
||||
first_pass = 0;
|
||||
}
|
||||
|
||||
priv_data->bad_blocks_loaded = 1;
|
||||
return 1;}
|
||||
|
||||
errbb: hfs_free_bad_blocks_list(priv_data->bad_blocks_xtent_list);
|
||||
priv_data->bad_blocks_xtent_list=NULL;
|
||||
priv_data->bad_blocks_xtent_nb=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function check if fblock is a bad block */
|
||||
int _GL_ATTRIBUTE_PURE
|
||||
hfs_is_bad_block (const PedFileSystem *fs, unsigned int fblock)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPrivateLinkExtent* walk;
|
||||
|
||||
for (walk = priv_data->bad_blocks_xtent_list; walk; walk = walk->next) {
|
||||
/* Won't compile without the strange cast ! gcc bug ? */
|
||||
/* or maybe C subtilties... */
|
||||
if ((fblock >= PED_BE16_TO_CPU (walk->extent.start_block)) &&
|
||||
(fblock < (unsigned int) (PED_BE16_TO_CPU (
|
||||
walk->extent.start_block)
|
||||
+ PED_BE16_TO_CPU (
|
||||
walk->extent.block_count))))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function returns the first sector of the last free block of an
|
||||
HFS volume we can get after a hfs_pack_free_space_from_block call */
|
||||
/* On error this function returns 0 */
|
||||
PedSector
|
||||
hfs_get_empty_end (const PedFileSystem *fs)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsMasterDirectoryBlock* mdb = priv_data->mdb;
|
||||
unsigned int block, last_bad, end_free_blocks;
|
||||
|
||||
/* find the next block to the last bad block of the volume */
|
||||
if (!hfs_read_bad_blocks (fs))
|
||||
return 0;
|
||||
|
||||
HfsPrivateLinkExtent* l;
|
||||
last_bad = 0;
|
||||
for (l = priv_data->bad_blocks_xtent_list; l; l = l->next) {
|
||||
if ((unsigned int) PED_BE16_TO_CPU (l->extent.start_block)
|
||||
+ PED_BE16_TO_CPU (l->extent.block_count) > last_bad)
|
||||
last_bad = PED_BE16_TO_CPU (l->extent.start_block)
|
||||
+ PED_BE16_TO_CPU (l->extent.block_count);
|
||||
}
|
||||
|
||||
/* Count the free blocks from last_bad to the end of the volume */
|
||||
end_free_blocks = 0;
|
||||
for (block = last_bad;
|
||||
block < PED_BE16_TO_CPU (mdb->total_blocks);
|
||||
block++) {
|
||||
if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
|
||||
end_free_blocks++;
|
||||
}
|
||||
|
||||
/* Calculate the block that will by the first free at the
|
||||
end of the volume */
|
||||
block = PED_BE16_TO_CPU (mdb->total_blocks) - end_free_blocks;
|
||||
|
||||
return (PedSector) PED_BE16_TO_CPU (mdb->start_block)
|
||||
+ (PedSector) block * (PED_BE32_TO_CPU (mdb->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT);
|
||||
}
|
||||
|
||||
/* return the block which should be used to pack data to have at
|
||||
least free fblock blocks at the end of the volume */
|
||||
unsigned int _GL_ATTRIBUTE_PURE
|
||||
hfs_find_start_pack (const PedFileSystem *fs, unsigned int fblock)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
unsigned int block;
|
||||
|
||||
for (block = PED_BE16_TO_CPU (priv_data->mdb->total_blocks) - 1;
|
||||
block && fblock;
|
||||
block--) {
|
||||
if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
|
||||
fblock--;
|
||||
}
|
||||
|
||||
while (block && !TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
|
||||
block--;
|
||||
if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
|
||||
block++;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 _ADVFS_H
|
||||
#define _ADVFS_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfs_btree_search (HfsPrivateFile* b_tree_file, HfsPrivateGenericKey* key,
|
||||
void *record_out, unsigned int record_size,
|
||||
HfsCPrivateLeafRec* record_ref);
|
||||
|
||||
void
|
||||
hfs_free_bad_blocks_list(HfsPrivateLinkExtent* first);
|
||||
|
||||
int
|
||||
hfs_read_bad_blocks (const PedFileSystem *fs);
|
||||
|
||||
int
|
||||
hfs_is_bad_block (const PedFileSystem *fs, unsigned int fblock);
|
||||
|
||||
PedSector
|
||||
hfs_get_empty_end (const PedFileSystem *fs);
|
||||
|
||||
unsigned int
|
||||
hfs_find_start_pack (const PedFileSystem *fs, unsigned int fblock);
|
||||
|
||||
#endif /* _ADVFS_H */
|
||||
@@ -1,385 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "advfs.h"
|
||||
#include "file_plus.h"
|
||||
|
||||
#include "advfs_plus.h"
|
||||
|
||||
/* - if a < b, 0 if a == b, + if a > b */
|
||||
/* Comparaison is done in the following order : */
|
||||
/* CNID, then fork type, then start block */
|
||||
static int
|
||||
hfsplus_extent_key_cmp(HfsPPrivateGenericKey* a, HfsPPrivateGenericKey* b)
|
||||
{
|
||||
HfsPExtentKey* key1 = (HfsPExtentKey*) a;
|
||||
HfsPExtentKey* key2 = (HfsPExtentKey*) b;
|
||||
|
||||
if (key1->file_ID != key2->file_ID)
|
||||
return PED_BE32_TO_CPU(key1->file_ID) <
|
||||
PED_BE32_TO_CPU(key2->file_ID) ?
|
||||
-1 : +1;
|
||||
|
||||
if (key1->type != key2->type)
|
||||
return (int)(key1->type - key2->type);
|
||||
|
||||
if (key1->start == key2->start)
|
||||
return 0;
|
||||
return PED_BE32_TO_CPU(key1->start) <
|
||||
PED_BE32_TO_CPU(key2->start) ?
|
||||
-1 : +1;
|
||||
}
|
||||
|
||||
/* do a B-Tree lookup */
|
||||
/* read the first record immediatly inferior or egal to the given key */
|
||||
/* return 0 on error */
|
||||
/* record_out _must_ be large enough to receive the whole record (key + data) */
|
||||
/* WARNING : the search function called only handle Extents BTree */
|
||||
/* so modify this function if you want to do lookup in */
|
||||
/* other BTrees has well */
|
||||
int
|
||||
hfsplus_btree_search (HfsPPrivateFile* b_tree_file, HfsPPrivateGenericKey* key,
|
||||
void *record_out, unsigned int record_size,
|
||||
HfsCPrivateLeafRec* record_ref)
|
||||
{
|
||||
uint8_t node_1[PED_SECTOR_SIZE_DEFAULT];
|
||||
uint8_t* node;
|
||||
HfsPHeaderRecord* header;
|
||||
HfsPPrivateGenericKey* record_key = NULL;
|
||||
unsigned int node_number, record_number, size, bsize;
|
||||
int i;
|
||||
uint16_t record_pos;
|
||||
|
||||
/* Read the header node */
|
||||
if (!hfsplus_file_read_sector(b_tree_file, node_1, 0))
|
||||
return 0;
|
||||
header = (HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC);
|
||||
|
||||
/* Get the node number of the root */
|
||||
node_number = PED_BE32_TO_CPU (header->root_node);
|
||||
if (!node_number)
|
||||
return 0;
|
||||
|
||||
/* Get the size of a node in sectors and allocate buffer */
|
||||
size = (bsize = PED_BE16_TO_CPU (header->node_size)) / PED_SECTOR_SIZE_DEFAULT;
|
||||
node = ped_malloc (bsize);
|
||||
if (!node)
|
||||
return 0;
|
||||
HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node;
|
||||
|
||||
/* Read the root node */
|
||||
if (!hfsplus_file_read (b_tree_file, node,
|
||||
(PedSector) node_number * size, size))
|
||||
return 0;
|
||||
|
||||
/* Follow the white rabbit */
|
||||
while (1) {
|
||||
record_number = PED_BE16_TO_CPU (desc->rec_nb);
|
||||
for (i = record_number; i; i--) {
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
|
||||
record_pos = PED_BE16_TO_CPU(value);
|
||||
record_key = (HfsPPrivateGenericKey*) (node + record_pos);
|
||||
/* check for obvious error in FS */
|
||||
if ((record_pos < HFS_FIRST_REC)
|
||||
|| (record_pos >= (signed)bsize
|
||||
- 2 * (signed)(record_number+1))) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("The file system contains errors."));
|
||||
free (node);
|
||||
return 0;
|
||||
}
|
||||
if (hfsplus_extent_key_cmp(record_key, key) <= 0)
|
||||
break;
|
||||
}
|
||||
if (!i) { free (node); return 0; }
|
||||
if (desc->type == HFS_IDX_NODE) {
|
||||
unsigned int skip;
|
||||
|
||||
skip = ( 2 + PED_BE16_TO_CPU (record_key->key_length)
|
||||
+ 1 ) & ~1;
|
||||
uint32_t value;
|
||||
memcpy(&value, node+record_pos+skip, sizeof(uint32_t));
|
||||
node_number = PED_BE32_TO_CPU(value);
|
||||
if (!hfsplus_file_read(b_tree_file, node,
|
||||
(PedSector) node_number * size,
|
||||
size)) {
|
||||
free (node);
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
/* copy the result if needed */
|
||||
if (record_size)
|
||||
memcpy (record_out, record_key, record_size);
|
||||
|
||||
/* send record reference if needed */
|
||||
if (record_ref) {
|
||||
record_ref->node_size = size; /* in sectors */
|
||||
record_ref->node_number = node_number;
|
||||
record_ref->record_pos = record_pos;
|
||||
record_ref->record_number = i;
|
||||
}
|
||||
|
||||
/* success */
|
||||
free (node);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* free the bad blocks linked list */
|
||||
void
|
||||
hfsplus_free_bad_blocks_list(HfsPPrivateLinkExtent* first)
|
||||
{
|
||||
HfsPPrivateLinkExtent* next;
|
||||
|
||||
while (first) {
|
||||
next = first->next;
|
||||
free (first);
|
||||
first = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function reads bad blocks extents in the extents file
|
||||
and store it in f.s. specific data of fs */
|
||||
int
|
||||
hfsplus_read_bad_blocks (const PedFileSystem *fs)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
|
||||
if (priv_data->bad_blocks_loaded)
|
||||
return 1;
|
||||
|
||||
{
|
||||
uint8_t record[sizeof (HfsPExtentKey)
|
||||
+ sizeof (HfsPExtDataRec)];
|
||||
HfsPExtentKey search;
|
||||
HfsPExtentKey* ret_key = (HfsPExtentKey*) record;
|
||||
HfsPExtDescriptor* ret_cache = (HfsPExtDescriptor*)
|
||||
(record + sizeof (HfsPExtentKey));
|
||||
int block, first_pass = 1;
|
||||
unsigned int last_start;
|
||||
|
||||
search.key_length = sizeof (HfsExtentKey) - 2;
|
||||
search.type = HFS_DATA_FORK;
|
||||
search.pad = 0;
|
||||
search.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID);
|
||||
|
||||
last_start = -1; block = 0;
|
||||
while (1) {
|
||||
int i;
|
||||
|
||||
search.start = PED_CPU_TO_BE32 (block);
|
||||
if (!hfsplus_btree_search (priv_data->extents_file,
|
||||
(HfsPPrivateGenericKey*) &search,
|
||||
record, sizeof (record), NULL)
|
||||
|| ret_key->file_ID != search.file_ID
|
||||
|| ret_key->type != search.type) {
|
||||
if (first_pass)
|
||||
break;
|
||||
else
|
||||
goto errbbp;
|
||||
}
|
||||
if (PED_BE32_TO_CPU (ret_key->start) == last_start)
|
||||
break;
|
||||
|
||||
last_start = PED_BE32_TO_CPU (ret_key->start);
|
||||
for (i = 0; i < HFSP_EXT_NB; i++) {
|
||||
if (ret_cache[i].block_count) {
|
||||
HfsPPrivateLinkExtent* new_xt =
|
||||
(HfsPPrivateLinkExtent*) ped_malloc (
|
||||
sizeof (HfsPPrivateLinkExtent));
|
||||
if (!new_xt)
|
||||
goto errbbp;
|
||||
new_xt->next = priv_data->bad_blocks_xtent_list;
|
||||
memcpy (&(new_xt->extent), ret_cache+i,
|
||||
sizeof (HfsPExtDescriptor));
|
||||
priv_data->bad_blocks_xtent_list = new_xt;
|
||||
priv_data->bad_blocks_xtent_nb++;
|
||||
block += PED_BE32_TO_CPU (
|
||||
ret_cache[i].block_count);
|
||||
}
|
||||
}
|
||||
first_pass = 0;
|
||||
}
|
||||
|
||||
priv_data->bad_blocks_loaded = 1;
|
||||
return 1;}
|
||||
|
||||
errbbp: hfsplus_free_bad_blocks_list(priv_data->bad_blocks_xtent_list);
|
||||
priv_data->bad_blocks_xtent_list=NULL;
|
||||
priv_data->bad_blocks_xtent_nb=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function check if fblock is a bad block */
|
||||
int _GL_ATTRIBUTE_PURE
|
||||
hfsplus_is_bad_block (const PedFileSystem *fs, unsigned int fblock)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPPrivateLinkExtent* walk;
|
||||
|
||||
for (walk = priv_data->bad_blocks_xtent_list; walk; walk = walk->next) {
|
||||
/* Won't compile without the strange cast ! gcc bug ? */
|
||||
/* or maybe C subtilties... */
|
||||
if ((fblock >= PED_BE32_TO_CPU (walk->extent.start_block)) &&
|
||||
(fblock < (unsigned int)(PED_BE32_TO_CPU (
|
||||
walk->extent.start_block)
|
||||
+ PED_BE32_TO_CPU (walk->extent.block_count))))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function returns the first sector of the last free block of
|
||||
an HFS+ volume we can get after a hfsplus_pack_free_space_from_block call */
|
||||
PedSector
|
||||
hfsplus_get_empty_end (const PedFileSystem *fs)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPVolumeHeader* vh = priv_data->vh;
|
||||
unsigned int block, last_bad, end_free_blocks;
|
||||
|
||||
/* find the next block to the last bad block of the volume */
|
||||
if (!hfsplus_read_bad_blocks (fs)) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Bad blocks could not be read."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
HfsPPrivateLinkExtent* l;
|
||||
last_bad = 0;
|
||||
for (l = priv_data->bad_blocks_xtent_list; l; l = l->next) {
|
||||
if ((unsigned int) PED_BE32_TO_CPU (l->extent.start_block)
|
||||
+ PED_BE32_TO_CPU (l->extent.block_count) > last_bad)
|
||||
last_bad = PED_BE32_TO_CPU (l->extent.start_block)
|
||||
+ PED_BE32_TO_CPU (l->extent.block_count);
|
||||
}
|
||||
|
||||
/* Count the free blocks from last_bad to the end of the volume */
|
||||
end_free_blocks = 0;
|
||||
for (block = last_bad;
|
||||
block < PED_BE32_TO_CPU (vh->total_blocks);
|
||||
block++) {
|
||||
if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
|
||||
end_free_blocks++;
|
||||
}
|
||||
|
||||
/* Calculate the block that will by the first free at
|
||||
the end of the volume */
|
||||
block = PED_BE32_TO_CPU (vh->total_blocks) - end_free_blocks;
|
||||
|
||||
return (PedSector) block * ( PED_BE32_TO_CPU (vh->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT );
|
||||
}
|
||||
|
||||
/* On error, returns 0 */
|
||||
PedSector
|
||||
hfsplus_get_min_size (const PedFileSystem *fs)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
PedSector min_size;
|
||||
|
||||
/* don't need to add anything because every sector
|
||||
can be part of allocation blocks in HFS+, and
|
||||
the last block _must_ be reserved */
|
||||
min_size = hfsplus_get_empty_end(fs);
|
||||
if (!min_size) return 0;
|
||||
|
||||
if (priv_data->wrapper) {
|
||||
HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*)
|
||||
priv_data->wrapper->type_specific;
|
||||
unsigned int hfs_sect_block;
|
||||
PedSector hgee;
|
||||
hfs_sect_block =
|
||||
PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT;
|
||||
/*
|
||||
* if hfs+ is embedded in an hfs wrapper then the new size is :
|
||||
* the new size of the hfs+ volume rounded up to the size
|
||||
* of hfs blocks
|
||||
* + the minimum size of the hfs wrapper without any hfs+
|
||||
* modification
|
||||
* - the current size of the hfs+ volume in the hfs wrapper
|
||||
*/
|
||||
hgee = hfs_get_empty_end(priv_data->wrapper);
|
||||
if (!hgee) return 0;
|
||||
min_size = ((min_size + hfs_sect_block - 1) / hfs_sect_block)
|
||||
* hfs_sect_block
|
||||
+ hgee + 2
|
||||
- (PedSector) PED_BE16_TO_CPU ( hfs_priv_data->mdb
|
||||
->old_new.embedded
|
||||
.location.block_count )
|
||||
* hfs_sect_block;
|
||||
}
|
||||
|
||||
return min_size;
|
||||
}
|
||||
|
||||
/* return the block which should be used to pack data to have
|
||||
at least free fblock blocks at the end of the volume */
|
||||
unsigned int _GL_ATTRIBUTE_PURE
|
||||
hfsplus_find_start_pack (const PedFileSystem *fs, unsigned int fblock)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
unsigned int block;
|
||||
|
||||
for (block = PED_BE32_TO_CPU (priv_data->vh->total_blocks) - 1;
|
||||
block && fblock;
|
||||
block--) {
|
||||
if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
|
||||
fblock--;
|
||||
}
|
||||
|
||||
while (block && !TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
|
||||
block--;
|
||||
if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
|
||||
block++;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 _ADVFS_PLUS_H
|
||||
#define _ADVFS_PLUS_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfsplus_btree_search (HfsPPrivateFile* b_tree_file, HfsPPrivateGenericKey* key,
|
||||
void *record_out, unsigned int record_size,
|
||||
HfsCPrivateLeafRec* record_ref);
|
||||
|
||||
void
|
||||
hfsplus_free_bad_blocks_list(HfsPPrivateLinkExtent* first);
|
||||
|
||||
int
|
||||
hfsplus_read_bad_blocks (const PedFileSystem *fs);
|
||||
|
||||
int
|
||||
hfsplus_is_bad_block (const PedFileSystem *fs, unsigned int fblock);
|
||||
|
||||
PedSector
|
||||
hfsplus_get_empty_end (const PedFileSystem *fs);
|
||||
|
||||
PedSector
|
||||
hfsplus_get_min_size (const PedFileSystem *fs);
|
||||
|
||||
unsigned int
|
||||
hfsplus_find_start_pack (const PedFileSystem *fs, unsigned int fblock);
|
||||
|
||||
#endif /* _ADVFS_PLUS_H */
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
#include "cache.h"
|
||||
|
||||
static HfsCPrivateCacheTable*
|
||||
hfsc_new_cachetable(unsigned int size)
|
||||
{
|
||||
HfsCPrivateCacheTable* ret;
|
||||
|
||||
ret = (HfsCPrivateCacheTable*) ped_malloc(sizeof(*ret));
|
||||
if (!ret) return NULL;
|
||||
|
||||
ret->next_cache = NULL;
|
||||
ret->table_size = size;
|
||||
ret->table_first_free = 0;
|
||||
|
||||
ret->table = ped_malloc(sizeof(*ret->table)*size);
|
||||
if (!ret->table) { free(ret); return NULL; }
|
||||
memset(ret->table, 0, sizeof(*ret->table)*size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HfsCPrivateCache*
|
||||
hfsc_new_cache(unsigned int block_number, unsigned int file_number)
|
||||
{
|
||||
unsigned int cachetable_size, i;
|
||||
HfsCPrivateCache* ret;
|
||||
|
||||
ret = (HfsCPrivateCache*) ped_malloc(sizeof(*ret));
|
||||
if (!ret) return NULL;
|
||||
ret->block_number = block_number;
|
||||
/* following code avoid integer overflow */
|
||||
ret->linked_ref_size = block_number > block_number + ((1<<CR_SHIFT)-1) ?
|
||||
( block_number >> CR_SHIFT ) + 1 :
|
||||
( block_number + ((1<<CR_SHIFT)-1) ) >> CR_SHIFT
|
||||
;
|
||||
|
||||
ret->linked_ref = (HfsCPrivateExtent**)
|
||||
ped_malloc( sizeof(*ret->linked_ref)
|
||||
* ret->linked_ref_size );
|
||||
if (!ret->linked_ref) { free(ret); return NULL; }
|
||||
|
||||
cachetable_size = file_number + file_number / CR_OVER_DIV + CR_ADD_CST;
|
||||
if (cachetable_size < file_number) cachetable_size = (unsigned) -1;
|
||||
ret->first_cachetable_size = cachetable_size;
|
||||
ret->table_list = hfsc_new_cachetable(cachetable_size);
|
||||
if (!ret->table_list) {
|
||||
free(ret->linked_ref);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->last_table = ret->table_list;
|
||||
|
||||
for (i = 0; i < ret->linked_ref_size; ++i)
|
||||
ret->linked_ref[i] = NULL;
|
||||
|
||||
ret->needed_alloc_size = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
hfsc_delete_cachetable(HfsCPrivateCacheTable* list)
|
||||
{
|
||||
HfsCPrivateCacheTable* next;
|
||||
|
||||
while (list) {
|
||||
free (list->table);
|
||||
next = list->next_cache;
|
||||
free (list);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hfsc_delete_cache(HfsCPrivateCache* cache)
|
||||
{
|
||||
hfsc_delete_cachetable(cache->table_list);
|
||||
free(cache->linked_ref);
|
||||
free(cache);
|
||||
}
|
||||
|
||||
HfsCPrivateExtent*
|
||||
hfsc_cache_add_extent(HfsCPrivateCache* cache, uint32_t start, uint32_t length,
|
||||
uint32_t block, uint16_t offset, uint8_t sbb,
|
||||
uint8_t where, uint8_t ref_index)
|
||||
{
|
||||
HfsCPrivateExtent* ext;
|
||||
unsigned int idx = start >> CR_SHIFT;
|
||||
|
||||
PED_ASSERT(idx < cache->linked_ref_size);
|
||||
|
||||
for (ext = cache->linked_ref[idx];
|
||||
ext && start != ext->ext_start;
|
||||
ext = ext->next);
|
||||
|
||||
if (ext) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Trying to register an extent starting at block "
|
||||
"0x%X, but another one already exists at this "
|
||||
"position. You should check the file system!"),
|
||||
start);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( cache->last_table->table_first_free
|
||||
== cache->last_table->table_size ) {
|
||||
cache->last_table->next_cache =
|
||||
hfsc_new_cachetable( ( cache->first_cachetable_size
|
||||
/ CR_NEW_ALLOC_DIV )
|
||||
+ CR_ADD_CST );
|
||||
if (!cache->last_table->next_cache)
|
||||
return NULL;
|
||||
cache->last_table = cache->last_table->next_cache;
|
||||
}
|
||||
|
||||
ext = cache->last_table->table+(cache->last_table->table_first_free++);
|
||||
|
||||
ext->ext_start = start;
|
||||
ext->ext_length = length;
|
||||
ext->ref_block = block;
|
||||
ext->ref_offset = offset;
|
||||
ext->sect_by_block = sbb;
|
||||
ext->where = where;
|
||||
ext->ref_index = ref_index;
|
||||
|
||||
ext->next = cache->linked_ref[idx];
|
||||
cache->linked_ref[idx] = ext;
|
||||
|
||||
cache->needed_alloc_size = cache->needed_alloc_size >
|
||||
(unsigned) PED_SECTOR_SIZE_DEFAULT * sbb ?
|
||||
cache->needed_alloc_size :
|
||||
(unsigned) PED_SECTOR_SIZE_DEFAULT * sbb;
|
||||
|
||||
return ext;
|
||||
}
|
||||
|
||||
HfsCPrivateExtent* _GL_ATTRIBUTE_PURE
|
||||
hfsc_cache_search_extent(HfsCPrivateCache* cache, uint32_t start)
|
||||
{
|
||||
HfsCPrivateExtent* ret;
|
||||
unsigned int idx = start >> CR_SHIFT;
|
||||
|
||||
PED_ASSERT(idx < cache->linked_ref_size);
|
||||
|
||||
for (ret = cache->linked_ref[idx];
|
||||
ret && start != ret->ext_start;
|
||||
ret = ret->next);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Can't fail if extent begining at old_start exists */
|
||||
/* Returns 0 if no such extent, or on error */
|
||||
HfsCPrivateExtent*
|
||||
hfsc_cache_move_extent(HfsCPrivateCache* cache, uint32_t old_start,
|
||||
uint32_t new_start)
|
||||
{
|
||||
HfsCPrivateExtent** ppext;
|
||||
HfsCPrivateExtent* pext;
|
||||
|
||||
unsigned int idx1 = old_start >> CR_SHIFT;
|
||||
unsigned int idx2 = new_start >> CR_SHIFT;
|
||||
|
||||
PED_ASSERT(idx1 < cache->linked_ref_size);
|
||||
PED_ASSERT(idx2 < cache->linked_ref_size);
|
||||
|
||||
for (pext = cache->linked_ref[idx2];
|
||||
pext && new_start != pext->ext_start;
|
||||
pext = pext->next);
|
||||
|
||||
if (pext) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_BUG,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Trying to move an extent from block 0x%X to block "
|
||||
"0x%X, but another one already exists at this "
|
||||
"position. This should not happen!"),
|
||||
old_start, new_start);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (ppext = &(cache->linked_ref[idx1]);
|
||||
(*ppext) && old_start != (*ppext)->ext_start;
|
||||
ppext = &((*ppext)->next));
|
||||
|
||||
if (!(*ppext)) return NULL;
|
||||
|
||||
/* removing the extent from the cache */
|
||||
pext = *ppext;
|
||||
(*ppext) = pext->next;
|
||||
|
||||
/* change ext_start and insert the extent again */
|
||||
pext->ext_start = new_start;
|
||||
pext->next = cache->linked_ref[idx2];
|
||||
cache->linked_ref[idx2] = pext;
|
||||
|
||||
return pext;
|
||||
}
|
||||
|
||||
#endif /* DISCOVER_ONLY */
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 _CACHE_H
|
||||
#define _CACHE_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
/* CR => CACHE REF */
|
||||
#define CR_NULL 0 /* reserved */
|
||||
#define CR_PRIM_CAT 1
|
||||
#define CR_PRIM_EXT 2
|
||||
#define CR_PRIM_ATTR 3
|
||||
#define CR_PRIM_ALLOC 4
|
||||
#define CR_PRIM_START 5
|
||||
#define CR_BTREE_CAT 6
|
||||
#define CR_BTREE_ATTR 7
|
||||
#define CR_BTREE_EXT_0 8
|
||||
#define CR_BTREE_EXT_CAT 9
|
||||
#define CR_BTREE_EXT_EXT 10 /* should not happen ! */
|
||||
#define CR_BTREE_EXT_ATTR 11
|
||||
#define CR_BTREE_EXT_ALLOC 12
|
||||
#define CR_BTREE_EXT_START 13 /* unneeded in current code */
|
||||
#define CR_BTREE_CAT_JIB 14 /* journal info block */
|
||||
#define CR_BTREE_CAT_JL 15 /* journal */
|
||||
/* 16 -> 31 || high order bit */ /* reserved */
|
||||
|
||||
/* tuning */
|
||||
#define CR_SHIFT 8 /* number of bits to shift start_block by */
|
||||
/* to get the index of the linked list */
|
||||
#define CR_OVER_DIV 16 /* alloc a table for (1+1/CR_OVER_DIV) *
|
||||
file_number + CR_ADD_CST */
|
||||
#define CR_ADD_CST 16
|
||||
#define CR_NEW_ALLOC_DIV 4 /* divide the size of the first alloc table
|
||||
by this value to allocate next tables */
|
||||
|
||||
/* See DOC for an explaination of this structure */
|
||||
/* Access read only from outside cache.c */
|
||||
struct _HfsCPrivateExtent {
|
||||
struct _HfsCPrivateExtent* next;
|
||||
uint32_t ext_start;
|
||||
uint32_t ext_length;
|
||||
uint32_t ref_block;
|
||||
uint16_t ref_offset;
|
||||
uint8_t sect_by_block;
|
||||
unsigned where : 5;
|
||||
unsigned ref_index : 3; /* 0 -> 7 */
|
||||
};
|
||||
typedef struct _HfsCPrivateExtent HfsCPrivateExtent;
|
||||
|
||||
/* Internaly used by cache.c for custom memory managment only */
|
||||
struct _HfsCPrivateCacheTable {
|
||||
struct _HfsCPrivateCacheTable* next_cache;
|
||||
HfsCPrivateExtent* table;
|
||||
unsigned int table_size;
|
||||
unsigned int table_first_free;
|
||||
/* first_elemt ? */
|
||||
};
|
||||
typedef struct _HfsCPrivateCacheTable HfsCPrivateCacheTable;
|
||||
|
||||
/* Internaly used by cache.c for custom memory managment
|
||||
and cache handling only */
|
||||
struct _HfsCPrivateCache {
|
||||
HfsCPrivateCacheTable* table_list;
|
||||
HfsCPrivateCacheTable* last_table;
|
||||
HfsCPrivateExtent** linked_ref;
|
||||
unsigned int linked_ref_size;
|
||||
unsigned int block_number;
|
||||
unsigned int first_cachetable_size;
|
||||
unsigned int needed_alloc_size;
|
||||
};
|
||||
typedef struct _HfsCPrivateCache HfsCPrivateCache;
|
||||
|
||||
HfsCPrivateCache*
|
||||
hfsc_new_cache(unsigned int block_number, unsigned int file_number);
|
||||
|
||||
void
|
||||
hfsc_delete_cache(HfsCPrivateCache* cache);
|
||||
|
||||
HfsCPrivateExtent*
|
||||
hfsc_cache_add_extent(HfsCPrivateCache* cache, uint32_t start, uint32_t length,
|
||||
uint32_t block, uint16_t offset, uint8_t sbb,
|
||||
uint8_t where, uint8_t index);
|
||||
|
||||
HfsCPrivateExtent*
|
||||
hfsc_cache_search_extent(HfsCPrivateCache* cache, uint32_t start);
|
||||
|
||||
HfsCPrivateExtent*
|
||||
hfsc_cache_move_extent(HfsCPrivateCache* cache, uint32_t old_start,
|
||||
uint32_t new_start);
|
||||
|
||||
static __inline__ unsigned int
|
||||
hfsc_cache_needed_buffer(HfsCPrivateCache* cache)
|
||||
{
|
||||
return cache->needed_alloc_size;
|
||||
}
|
||||
|
||||
#endif /* _CACHE_H */
|
||||
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "advfs.h"
|
||||
|
||||
#include "file.h"
|
||||
|
||||
/* Open the data fork of a file with its first three extents and its CNID */
|
||||
HfsPrivateFile*
|
||||
hfs_file_open (PedFileSystem *fs, uint32_t CNID,
|
||||
HfsExtDataRec ext_desc, PedSector sect_nb)
|
||||
{
|
||||
HfsPrivateFile* file;
|
||||
|
||||
file = (HfsPrivateFile*) ped_malloc (sizeof (HfsPrivateFile));
|
||||
if (!file) return NULL;
|
||||
|
||||
file->fs = fs;
|
||||
file->sect_nb = sect_nb;
|
||||
file->CNID = CNID;
|
||||
memcpy(file->first, ext_desc, sizeof (HfsExtDataRec));
|
||||
file->start_cache = 0;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/* Close an HFS file */
|
||||
void
|
||||
hfs_file_close (HfsPrivateFile* file)
|
||||
{
|
||||
free (file);
|
||||
}
|
||||
|
||||
/* warning : only works on data forks */
|
||||
static int
|
||||
hfs_get_extent_containing (HfsPrivateFile* file, unsigned int block,
|
||||
HfsExtDataRec cache, uint16_t* ptr_start_cache)
|
||||
{
|
||||
uint8_t record[sizeof (HfsExtentKey)
|
||||
+ sizeof (HfsExtDataRec)];
|
||||
HfsExtentKey search;
|
||||
HfsExtentKey* ret_key = (HfsExtentKey*) record;
|
||||
HfsExtDescriptor* ret_cache = (HfsExtDescriptor*)
|
||||
(record + sizeof (HfsExtentKey));
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
file->fs->type_specific;
|
||||
|
||||
search.key_length = sizeof (HfsExtentKey) - 1;
|
||||
search.type = HFS_DATA_FORK;
|
||||
search.file_ID = file->CNID;
|
||||
search.start = PED_CPU_TO_BE16 (block);
|
||||
|
||||
if (!hfs_btree_search (priv_data->extent_file,
|
||||
(HfsPrivateGenericKey*) &search,
|
||||
record, sizeof (record), NULL))
|
||||
return 0;
|
||||
|
||||
if (ret_key->file_ID != search.file_ID || ret_key->type != search.type)
|
||||
return 0;
|
||||
|
||||
memcpy (cache, ret_cache, sizeof(HfsExtDataRec));
|
||||
*ptr_start_cache = PED_BE16_TO_CPU (ret_key->start);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* find and return the nth sector of a file */
|
||||
/* return 0 on error */
|
||||
static PedSector
|
||||
hfs_file_find_sector (HfsPrivateFile* file, PedSector sector)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
file->fs->type_specific;
|
||||
unsigned int sect_by_block = PED_BE32_TO_CPU (
|
||||
priv_data->mdb->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT;
|
||||
unsigned int i, s, vol_block;
|
||||
unsigned int block = sector / sect_by_block;
|
||||
unsigned int offset = sector % sect_by_block;
|
||||
|
||||
/* in the three first extent */
|
||||
for (s = 0, i = 0; i < HFS_EXT_NB; i++) {
|
||||
if ((block >= s) && ( block < s + PED_BE16_TO_CPU (
|
||||
file->first[i].block_count))) {
|
||||
vol_block = (block - s) + PED_BE16_TO_CPU (
|
||||
file->first[i].start_block);
|
||||
goto sector_found;
|
||||
}
|
||||
s += PED_BE16_TO_CPU (file->first[i].block_count);
|
||||
}
|
||||
|
||||
/* in the three cached extent */
|
||||
if (file->start_cache && block >= file->start_cache)
|
||||
for (s = file->start_cache, i = 0; i < HFS_EXT_NB; i++) {
|
||||
if ((block >= s) && (block < s + PED_BE16_TO_CPU (
|
||||
file->cache[i].block_count))) {
|
||||
vol_block = (block - s) + PED_BE16_TO_CPU (
|
||||
file->cache[i].start_block);
|
||||
goto sector_found;
|
||||
}
|
||||
s += PED_BE16_TO_CPU (file->cache[i].block_count);
|
||||
}
|
||||
|
||||
/* update cache */
|
||||
if (!hfs_get_extent_containing (file, block, file->cache,
|
||||
&(file->start_cache))) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_WARNING,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Could not update the extent cache for HFS file with "
|
||||
"CNID %X."),
|
||||
PED_BE32_TO_CPU(file->CNID));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* in the three cached extent */
|
||||
PED_ASSERT(file->start_cache && block >= file->start_cache);
|
||||
for (s = file->start_cache, i = 0; i < HFS_EXT_NB; i++) {
|
||||
if ((block >= s) && (block < s + PED_BE16_TO_CPU (
|
||||
file->cache[i].block_count))) {
|
||||
vol_block = (block - s) + PED_BE16_TO_CPU (
|
||||
file->cache[i].start_block);
|
||||
goto sector_found;
|
||||
}
|
||||
s += PED_BE16_TO_CPU (file->cache[i].block_count);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
sector_found:
|
||||
return (PedSector) PED_BE16_TO_CPU (priv_data->mdb->start_block)
|
||||
+ (PedSector) vol_block * sect_by_block
|
||||
+ offset;
|
||||
}
|
||||
|
||||
/* Read the nth sector of a file */
|
||||
/* return 0 on error */
|
||||
int
|
||||
hfs_file_read_sector (HfsPrivateFile* file, void *buf, PedSector sector)
|
||||
{
|
||||
PedSector abs_sector;
|
||||
|
||||
if (sector >= file->sect_nb) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Trying to read HFS file with CNID %X behind EOF."),
|
||||
PED_BE32_TO_CPU(file->CNID));
|
||||
return 0;
|
||||
}
|
||||
|
||||
abs_sector = hfs_file_find_sector (file, sector);
|
||||
if (!abs_sector) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Could not find sector %lli of HFS file with "
|
||||
"CNID %X."),
|
||||
sector, PED_BE32_TO_CPU(file->CNID));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ped_geometry_read (file->fs->geom, buf, abs_sector, 1);
|
||||
}
|
||||
|
||||
/* Write the nth sector of a file */
|
||||
/* return 0 on error */
|
||||
int
|
||||
hfs_file_write_sector (HfsPrivateFile* file, void *buf, PedSector sector)
|
||||
{
|
||||
PedSector abs_sector;
|
||||
|
||||
if (sector >= file->sect_nb) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Trying to write HFS file with CNID %X behind EOF."),
|
||||
PED_BE32_TO_CPU(file->CNID));
|
||||
return 0;
|
||||
}
|
||||
|
||||
abs_sector = hfs_file_find_sector (file, sector);
|
||||
if (!abs_sector) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Could not find sector %lli of HFS file with "
|
||||
"CNID %X."),
|
||||
sector, PED_BE32_TO_CPU(file->CNID));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ped_geometry_write (file->fs->geom, buf, abs_sector, 1);
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 _FILE_H
|
||||
#define _FILE_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
HfsPrivateFile*
|
||||
hfs_file_open (PedFileSystem *fs, uint32_t CNID,
|
||||
HfsExtDataRec ext_desc, PedSector sect_nb);
|
||||
|
||||
void
|
||||
hfs_file_close (HfsPrivateFile* file);
|
||||
|
||||
int
|
||||
hfs_file_read_sector (HfsPrivateFile* file, void *buf, PedSector sector);
|
||||
|
||||
int
|
||||
hfs_file_write_sector (HfsPrivateFile* file, void *buf, PedSector sector);
|
||||
|
||||
#endif /* _FILE_H */
|
||||
@@ -1,274 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "advfs_plus.h"
|
||||
|
||||
#include "file_plus.h"
|
||||
|
||||
/* Open the data fork of a file with its first eight extents and its CNID */
|
||||
/* CNID and ext_desc must be in disc order, sect_nb in CPU order */
|
||||
/* return null on failure */
|
||||
HfsPPrivateFile*
|
||||
hfsplus_file_open (PedFileSystem *fs, HfsPNodeID CNID,
|
||||
HfsPExtDataRec ext_desc, PedSector sect_nb)
|
||||
{
|
||||
HfsPPrivateFile* file;
|
||||
|
||||
file = (HfsPPrivateFile*) ped_malloc (sizeof (HfsPPrivateFile));
|
||||
if (!file) return NULL;
|
||||
|
||||
file->fs = fs;
|
||||
file->sect_nb = sect_nb;
|
||||
file->CNID = CNID;
|
||||
memcpy(file->first, ext_desc, sizeof (HfsPExtDataRec));
|
||||
file->start_cache = 0;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/* Close an HFS+ file */
|
||||
void
|
||||
hfsplus_file_close (HfsPPrivateFile* file)
|
||||
{
|
||||
free (file);
|
||||
}
|
||||
|
||||
/* warning : only works on data forks */
|
||||
static int
|
||||
hfsplus_get_extent_containing (HfsPPrivateFile* file, unsigned int block,
|
||||
HfsPExtDataRec cache, uint32_t* ptr_start_cache)
|
||||
{
|
||||
uint8_t record[sizeof (HfsPExtentKey)
|
||||
+ sizeof (HfsPExtDataRec)];
|
||||
HfsPExtentKey search;
|
||||
HfsPExtentKey* ret_key = (HfsPExtentKey*) record;
|
||||
HfsPExtDescriptor* ret_cache = (HfsPExtDescriptor*)
|
||||
(record + sizeof (HfsPExtentKey));
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
file->fs->type_specific;
|
||||
|
||||
search.key_length = PED_CPU_TO_BE16 (sizeof (HfsPExtentKey) - 2);
|
||||
search.type = HFS_DATA_FORK;
|
||||
search.pad = 0;
|
||||
search.file_ID = file->CNID;
|
||||
search.start = PED_CPU_TO_BE32 (block);
|
||||
|
||||
if (!hfsplus_btree_search (priv_data->extents_file,
|
||||
(HfsPPrivateGenericKey*) &search,
|
||||
record, sizeof (record), NULL))
|
||||
return 0;
|
||||
|
||||
if (ret_key->file_ID != search.file_ID || ret_key->type != search.type)
|
||||
return 0;
|
||||
|
||||
memcpy (cache, ret_cache, sizeof(HfsPExtDataRec));
|
||||
*ptr_start_cache = PED_BE32_TO_CPU (ret_key->start);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* find a sub extent contained in the desired area */
|
||||
/* and with the same starting point */
|
||||
/* return 0 in sector_count on error, or the physical area */
|
||||
/* on the volume corresponding to the logical area in the file */
|
||||
static HfsPPrivateExtent
|
||||
hfsplus_file_find_extent (HfsPPrivateFile* file, PedSector sector,
|
||||
unsigned int nb)
|
||||
{
|
||||
HfsPPrivateExtent ret = {0,0};
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
file->fs->type_specific;
|
||||
unsigned int sect_by_block = PED_BE32_TO_CPU (
|
||||
priv_data->vh->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT;
|
||||
unsigned int i, s, vol_block, size;
|
||||
PedSector sect_size;
|
||||
unsigned int block = sector / sect_by_block;
|
||||
unsigned int offset = sector % sect_by_block;
|
||||
|
||||
/* in the 8 first extent */
|
||||
for (s = 0, i = 0; i < HFSP_EXT_NB; i++) {
|
||||
if ((block >= s) && (block < s + PED_BE32_TO_CPU (
|
||||
file->first[i].block_count))) {
|
||||
vol_block = (block - s)
|
||||
+ PED_BE32_TO_CPU (file->first[i]
|
||||
.start_block);
|
||||
size = PED_BE32_TO_CPU (file->first[i].block_count)
|
||||
+ s - block;
|
||||
goto plus_sector_found;
|
||||
}
|
||||
s += PED_BE32_TO_CPU (file->first[i].block_count);
|
||||
}
|
||||
|
||||
/* in the 8 cached extent */
|
||||
if (file->start_cache && block >= file->start_cache)
|
||||
for (s = file->start_cache, i = 0; i < HFSP_EXT_NB; i++) {
|
||||
if ((block >= s) && (block < s + PED_BE32_TO_CPU (
|
||||
file->cache[i].block_count))) {
|
||||
vol_block = (block - s)
|
||||
+ PED_BE32_TO_CPU (file->cache[i]
|
||||
.start_block);
|
||||
size = PED_BE32_TO_CPU (file->cache[i].block_count)
|
||||
+ s - block;
|
||||
goto plus_sector_found;
|
||||
}
|
||||
s += PED_BE32_TO_CPU (file->cache[i].block_count);
|
||||
}
|
||||
|
||||
/* update cache */
|
||||
if (!hfsplus_get_extent_containing (file, block, file->cache,
|
||||
&(file->start_cache))) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_WARNING,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Could not update the extent cache for HFS+ file "
|
||||
"with CNID %X."),
|
||||
PED_BE32_TO_CPU(file->CNID));
|
||||
return ret; /* ret == {0,0} */
|
||||
}
|
||||
|
||||
/* ret == {0,0} */
|
||||
PED_ASSERT(file->start_cache && block >= file->start_cache);
|
||||
|
||||
for (s = file->start_cache, i = 0; i < HFSP_EXT_NB; i++) {
|
||||
if ((block >= s) && (block < s + PED_BE32_TO_CPU (
|
||||
file->cache[i].block_count))) {
|
||||
vol_block = (block - s)
|
||||
+ PED_BE32_TO_CPU (file->cache[i]
|
||||
.start_block);
|
||||
size = PED_BE32_TO_CPU (file->cache[i].block_count)
|
||||
+ s - block;
|
||||
goto plus_sector_found;
|
||||
}
|
||||
s += PED_BE32_TO_CPU (file->cache[i].block_count);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
plus_sector_found:
|
||||
sect_size = (PedSector) size * sect_by_block - offset;
|
||||
ret.start_sector = vol_block * sect_by_block + offset;
|
||||
ret.sector_count = (sect_size < nb) ? sect_size : nb;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
hfsplus_file_read(HfsPPrivateFile* file, void *buf, PedSector sector,
|
||||
unsigned int nb)
|
||||
{
|
||||
HfsPPrivateExtent phy_area;
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
file->fs->type_specific;
|
||||
char *b = buf;
|
||||
|
||||
if (sector+nb < sector /* detect overflow */
|
||||
|| sector+nb > file->sect_nb) /* out of file */ {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Trying to read HFS+ file with CNID %X behind EOF."),
|
||||
PED_BE32_TO_CPU(file->CNID));
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (nb) {
|
||||
phy_area = hfsplus_file_find_extent(file, sector, nb);
|
||||
if (phy_area.sector_count == 0) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Could not find sector %lli of HFS+ file "
|
||||
"with CNID %X."),
|
||||
sector, PED_BE32_TO_CPU(file->CNID));
|
||||
return 0;
|
||||
}
|
||||
if (!ped_geometry_read(priv_data->plus_geom, b,
|
||||
phy_area.start_sector,
|
||||
phy_area.sector_count))
|
||||
return 0;
|
||||
|
||||
nb -= phy_area.sector_count; /* < nb anyway ... */
|
||||
sector += phy_area.sector_count;
|
||||
b += phy_area.sector_count * PED_SECTOR_SIZE_DEFAULT;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
hfsplus_file_write(HfsPPrivateFile* file, void *buf, PedSector sector,
|
||||
unsigned int nb)
|
||||
{
|
||||
HfsPPrivateExtent phy_area;
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
file->fs->type_specific;
|
||||
char *b = buf;
|
||||
|
||||
if (sector+nb < sector /* detect overflow */
|
||||
|| sector+nb > file->sect_nb) /* out of file */ {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Trying to write HFS+ file with CNID %X behind EOF."),
|
||||
PED_BE32_TO_CPU(file->CNID));
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (nb) {
|
||||
phy_area = hfsplus_file_find_extent(file, sector, nb);
|
||||
if (phy_area.sector_count == 0) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Could not find sector %lli of HFS+ file "
|
||||
"with CNID %X."),
|
||||
sector, PED_BE32_TO_CPU(file->CNID));
|
||||
return 0;
|
||||
}
|
||||
if (!ped_geometry_write(priv_data->plus_geom, b,
|
||||
phy_area.start_sector,
|
||||
phy_area.sector_count))
|
||||
return 0;
|
||||
|
||||
nb -= phy_area.sector_count; /* < nb anyway ... */
|
||||
sector += phy_area.sector_count;
|
||||
b += phy_area.sector_count * PED_SECTOR_SIZE_DEFAULT;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 _FILE_PLUS_H
|
||||
#define _FILE_PLUS_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
HfsPPrivateFile*
|
||||
hfsplus_file_open (PedFileSystem *fs, HfsPNodeID CNID,
|
||||
HfsPExtDataRec ext_desc, PedSector sect_nb);
|
||||
|
||||
void
|
||||
hfsplus_file_close (HfsPPrivateFile* file);
|
||||
|
||||
int
|
||||
hfsplus_file_read(HfsPPrivateFile* file, void *buf,
|
||||
PedSector sector, unsigned int nb);
|
||||
|
||||
int
|
||||
hfsplus_file_write(HfsPPrivateFile* file, void *buf,
|
||||
PedSector sector, unsigned int nb);
|
||||
|
||||
/* Read the nth sector of a file */
|
||||
/* return 0 on error */
|
||||
static __inline__ int
|
||||
hfsplus_file_read_sector (HfsPPrivateFile* file, void *buf, PedSector sector)
|
||||
{
|
||||
return hfsplus_file_read(file, buf, sector, 1);
|
||||
}
|
||||
|
||||
/* Write the nth sector of a file */
|
||||
/* return 0 on error */
|
||||
static __inline__ int
|
||||
hfsplus_file_write_sector (HfsPPrivateFile* file, void *buf, PedSector sector)
|
||||
{
|
||||
return hfsplus_file_write(file, buf, sector, 1);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _FILE_PLUS_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,648 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2003-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 _HFS_H
|
||||
#define _HFS_H
|
||||
|
||||
/* WARNING : bn is used 2 times in theses macro */
|
||||
/* so _never_ use side effect operators when using them */
|
||||
#define TST_BLOC_OCCUPATION(tab,bn) \
|
||||
(((tab)[(bn)/8]) & (1<<(7-((bn)&7))))
|
||||
#define SET_BLOC_OCCUPATION(tab,bn) \
|
||||
(((tab)[(bn)/8]) |= (1<<(7-((bn)&7))))
|
||||
#define CLR_BLOC_OCCUPATION(tab,bn) \
|
||||
(((tab)[(bn)/8]) &= ~(1<<(7-((bn)&7))))
|
||||
|
||||
/* Maximum number of blocks for the copy buffers */
|
||||
#define BLOCK_MAX_BUFF 256
|
||||
/* Maximum size of the copy buffers, in bytes */
|
||||
#define BYTES_MAX_BUFF 8388608
|
||||
|
||||
/* Apple Creator Codes follow */
|
||||
#define HFSP_IMPL_Shnk 0x53686e6b /* in use */
|
||||
#define HFSP_IMPL_Xpnd 0x58706e64 /* reserved */
|
||||
#define HFSP_IMPL_Resz 0x5265737a /* reserved */
|
||||
#define HFSP_IMPL_PHpx 0x50482b78 /* reserved */
|
||||
#define HFSP_IMPL_traP 0x74726150 /* reserved */
|
||||
#define HFSP_IMPL_GnuP 0x476e7550 /* reserved */
|
||||
|
||||
#define HFS_SIGNATURE 0x4244 /* 'BD' */
|
||||
#define HFSP_SIGNATURE 0x482B /* 'H+' */
|
||||
#define HFSX_SIGNATURE 0x4858 /* 'HX' */
|
||||
|
||||
#define HFSP_VERSION 4
|
||||
#define HFSX_VERSION 5
|
||||
|
||||
#define HFS_HARD_LOCK 7
|
||||
#define HFS_UNMOUNTED 8
|
||||
#define HFS_BAD_SPARED 9
|
||||
#define HFS_SOFT_LOCK 15
|
||||
#define HFSP_NO_CACHE 10
|
||||
#define HFSP_INCONSISTENT 11
|
||||
#define HFSP_REUSE_CNID 12
|
||||
#define HFSP_JOURNALED 13
|
||||
|
||||
#define HFS_IDX_NODE 0x00
|
||||
#define HFS_HDR_NODE 0x01
|
||||
#define HFS_MAP_NODE 0x02
|
||||
#define HFS_LEAF_NODE 0xFF
|
||||
|
||||
#define HFS_FIRST_REC 0x0E
|
||||
#define HFS_NSD_HD_REC 0x78
|
||||
#define HFS_MAP_REC 0xF8
|
||||
|
||||
#define HFS_DATA_FORK 0x00
|
||||
#define HFS_RES_FORK 0xFF
|
||||
|
||||
#define HFS_CAT_DIR 0x01
|
||||
#define HFS_CAT_FILE 0x02
|
||||
#define HFS_CAT_DIR_TH 0x03
|
||||
#define HFS_CAT_FILE_TH 0x04
|
||||
|
||||
#define HFSP_ATTR_INLINE 0x10
|
||||
#define HFSP_ATTR_FORK 0x20
|
||||
#define HFSP_ATTR_EXTENTS 0x30
|
||||
|
||||
#define HFS_ROOT_PAR_ID 0x01
|
||||
#define HFS_ROOT_DIR_ID 0x02
|
||||
#define HFS_XTENT_ID 0x03
|
||||
#define HFS_CATALOG_ID 0x04
|
||||
#define HFS_BAD_BLOCK_ID 0x05
|
||||
#define HFSP_ALLOC_ID 0x06
|
||||
#define HFSP_STARTUP_ID 0x07
|
||||
#define HFSP_ATTRIB_ID 0x08
|
||||
#define HFSP_BOGUS_ID 0x0F
|
||||
#define HFSP_FIRST_AV_ID 0x10
|
||||
|
||||
#define HFSJ_JOURN_IN_FS 0x00
|
||||
#define HFSJ_JOURN_OTHER_DEV 0x01
|
||||
#define HFSJ_JOURN_NEED_INIT 0x02
|
||||
|
||||
#define HFSJ_HEADER_MAGIC 0x4a4e4c78
|
||||
#define HFSJ_ENDIAN_MAGIC 0x12345678
|
||||
|
||||
#define HFSX_CASE_FOLDING 0xCF /* case insensitive HFSX */
|
||||
#define HFSX_BINARY_COMPARE 0xBC /* case sensitive HFSX */
|
||||
|
||||
#define HFS_EXT_NB 3
|
||||
#define HFSP_EXT_NB 8
|
||||
|
||||
/* Define the filenames used by the FS extractor */
|
||||
#ifdef HFS_EXTRACT_FS
|
||||
|
||||
#define HFS_MDB_FILENAME "mdb.hfs"
|
||||
#define HFS_CATALOG_FILENAME "catalog.hfs"
|
||||
#define HFS_EXTENTS_FILENAME "extents.hfs"
|
||||
#define HFS_BITMAP_FILENAME "bitmap.hfs"
|
||||
|
||||
#define HFSP_VH_FILENAME "vh.hfsplus"
|
||||
#define HFSP_CATALOG_FILENAME "catalog.hfsplus"
|
||||
#define HFSP_EXTENTS_FILENAME "extents.hfsplus"
|
||||
#define HFSP_BITMAP_FILENAME "bitmap.hfsplus"
|
||||
#define HFSP_ATTRIB_FILENAME "attributes.hfsplus"
|
||||
#define HFSP_STARTUP_FILENAME "startup.hfsplus"
|
||||
|
||||
#endif /* HFS_EXTRACT_FS */
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------- */
|
||||
/* -- HFS DATA STRUCTURES -- */
|
||||
/* ----------------------------------- */
|
||||
|
||||
/* Extent descriptor */
|
||||
struct __attribute__ ((packed)) _HfsExtDescriptor {
|
||||
uint16_t start_block;
|
||||
uint16_t block_count;
|
||||
};
|
||||
typedef struct _HfsExtDescriptor HfsExtDescriptor;
|
||||
typedef HfsExtDescriptor HfsExtDataRec[HFS_EXT_NB];
|
||||
|
||||
/* Volume header */
|
||||
struct __attribute__ ((packed)) _HfsMasterDirectoryBlock {
|
||||
uint16_t signature;
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint16_t volume_attributes;
|
||||
uint16_t files_in_root;
|
||||
uint16_t volume_bitmap_block; /* in sectors */
|
||||
uint16_t next_allocation;
|
||||
uint16_t total_blocks;
|
||||
uint32_t block_size; /* in bytes */
|
||||
uint32_t def_clump_size; /* in bytes */
|
||||
uint16_t start_block; /* in sectors */
|
||||
uint32_t next_free_node;
|
||||
uint16_t free_blocks;
|
||||
uint8_t name_length;
|
||||
char name[27];
|
||||
uint32_t backup_date;
|
||||
uint16_t backup_number;
|
||||
uint32_t write_count;
|
||||
uint32_t extents_clump;
|
||||
uint32_t catalog_clump;
|
||||
uint16_t dirs_in_root;
|
||||
uint32_t file_count;
|
||||
uint32_t dir_count;
|
||||
uint32_t finder_info[8];
|
||||
union __attribute__ ((packed)) {
|
||||
struct __attribute__ ((packed)) {
|
||||
uint16_t volume_cache_size; /* in blocks */
|
||||
uint16_t bitmap_cache_size; /* in blocks */
|
||||
uint16_t common_cache_size; /* in blocks */
|
||||
} legacy;
|
||||
struct __attribute__ ((packed)) {
|
||||
uint16_t signature;
|
||||
HfsExtDescriptor location;
|
||||
} embedded;
|
||||
} old_new;
|
||||
uint32_t extents_file_size; /* in bytes, block size multiple */
|
||||
HfsExtDataRec extents_file_rec;
|
||||
uint32_t catalog_file_size; /* in bytes, block size multiple */
|
||||
HfsExtDataRec catalog_file_rec;
|
||||
};
|
||||
typedef struct _HfsMasterDirectoryBlock HfsMasterDirectoryBlock;
|
||||
|
||||
/* B*-Tree Node Descriptor */
|
||||
struct __attribute__ ((packed)) _HfsNodeDescriptor {
|
||||
uint32_t next;
|
||||
uint32_t previous;
|
||||
int8_t type;
|
||||
uint8_t height;
|
||||
uint16_t rec_nb;
|
||||
uint16_t reserved;
|
||||
};
|
||||
typedef struct _HfsNodeDescriptor HfsNodeDescriptor;
|
||||
|
||||
/* Header record of a whole B*-Tree */
|
||||
struct __attribute__ ((packed)) _HfsHeaderRecord {
|
||||
uint16_t depth;
|
||||
uint32_t root_node;
|
||||
uint32_t leaf_records;
|
||||
uint32_t first_leaf_node;
|
||||
uint32_t last_leaf_node;
|
||||
uint16_t node_size;
|
||||
uint16_t max_key_len;
|
||||
uint32_t total_nodes;
|
||||
uint32_t free_nodes;
|
||||
int8_t reserved[76];
|
||||
};
|
||||
typedef struct _HfsHeaderRecord HfsHeaderRecord;
|
||||
|
||||
/* Catalog key for B*-Tree lookup in the catalog file */
|
||||
struct __attribute__ ((packed)) _HfsCatalogKey {
|
||||
uint8_t key_length; /* length of the key without key_length */
|
||||
uint8_t reserved;
|
||||
uint32_t parent_ID;
|
||||
uint8_t name_length;
|
||||
char name[31]; /* in fact physicaly 1 upto 31 */
|
||||
};
|
||||
typedef struct _HfsCatalogKey HfsCatalogKey;
|
||||
|
||||
/* Extents overflow key for B*-Tree lookup */
|
||||
struct __attribute__ ((packed)) _HfsExtentKey {
|
||||
uint8_t key_length; /* length of the key without key_length */
|
||||
uint8_t type; /* data or ressource fork */
|
||||
uint32_t file_ID;
|
||||
uint16_t start;
|
||||
};
|
||||
typedef struct _HfsExtentKey HfsExtentKey;
|
||||
|
||||
/* Catalog subdata case directory */
|
||||
struct __attribute__ ((packed)) _HfsDir {
|
||||
uint16_t flags;
|
||||
uint16_t valence; /* number of files in this directory */
|
||||
uint32_t dir_ID;
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint32_t backup_date;
|
||||
int8_t DInfo[16]; /* used by Finder, handle as reserved */
|
||||
int8_t DXInfo[16]; /* used by Finder, handle as reserved */
|
||||
uint32_t reserved[4];
|
||||
};
|
||||
typedef struct _HfsDir HfsDir;
|
||||
|
||||
/* Catalog subdata case file */
|
||||
struct __attribute__ ((packed)) _HfsFile {
|
||||
int8_t flags;
|
||||
int8_t type; /* should be 0 */
|
||||
int8_t FInfo[16]; /* used by Finder, handle as reserved */
|
||||
uint32_t file_ID;
|
||||
uint16_t data_start_block;
|
||||
uint32_t data_sz_byte;
|
||||
uint32_t data_sz_block;
|
||||
uint16_t res_start_block;
|
||||
uint32_t res_sz_byte;
|
||||
uint32_t res_sz_block;
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint32_t backup_date;
|
||||
int8_t FXInfo[16]; /* used by Finder, handle as reserved */
|
||||
uint16_t clump_size;
|
||||
HfsExtDataRec extents_data;
|
||||
HfsExtDataRec extents_res;
|
||||
uint32_t reserved;
|
||||
};
|
||||
typedef struct _HfsFile HfsFile;
|
||||
|
||||
/* Catalog subdata case directory thread */
|
||||
struct __attribute__ ((packed)) _HfsDirTh {
|
||||
uint32_t reserved[2];
|
||||
uint32_t parent_ID;
|
||||
int8_t name_length;
|
||||
char name[31];
|
||||
};
|
||||
typedef struct _HfsDirTh HfsDirTh;
|
||||
|
||||
/* Catalog subdata case file thread */
|
||||
typedef struct _HfsDirTh HfsFileTh; /* same as directory thread */
|
||||
|
||||
/* Catalog data */
|
||||
struct __attribute__ ((packed)) _HfsCatalog {
|
||||
int8_t type;
|
||||
int8_t reserved;
|
||||
union {
|
||||
HfsDir dir;
|
||||
HfsFile file;
|
||||
HfsDirTh dir_th;
|
||||
HfsFileTh file_th;
|
||||
} sel;
|
||||
};
|
||||
typedef struct _HfsCatalog HfsCatalog;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------ */
|
||||
/* -- HFS+ DATA STRUCTURES -- */
|
||||
/* ------------------------------------ */
|
||||
|
||||
/* documented since 2004 in tn1150 */
|
||||
struct __attribute__ ((packed)) _HfsPPerms {
|
||||
uint32_t owner_ID;
|
||||
uint32_t group_ID;
|
||||
uint32_t permissions;
|
||||
uint32_t special_devices;
|
||||
};
|
||||
typedef struct _HfsPPerms HfsPPerms;
|
||||
|
||||
/* HFS+ extent descriptor*/
|
||||
struct __attribute__ ((packed)) _HfsPExtDescriptor {
|
||||
uint32_t start_block;
|
||||
uint32_t block_count;
|
||||
};
|
||||
typedef struct _HfsPExtDescriptor HfsPExtDescriptor;
|
||||
typedef HfsPExtDescriptor HfsPExtDataRec[HFSP_EXT_NB];
|
||||
|
||||
/* HFS+ fork data structure */
|
||||
struct __attribute__ ((packed)) _HfsPForkData {
|
||||
uint64_t logical_size;
|
||||
uint32_t clump_size;
|
||||
uint32_t total_blocks;
|
||||
HfsPExtDataRec extents;
|
||||
};
|
||||
typedef struct _HfsPForkData HfsPForkData;
|
||||
|
||||
/* HFS+ catalog node ID */
|
||||
typedef uint32_t HfsPNodeID;
|
||||
|
||||
/* HFS+ file names */
|
||||
typedef uint16_t unichar;
|
||||
struct __attribute__ ((packed)) _HfsPUniStr255 {
|
||||
uint16_t length;
|
||||
unichar unicode[255]; /* 1 upto 255 */
|
||||
};
|
||||
typedef struct _HfsPUniStr255 HfsPUniStr255;
|
||||
|
||||
/* HFS+ volume header */
|
||||
struct __attribute__ ((packed)) _HfsPVolumeHeader {
|
||||
uint16_t signature;
|
||||
uint16_t version;
|
||||
uint32_t attributes;
|
||||
uint32_t last_mounted_version;
|
||||
uint32_t journal_info_block;
|
||||
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint32_t backup_date;
|
||||
uint32_t checked_date;
|
||||
|
||||
uint32_t file_count;
|
||||
uint32_t dir_count;
|
||||
|
||||
uint32_t block_size;
|
||||
uint32_t total_blocks;
|
||||
uint32_t free_blocks;
|
||||
|
||||
uint32_t next_allocation;
|
||||
uint32_t res_clump_size;
|
||||
uint32_t data_clump_size;
|
||||
HfsPNodeID next_catalog_ID;
|
||||
|
||||
uint32_t write_count;
|
||||
uint64_t encodings_bitmap;
|
||||
|
||||
uint8_t finder_info[32];
|
||||
|
||||
HfsPForkData allocation_file;
|
||||
HfsPForkData extents_file;
|
||||
HfsPForkData catalog_file;
|
||||
HfsPForkData attributes_file;
|
||||
HfsPForkData startup_file;
|
||||
};
|
||||
typedef struct _HfsPVolumeHeader HfsPVolumeHeader;
|
||||
|
||||
/* HFS+ B-Tree Node Descriptor. Same as HFS btree. */
|
||||
struct __attribute__ ((packed)) _HfsPNodeDescriptor {
|
||||
uint32_t next;
|
||||
uint32_t previous;
|
||||
int8_t type;
|
||||
uint8_t height;
|
||||
uint16_t rec_nb;
|
||||
uint16_t reserved;
|
||||
};
|
||||
typedef struct _HfsPNodeDescriptor HfsPNodeDescriptor;
|
||||
|
||||
/* Header record of a whole HFS+ B-Tree. */
|
||||
struct __attribute__ ((packed)) _HfsPHeaderRecord {
|
||||
uint16_t depth;
|
||||
uint32_t root_node;
|
||||
uint32_t leaf_records;
|
||||
uint32_t first_leaf_node;
|
||||
uint32_t last_leaf_node;
|
||||
uint16_t node_size;
|
||||
uint16_t max_key_len;
|
||||
uint32_t total_nodes;
|
||||
uint32_t free_nodes; /* same as hfs btree until here */
|
||||
uint16_t reserved1;
|
||||
|
||||
uint32_t clump_size;
|
||||
uint8_t btree_type; /* must be 0 for HFS+ B-Tree */
|
||||
uint8_t key_compare_type; /* hfsx => 0xCF = case folding */
|
||||
/* 0xBC = binary compare */
|
||||
/* otherwise, reserved */
|
||||
uint32_t attributes;
|
||||
uint32_t reserved3[16];
|
||||
};
|
||||
typedef struct _HfsPHeaderRecord HfsPHeaderRecord;
|
||||
|
||||
/* Catalog key for B-Tree lookup in the HFS+ catalog file */
|
||||
struct __attribute__ ((packed)) _HfsPCatalogKey {
|
||||
uint16_t key_length;
|
||||
HfsPNodeID parent_ID;
|
||||
HfsPUniStr255 node_name;
|
||||
};
|
||||
typedef struct _HfsPCatalogKey HfsPCatalogKey;
|
||||
|
||||
/* HFS+ catalog subdata case dir */
|
||||
struct __attribute__ ((packed)) _HfsPDir {
|
||||
uint16_t flags;
|
||||
uint32_t valence;
|
||||
HfsPNodeID dir_ID;
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint32_t attrib_mod_date;
|
||||
uint32_t access_date;
|
||||
uint32_t backup_date;
|
||||
HfsPPerms permissions;
|
||||
int8_t DInfo[16]; /* used by Finder, handle as reserved */
|
||||
int8_t DXInfo[16]; /* used by Finder, handle as reserved */
|
||||
uint32_t text_encoding;
|
||||
uint32_t reserved;
|
||||
};
|
||||
typedef struct _HfsPDir HfsPDir;
|
||||
|
||||
/* HFS+ catalog subdata case file */
|
||||
struct __attribute__ ((packed)) _HfsPFile {
|
||||
uint16_t flags;
|
||||
uint32_t reserved1;
|
||||
HfsPNodeID file_ID;
|
||||
uint32_t create_date;
|
||||
uint32_t modify_date;
|
||||
uint32_t attrib_mod_date;
|
||||
uint32_t access_date;
|
||||
uint32_t backup_date;
|
||||
HfsPPerms permissions;
|
||||
int8_t FInfo[16]; /* used by Finder, handle as reserved */
|
||||
int8_t FXInfo[16]; /* used by Finder, handle as reserved */
|
||||
uint32_t text_encoding;
|
||||
uint32_t reserved2;
|
||||
|
||||
HfsPForkData data_fork;
|
||||
HfsPForkData res_fork;
|
||||
};
|
||||
typedef struct _HfsPFile HfsPFile;
|
||||
|
||||
/* HFS+ catalog subdata case thread */
|
||||
struct __attribute__ ((packed)) _HfsPThread {
|
||||
int16_t reserved;
|
||||
HfsPNodeID parent_ID;
|
||||
HfsPUniStr255 node_name;
|
||||
};
|
||||
typedef struct _HfsPThread HfsPDirTh;
|
||||
typedef struct _HfsPThread HfsPFileTh;
|
||||
|
||||
/* HFS+ Catalog leaf data */
|
||||
struct __attribute__ ((packed)) _HfsPCatalog {
|
||||
int16_t type;
|
||||
union {
|
||||
HfsPDir dir;
|
||||
HfsPFile file;
|
||||
HfsPDirTh dir_th;
|
||||
HfsPFileTh file_th;
|
||||
} sel;
|
||||
};
|
||||
typedef struct _HfsPCatalog HfsPCatalog;
|
||||
|
||||
/* HFS+ extents file key */
|
||||
struct __attribute__ ((packed)) _HfsPExtentKey {
|
||||
uint16_t key_length;
|
||||
uint8_t type;
|
||||
uint8_t pad;
|
||||
HfsPNodeID file_ID;
|
||||
uint32_t start;
|
||||
};
|
||||
typedef struct _HfsPExtentKey HfsPExtentKey;
|
||||
|
||||
/* extent file data is HfsPExtDataRec */
|
||||
|
||||
/* Fork data attribute file */
|
||||
struct __attribute__ ((packed)) _HfsPForkDataAttr {
|
||||
uint32_t record_type;
|
||||
uint32_t reserved;
|
||||
union __attribute__ ((packed)) {
|
||||
HfsPForkData fork;
|
||||
HfsPExtDataRec extents;
|
||||
} fork_res;
|
||||
};
|
||||
typedef struct _HfsPForkDataAttr HfsPForkDataAttr;
|
||||
|
||||
|
||||
/* ----------- Journal data structures ----------- */
|
||||
|
||||
/* Info block : stored in a block # defined in the VH */
|
||||
struct __attribute__ ((packed)) _HfsJJournalInfoBlock {
|
||||
uint32_t flags;
|
||||
uint32_t device_signature[8];
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
uint32_t reserved[32];
|
||||
};
|
||||
typedef struct _HfsJJournalInfoBlock HfsJJournalInfoBlock;
|
||||
|
||||
struct __attribute__ ((packed)) _HfsJJournalHeader {
|
||||
uint32_t magic;
|
||||
uint32_t endian;
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
uint64_t size;
|
||||
uint32_t blhdr_size;
|
||||
uint32_t checksum;
|
||||
uint32_t jhdr_size;
|
||||
};
|
||||
typedef struct _HfsJJournalHeader HfsJJournalHeader;
|
||||
|
||||
struct __attribute__ ((packed)) _HfsJBlockInfo {
|
||||
uint64_t bnum; /* sector number */
|
||||
uint32_t bsize; /* size in bytes */
|
||||
uint32_t next;
|
||||
};
|
||||
typedef struct _HfsJBlockInfo HfsJBlockInfo;
|
||||
|
||||
struct __attribute__ ((packed)) _HfsJBlockListHeader {
|
||||
uint16_t max_blocks; /* reserved */
|
||||
uint16_t num_blocks;
|
||||
uint32_t bytes_used;
|
||||
uint32_t checksum;
|
||||
uint32_t pad;
|
||||
HfsJBlockInfo binfo[];
|
||||
};
|
||||
typedef struct _HfsJBlockListHeader HfsJBlockListHeader;
|
||||
|
||||
|
||||
|
||||
/* ---------------------------------------- */
|
||||
/* -- INTERNAL DATA STRUCTURES -- */
|
||||
/* ---------------------------------------- */
|
||||
|
||||
/* Data of an opened HFS file */
|
||||
struct _HfsPrivateFile {
|
||||
PedSector sect_nb;
|
||||
PedFileSystem* fs;
|
||||
uint32_t CNID; /* disk order (BE) */
|
||||
HfsExtDataRec first; /* disk order (BE) */
|
||||
HfsExtDataRec cache; /* disk order (BE) */
|
||||
uint16_t start_cache; /* CPU order */
|
||||
};
|
||||
typedef struct _HfsPrivateFile HfsPrivateFile;
|
||||
|
||||
/* To store bad block list */
|
||||
struct _HfsPrivateLinkExtent {
|
||||
HfsExtDescriptor extent;
|
||||
struct _HfsPrivateLinkExtent* next;
|
||||
};
|
||||
typedef struct _HfsPrivateLinkExtent HfsPrivateLinkExtent;
|
||||
|
||||
/* HFS Filesystem specific data */
|
||||
struct _HfsPrivateFSData {
|
||||
uint8_t alloc_map[(1<<16) / 8];
|
||||
HfsMasterDirectoryBlock* mdb;
|
||||
HfsPrivateFile* extent_file;
|
||||
HfsPrivateFile* catalog_file;
|
||||
HfsPrivateLinkExtent* bad_blocks_xtent_list;
|
||||
unsigned int bad_blocks_xtent_nb;
|
||||
char bad_blocks_loaded;
|
||||
};
|
||||
typedef struct _HfsPrivateFSData HfsPrivateFSData;
|
||||
|
||||
/* Generic btree key */
|
||||
struct __attribute__ ((packed)) _HfsPrivateGenericKey {
|
||||
uint8_t key_length;
|
||||
uint8_t key_content[1]; /* we use 1 as a minimum size */
|
||||
};
|
||||
typedef struct _HfsPrivateGenericKey HfsPrivateGenericKey;
|
||||
|
||||
/* ----- HFS+ ----- */
|
||||
|
||||
/* Data of an opened HFS file */
|
||||
struct _HfsPPrivateFile {
|
||||
PedSector sect_nb;
|
||||
PedFileSystem* fs;
|
||||
HfsPNodeID CNID; /* disk order (BE) */
|
||||
HfsPExtDataRec first; /* disk order (BE) */
|
||||
HfsPExtDataRec cache; /* disk order (BE) */
|
||||
uint32_t start_cache; /* CPU order */
|
||||
};
|
||||
typedef struct _HfsPPrivateFile HfsPPrivateFile;
|
||||
|
||||
struct _HfsPPrivateExtent {
|
||||
PedSector start_sector;
|
||||
PedSector sector_count;
|
||||
};
|
||||
typedef struct _HfsPPrivateExtent HfsPPrivateExtent;
|
||||
|
||||
/* To store bad block list */
|
||||
struct _HfsPPrivateLinkExtent {
|
||||
HfsPExtDescriptor extent;
|
||||
struct _HfsPPrivateLinkExtent* next;
|
||||
};
|
||||
typedef struct _HfsPPrivateLinkExtent HfsPPrivateLinkExtent;
|
||||
|
||||
/* HFS+ file system specific data */
|
||||
struct _HfsPPrivateFSData {
|
||||
PedFileSystem* wrapper; /* NULL if hfs+ is not embedded */
|
||||
PedGeometry* plus_geom; /* Geometry of HFS+ _volume_ */
|
||||
uint8_t* alloc_map;
|
||||
uint8_t* dirty_alloc_map;
|
||||
HfsPVolumeHeader* vh;
|
||||
HfsPPrivateFile* extents_file;
|
||||
HfsPPrivateFile* catalog_file;
|
||||
HfsPPrivateFile* attributes_file;
|
||||
HfsPPrivateFile* allocation_file;
|
||||
HfsPPrivateLinkExtent* bad_blocks_xtent_list;
|
||||
uint32_t jib_start_block;
|
||||
uint32_t jl_start_block;
|
||||
unsigned int bad_blocks_xtent_nb;
|
||||
char bad_blocks_loaded;
|
||||
char free_geom; /* 1 = plus_geom must be freed */
|
||||
};
|
||||
typedef struct _HfsPPrivateFSData HfsPPrivateFSData;
|
||||
|
||||
/* Generic + btree key */
|
||||
struct __attribute__ ((packed)) _HfsPPrivateGenericKey {
|
||||
uint16_t key_length;
|
||||
uint8_t key_content[1]; /* we use 1 as a minimum size */
|
||||
};
|
||||
typedef struct _HfsPPrivateGenericKey HfsPPrivateGenericKey;
|
||||
|
||||
/* ---- common ---- */
|
||||
|
||||
/* node and lead record reference for a BTree search */
|
||||
struct _HfsCPrivateLeafRec {
|
||||
unsigned int node_size; /* in sectors */
|
||||
unsigned int node_number;
|
||||
unsigned int record_pos;
|
||||
unsigned int record_number;
|
||||
};
|
||||
typedef struct _HfsCPrivateLeafRec HfsCPrivateLeafRec;
|
||||
|
||||
extern uint8_t* hfs_block;
|
||||
extern uint8_t* hfsp_block;
|
||||
extern unsigned hfs_block_count;
|
||||
extern unsigned hfsp_block_count;
|
||||
|
||||
#endif /* _HFS_H */
|
||||
@@ -1,392 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
#include "reloc_plus.h"
|
||||
|
||||
#include "journal.h"
|
||||
|
||||
static int hfsj_vh_replayed = 0;
|
||||
static int is_le = 0;
|
||||
|
||||
static uint32_t
|
||||
hfsj_calc_checksum(uint8_t *ptr, int len)
|
||||
{
|
||||
int i;
|
||||
uint32_t cksum=0;
|
||||
|
||||
for (i=0; i < len; i++, ptr++) {
|
||||
cksum = (cksum << 8) ^ (cksum + *ptr);
|
||||
}
|
||||
|
||||
return (~cksum);
|
||||
}
|
||||
|
||||
int
|
||||
hfsj_update_jib(PedFileSystem* fs, uint32_t block)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
|
||||
priv_data->vh->journal_info_block = PED_CPU_TO_BE32(block);
|
||||
|
||||
if (!hfsplus_update_vh (fs))
|
||||
return 0;
|
||||
|
||||
priv_data->jib_start_block = block;
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Return the sector in the journal that is after the area read */
|
||||
/* or 0 on error */
|
||||
static PedSector
|
||||
hfsj_journal_read(PedGeometry* geom, HfsJJournalHeader* jh,
|
||||
PedSector journ_sect, PedSector journ_length,
|
||||
PedSector read_sect, unsigned int nb_sect,
|
||||
void* buf)
|
||||
{
|
||||
int r;
|
||||
|
||||
while (nb_sect--) {
|
||||
r = ped_geometry_read(geom, buf, journ_sect + read_sect, 1);
|
||||
if (!r) return 0;
|
||||
|
||||
buf = ((uint8_t*)buf) + PED_SECTOR_SIZE_DEFAULT;
|
||||
read_sect++;
|
||||
if (read_sect == journ_length)
|
||||
read_sect = 1; /* skip journal header
|
||||
which is asserted to be
|
||||
1 sector long */
|
||||
}
|
||||
|
||||
return read_sect;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 0 => Failure, don't continue to open ! */
|
||||
/* 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 deactivate 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);
|
||||
|
||||
/* https://github.com/apple-opensource/hfs/blob/master/core/hfs_journal.c#L1167
|
||||
* indicates that this is:
|
||||
* wrap the start ptr if it points to the very end of the journal
|
||||
*/
|
||||
if (jh->start == jh->size)
|
||||
jh->start = HFS_CPU_TO_64(PED_SECTOR_SIZE_DEFAULT, is_le);
|
||||
if (jh->end == jh->size)
|
||||
jh->end = 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;
|
||||
}
|
||||
|
||||
#endif /* DISCOVER_ONLY */
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 _JOURNAL_H
|
||||
#define _JOURNAL_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfsj_replay_journal(PedFileSystem* fs);
|
||||
|
||||
int
|
||||
hfsj_update_jib(PedFileSystem* fs, uint32_t block);
|
||||
|
||||
int
|
||||
hfsj_update_jl(PedFileSystem* fs, uint32_t block);
|
||||
|
||||
#define HFS_16_TO_CPU(x, is_little_endian) ((is_little_endian) ? (uint16_t)PED_LE16_TO_CPU(x) : (uint16_t)PED_BE16_TO_CPU(x))
|
||||
#define HFS_32_TO_CPU(x, is_little_endian) ((is_little_endian) ? (uint32_t)PED_LE32_TO_CPU(x) : (uint32_t)PED_BE32_TO_CPU(x))
|
||||
#define HFS_64_TO_CPU(x, is_little_endian) ((is_little_endian) ? (uint64_t)PED_LE64_TO_CPU(x) : (uint64_t)PED_BE64_TO_CPU(x))
|
||||
#define HFS_CPU_TO_16(x, is_little_endian) ((is_little_endian) ? (uint16_t)PED_CPU_TO_LE16(x) : (uint16_t)PED_CPU_TO_BE16(x))
|
||||
#define HFS_CPU_TO_32(x, is_little_endian) ((is_little_endian) ? (uint32_t)PED_CPU_TO_LE32(x) : (uint32_t)PED_CPU_TO_BE32(x))
|
||||
#define HFS_CPU_TO_64(x, is_little_endian) ((is_little_endian) ? (uint64_t)PED_CPU_TO_LE64(x) : (uint64_t)PED_CPU_TO_BE64(x))
|
||||
|
||||
#endif /* _JOURNAL_H */
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
#include "probe.h"
|
||||
|
||||
int
|
||||
hfsc_can_use_geom (PedGeometry* geom)
|
||||
{
|
||||
PedDevice* dev;
|
||||
|
||||
dev = geom->dev;
|
||||
PED_ASSERT (geom != NULL);
|
||||
PED_ASSERT (dev != NULL);
|
||||
|
||||
if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Parted can't use HFS file systems on disks "
|
||||
"with a sector size not equal to %d bytes."),
|
||||
(int)PED_SECTOR_SIZE_DEFAULT );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Probe an HFS volume, detecting it even if
|
||||
it is in fact a wrapper to an HFS+ volume */
|
||||
/* Used by hfsplus_probe and hfs_probe */
|
||||
PedGeometry*
|
||||
hfs_and_wrapper_probe (PedGeometry* geom)
|
||||
{
|
||||
uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
|
||||
HfsMasterDirectoryBlock *mdb;
|
||||
PedGeometry* geom_ret;
|
||||
PedSector search, max;
|
||||
|
||||
PED_ASSERT (geom != NULL);
|
||||
PED_ASSERT (hfsc_can_use_geom (geom));
|
||||
|
||||
mdb = (HfsMasterDirectoryBlock *) buf;
|
||||
|
||||
/* is 5 an intelligent value ? */
|
||||
if ((geom->length < 5)
|
||||
|| (!ped_geometry_read (geom, buf, 2, 1))
|
||||
|| (mdb->signature != PED_CPU_TO_BE16 (HFS_SIGNATURE)) )
|
||||
return NULL;
|
||||
|
||||
search = ((PedSector) PED_BE16_TO_CPU (mdb->start_block)
|
||||
+ ((PedSector) PED_BE16_TO_CPU (mdb->total_blocks)
|
||||
* (PED_BE32_TO_CPU (mdb->block_size) / PED_SECTOR_SIZE_DEFAULT )));
|
||||
max = search + (PED_BE32_TO_CPU (mdb->block_size) / PED_SECTOR_SIZE_DEFAULT);
|
||||
if (!(geom_ret = ped_geometry_new (geom->dev, geom->start, search + 2)))
|
||||
return NULL;
|
||||
|
||||
for (; search < max; search++) {
|
||||
if (!ped_geometry_set (geom_ret, geom_ret->start, search + 2)
|
||||
|| !ped_geometry_read (geom_ret, buf, search, 1))
|
||||
break;
|
||||
if (mdb->signature == PED_CPU_TO_BE16 (HFS_SIGNATURE))
|
||||
return geom_ret;
|
||||
}
|
||||
|
||||
ped_geometry_destroy (geom_ret);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 _PROBE_H
|
||||
#define _PROBE_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfsc_can_use_geom (PedGeometry* geom);
|
||||
|
||||
PedGeometry*
|
||||
hfs_and_wrapper_probe (PedGeometry* geom);
|
||||
|
||||
#endif /* _PROBE_H */
|
||||
@@ -1,676 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#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
|
||||
hfs_effect_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock,
|
||||
unsigned int *ptr_to_fblock, unsigned int size)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
unsigned int i, ok = 0;
|
||||
unsigned int next_to_fblock;
|
||||
unsigned int start, stop;
|
||||
|
||||
PED_ASSERT (hfs_block != NULL);
|
||||
PED_ASSERT (*ptr_to_fblock <= *ptr_fblock);
|
||||
/* quiet gcc */
|
||||
start = stop = 0;
|
||||
|
||||
/*
|
||||
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 = stop = *ptr_fblock < *ptr_to_fblock+size ?
|
||||
*ptr_fblock : *ptr_to_fblock+size;
|
||||
while (start && stop-start != size) {
|
||||
--start;
|
||||
if (TST_BLOC_OCCUPATION(priv_data->alloc_map,start))
|
||||
stop = start;
|
||||
}
|
||||
ok = (stop-start == size);
|
||||
}
|
||||
|
||||
/* Forward search */
|
||||
/* 1 pass relocation in the gap merged with 2 pass reloc after source */
|
||||
if (!ok && *ptr_to_fblock != *ptr_fblock) {
|
||||
start = stop = *ptr_to_fblock+1;
|
||||
while (stop < PED_BE16_TO_CPU(priv_data->mdb->total_blocks)
|
||||
&& stop-start != size) {
|
||||
if (TST_BLOC_OCCUPATION(priv_data->alloc_map,stop))
|
||||
start = stop + 1;
|
||||
++stop;
|
||||
}
|
||||
ok = (stop-start == size);
|
||||
}
|
||||
|
||||
/* new non overlapping room has been found ? */
|
||||
if (ok) {
|
||||
/* enough room */
|
||||
unsigned int j;
|
||||
unsigned int start_block =
|
||||
PED_BE16_TO_CPU (priv_data->mdb->start_block );
|
||||
unsigned int block_sz =
|
||||
(PED_BE32_TO_CPU (priv_data->mdb->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT);
|
||||
|
||||
if (stop > *ptr_to_fblock && stop <= *ptr_fblock)
|
||||
/* Fit in the gap */
|
||||
next_to_fblock = stop;
|
||||
else
|
||||
/* Before or after the gap */
|
||||
next_to_fblock = *ptr_to_fblock;
|
||||
|
||||
/* move blocks */
|
||||
for (i = 0; i < size; /*i+=j*/) {
|
||||
PedSector abs_sector;
|
||||
unsigned int ai;
|
||||
|
||||
j = size - i; j = (j < hfs_block_count) ?
|
||||
j : hfs_block_count ;
|
||||
|
||||
abs_sector = start_block
|
||||
+ (PedSector) (*ptr_fblock + i) * block_sz;
|
||||
if (!ped_geometry_read (fs->geom, hfs_block, abs_sector,
|
||||
block_sz * j))
|
||||
return -1;
|
||||
|
||||
abs_sector = start_block
|
||||
+ (PedSector) (start + i) * block_sz;
|
||||
if (!ped_geometry_write (fs->geom,hfs_block,abs_sector,
|
||||
block_sz * j))
|
||||
return -1;
|
||||
|
||||
for (ai = i+j; i < ai; i++) {
|
||||
/* free source block */
|
||||
CLR_BLOC_OCCUPATION(priv_data->alloc_map,
|
||||
*ptr_fblock + i);
|
||||
|
||||
/* set dest block */
|
||||
SET_BLOC_OCCUPATION(priv_data->alloc_map,
|
||||
start + i);
|
||||
}
|
||||
}
|
||||
if (!ped_geometry_sync_fast (fs->geom))
|
||||
return -1;
|
||||
|
||||
*ptr_fblock += size;
|
||||
*ptr_to_fblock = next_to_fblock;
|
||||
} else {
|
||||
if (*ptr_fblock != *ptr_to_fblock)
|
||||
/* not enough room, but try to continue */
|
||||
ped_exception_throw (PED_EXCEPTION_WARNING,
|
||||
PED_EXCEPTION_IGNORE,
|
||||
_("An extent has not been relocated."));
|
||||
start = *ptr_fblock;
|
||||
*ptr_fblock = *ptr_to_fblock = start + size;
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
/* Update MDB */
|
||||
/* Return 0 if an error occurred */
|
||||
/* Return 1 if everything ok */
|
||||
int
|
||||
hfs_update_mdb (PedFileSystem *fs)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
|
||||
|
||||
if (!ped_geometry_read (fs->geom, node, 2, 1))
|
||||
return 0;
|
||||
memcpy (node, priv_data->mdb, sizeof (HfsMasterDirectoryBlock));
|
||||
if ( !ped_geometry_write (fs->geom, node, 2, 1)
|
||||
|| !ped_geometry_write (fs->geom, node, fs->geom->length - 2, 1)
|
||||
|| !ped_geometry_sync_fast (fs->geom))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generic relocator */
|
||||
/* replace previous hfs_do_move_* */
|
||||
static int
|
||||
hfs_do_move (PedFileSystem* fs, unsigned int *ptr_src,
|
||||
unsigned int *ptr_dest, HfsCPrivateCache* cache,
|
||||
HfsCPrivateExtent* ref)
|
||||
{
|
||||
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPrivateFile* file;
|
||||
HfsExtDescriptor* extent;
|
||||
HfsCPrivateExtent* move;
|
||||
int new_start;
|
||||
|
||||
new_start = hfs_effect_move_extent (fs, ptr_src, ptr_dest,
|
||||
ref->ext_length);
|
||||
if (new_start == -1) return -1;
|
||||
|
||||
if (ref->ext_start != (unsigned) new_start) {
|
||||
/* Load, modify & save */
|
||||
switch (ref->where) {
|
||||
/******** MDB *********/
|
||||
case CR_PRIM_CAT :
|
||||
priv_data->catalog_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE16(new_start);
|
||||
goto CR_PRIM;
|
||||
case CR_PRIM_EXT :
|
||||
priv_data->extent_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE16(new_start);
|
||||
CR_PRIM :
|
||||
extent = ( HfsExtDescriptor* )
|
||||
( (uint8_t*)priv_data->mdb + ref->ref_offset );
|
||||
extent[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE16(new_start);
|
||||
if (!hfs_update_mdb(fs)) return -1;
|
||||
break;
|
||||
|
||||
/********* BTREE *******/
|
||||
case CR_BTREE_EXT_CAT :
|
||||
if (priv_data->catalog_file
|
||||
->cache[ref->ref_index].start_block
|
||||
== PED_CPU_TO_BE16(ref->ext_start))
|
||||
priv_data->catalog_file
|
||||
->cache[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE16(new_start);
|
||||
/* FALLTHROUGH */
|
||||
case CR_BTREE_EXT_0 :
|
||||
file = priv_data->extent_file;
|
||||
goto CR_BTREE;
|
||||
case CR_BTREE_CAT :
|
||||
file = priv_data->catalog_file;
|
||||
CR_BTREE:
|
||||
PED_ASSERT(ref->sect_by_block == 1
|
||||
&& ref->ref_offset < PED_SECTOR_SIZE_DEFAULT);
|
||||
if (!hfs_file_read_sector(file, node, ref->ref_block))
|
||||
return -1;
|
||||
extent = ( HfsExtDescriptor* ) (node + ref->ref_offset);
|
||||
extent[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE16(new_start);
|
||||
if (!hfs_file_write_sector(file, node, ref->ref_block)
|
||||
|| !ped_geometry_sync_fast (fs->geom))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
/********** BUG ********/
|
||||
default :
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("A reference to an extent comes from a place "
|
||||
"it should not. You should check the file "
|
||||
"system!"));
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update the cache */
|
||||
move = hfsc_cache_move_extent(cache, ref->ext_start, new_start);
|
||||
if (!move) return -1; /* "cleanly" fail */
|
||||
PED_ASSERT(move == ref); /* generate a bug */
|
||||
}
|
||||
|
||||
return new_start;
|
||||
}
|
||||
|
||||
/* 0 error, 1 ok */
|
||||
static int
|
||||
hfs_save_allocation(PedFileSystem* fs)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
unsigned int map_sectors;
|
||||
|
||||
map_sectors = ( PED_BE16_TO_CPU (priv_data->mdb->total_blocks)
|
||||
+ PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
|
||||
/ (PED_SECTOR_SIZE_DEFAULT * 8);
|
||||
return ( ped_geometry_write (fs->geom, priv_data->alloc_map,
|
||||
PED_BE16_TO_CPU (priv_data->mdb->volume_bitmap_block),
|
||||
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
|
||||
hfs_move_extent_starting_at (PedFileSystem *fs, unsigned int *ptr_fblock,
|
||||
unsigned int *ptr_to_fblock,
|
||||
HfsCPrivateCache* cache)
|
||||
{
|
||||
HfsCPrivateExtent* ref;
|
||||
unsigned int old_start, new_start;
|
||||
|
||||
/* Reference search powered by the cache... */
|
||||
/* This is the optimisation secret :) */
|
||||
ref = hfsc_cache_search_extent(cache, *ptr_fblock);
|
||||
if (!ref) return 0; /* not found */
|
||||
|
||||
old_start = *ptr_fblock;
|
||||
new_start = hfs_do_move(fs, ptr_fblock, ptr_to_fblock, cache, ref);
|
||||
if (new_start == (unsigned int) -1) return -1;
|
||||
if (new_start > old_start) { /* detect 2 pass reloc */
|
||||
new_start = hfs_do_move(fs,&new_start,ptr_to_fblock,cache,ref);
|
||||
if (new_start == (unsigned int) -1 || new_start > old_start)
|
||||
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 */
|
||||
hfs_save_allocation(fs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfs_cache_from_mdb(HfsCPrivateCache* cache, PedFileSystem* fs,
|
||||
PedTimer* timer)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsExtDescriptor* extent;
|
||||
unsigned int j;
|
||||
|
||||
extent = priv_data->mdb->extents_file_rec;
|
||||
for (j = 0; j < HFS_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE16_TO_CPU(extent[j].start_block),
|
||||
PED_BE16_TO_CPU(extent[j].block_count),
|
||||
0, /* unused for mdb */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->mdb),
|
||||
1, /* load/save only 1 sector */
|
||||
CR_PRIM_EXT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = priv_data->mdb->catalog_file_rec;
|
||||
for (j = 0; j < HFS_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE16_TO_CPU(extent[j].start_block),
|
||||
PED_BE16_TO_CPU(extent[j].block_count),
|
||||
0,
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->mdb),
|
||||
1,
|
||||
CR_PRIM_CAT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfs_cache_from_catalog(HfsCPrivateCache* cache, PedFileSystem* fs,
|
||||
PedTimer* timer)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
|
||||
HfsHeaderRecord* header;
|
||||
HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
|
||||
HfsCatalogKey* catalog_key;
|
||||
HfsCatalog* catalog_data;
|
||||
HfsExtDescriptor* extent;
|
||||
unsigned int leaf_node, record_number;
|
||||
unsigned int i, j;
|
||||
uint16_t catalog_pos;
|
||||
|
||||
if (!priv_data->catalog_file->sect_nb) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_INFORMATION,
|
||||
PED_EXCEPTION_OK,
|
||||
_("This HFS volume has no catalog file. "
|
||||
"This is very unusual!"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!hfs_file_read_sector (priv_data->catalog_file, node, 0))
|
||||
return 0;
|
||||
uint16_t offset;
|
||||
memcpy(&offset, node+(PED_SECTOR_SIZE_DEFAULT-2), sizeof(uint16_t));
|
||||
header = (HfsHeaderRecord*) (node + PED_BE16_TO_CPU(offset));
|
||||
|
||||
for (leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
|
||||
leaf_node;
|
||||
leaf_node = PED_BE32_TO_CPU (desc->next)) {
|
||||
if (!hfs_file_read_sector (priv_data->catalog_file,
|
||||
node, leaf_node))
|
||||
return 0;
|
||||
record_number = PED_BE16_TO_CPU (desc->rec_nb);
|
||||
for (i = 1; i <= record_number; ++i) {
|
||||
/* undocumented alignement */
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(PED_SECTOR_SIZE_DEFAULT - (2*i)), sizeof(uint16_t));
|
||||
catalog_pos = PED_BE16_TO_CPU(value);
|
||||
catalog_key = (HfsCatalogKey*) (node + catalog_pos);
|
||||
unsigned int skip;
|
||||
skip = (1 + catalog_key->key_length + 1) & ~1;
|
||||
catalog_data = (HfsCatalog*)(node+catalog_pos+skip);
|
||||
/* check for obvious error in FS */
|
||||
if ((catalog_pos < HFS_FIRST_REC)
|
||||
|| ((uint8_t*)catalog_data - node
|
||||
>= PED_SECTOR_SIZE_DEFAULT
|
||||
- 2 * (signed)(record_number+1))) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("The file system contains errors."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (catalog_data->type != HFS_CAT_FILE) continue;
|
||||
|
||||
extent = catalog_data->sel.file.extents_data;
|
||||
for (j = 0; j < HFS_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE16_TO_CPU(extent[j].start_block),
|
||||
PED_BE16_TO_CPU(extent[j].block_count),
|
||||
leaf_node,
|
||||
(uint8_t*)extent - node,
|
||||
1, /* hfs => btree block = 512 b */
|
||||
CR_BTREE_CAT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = catalog_data->sel.file.extents_res;
|
||||
for (j = 0; j < HFS_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE16_TO_CPU(extent[j].start_block),
|
||||
PED_BE16_TO_CPU(extent[j].block_count),
|
||||
leaf_node,
|
||||
(uint8_t*)extent - node,
|
||||
1, /* hfs => btree block = 512 b */
|
||||
CR_BTREE_CAT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfs_cache_from_extent(HfsCPrivateCache* cache, PedFileSystem* fs,
|
||||
PedTimer* timer)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
|
||||
HfsHeaderRecord* header;
|
||||
HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
|
||||
HfsExtentKey* extent_key;
|
||||
HfsExtDescriptor* extent;
|
||||
unsigned int leaf_node, record_number;
|
||||
unsigned int i, j;
|
||||
uint16_t extent_pos;
|
||||
|
||||
if (!priv_data->extent_file->sect_nb) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_INFORMATION,
|
||||
PED_EXCEPTION_OK,
|
||||
_("This HFS volume has no extents overflow "
|
||||
"file. This is quite unusual!"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!hfs_file_read_sector (priv_data->extent_file, node, 0))
|
||||
return 0;
|
||||
uint16_t offset;
|
||||
memcpy(&offset, node+(PED_SECTOR_SIZE_DEFAULT-2), sizeof(uint16_t));
|
||||
header = (HfsHeaderRecord*) (node + PED_BE16_TO_CPU(offset));
|
||||
|
||||
for (leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
|
||||
leaf_node;
|
||||
leaf_node = PED_BE32_TO_CPU (desc->next)) {
|
||||
if (!hfs_file_read_sector (priv_data->extent_file, node,
|
||||
leaf_node))
|
||||
return 0;
|
||||
record_number = PED_BE16_TO_CPU (desc->rec_nb);
|
||||
for (i = 1; i <= record_number; i++) {
|
||||
uint8_t where;
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(PED_SECTOR_SIZE_DEFAULT - (2*i)), sizeof(uint16_t));
|
||||
extent_pos = PED_BE16_TO_CPU(value);
|
||||
extent_key = (HfsExtentKey*)(node + extent_pos);
|
||||
/* size is cst */
|
||||
extent = (HfsExtDescriptor*)(node+extent_pos+sizeof(HfsExtentKey));
|
||||
/* check for obvious error in FS */
|
||||
if ((extent_pos < HFS_FIRST_REC)
|
||||
|| ((uint8_t*)extent - node
|
||||
>= PED_SECTOR_SIZE_DEFAULT
|
||||
- 2 * (signed)(record_number+1))) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("The file system contains errors."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (extent_key->file_ID) {
|
||||
case PED_CPU_TO_BE32 (HFS_XTENT_ID) :
|
||||
if (ped_exception_throw (
|
||||
PED_EXCEPTION_WARNING,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("The extents overflow file should not"
|
||||
" contain its own extents! You "
|
||||
"should check the file system."))
|
||||
!= PED_EXCEPTION_IGNORE)
|
||||
return 0;
|
||||
where = CR_BTREE_EXT_EXT;
|
||||
break;
|
||||
case PED_CPU_TO_BE32 (HFS_CATALOG_ID) :
|
||||
where = CR_BTREE_EXT_CAT;
|
||||
break;
|
||||
default :
|
||||
where = CR_BTREE_EXT_0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (j = 0; j < HFS_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE16_TO_CPU(extent[j].start_block),
|
||||
PED_BE16_TO_CPU(extent[j].block_count),
|
||||
leaf_node,
|
||||
(uint8_t*)extent - node,
|
||||
1, /* hfs => btree block = 512 b */
|
||||
where,
|
||||
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*
|
||||
hfs_cache_extents(PedFileSystem *fs, PedTimer* timer)
|
||||
{
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsCPrivateCache* ret;
|
||||
unsigned int file_number, block_number;
|
||||
|
||||
file_number = PED_BE32_TO_CPU(priv_data->mdb->file_count);
|
||||
block_number = PED_BE16_TO_CPU(priv_data->mdb->total_blocks);
|
||||
ret = hfsc_new_cache(block_number, file_number);
|
||||
if (!ret) return NULL;
|
||||
|
||||
if (!hfs_cache_from_mdb(ret, fs, timer) ||
|
||||
!hfs_cache_from_catalog(ret, fs, timer) ||
|
||||
!hfs_cache_from_extent(ret, fs, timer)) {
|
||||
ped_exception_throw(
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Could not cache the file system in memory."));
|
||||
hfsc_delete_cache(ret);
|
||||
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
|
||||
hfs_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
|
||||
PedTimer* timer, unsigned int to_free)
|
||||
{
|
||||
PedSector bytes_buff;
|
||||
HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsMasterDirectoryBlock* mdb = priv_data->mdb;
|
||||
HfsCPrivateCache* cache;
|
||||
unsigned int to_fblock = fblock;
|
||||
unsigned int start = fblock;
|
||||
unsigned int divisor = PED_BE16_TO_CPU (mdb->total_blocks)
|
||||
+ 1 - start - to_free;
|
||||
int ret;
|
||||
|
||||
PED_ASSERT (!hfs_block);
|
||||
|
||||
cache = hfs_cache_extents (fs, timer);
|
||||
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 */
|
||||
bytes_buff = PED_BE32_TO_CPU (priv_data->mdb->block_size)
|
||||
* (PedSector) BLOCK_MAX_BUFF;
|
||||
if (bytes_buff > BYTES_MAX_BUFF) {
|
||||
hfs_block_count = BYTES_MAX_BUFF
|
||||
/ PED_BE32_TO_CPU (priv_data->mdb->block_size);
|
||||
if (!hfs_block_count)
|
||||
hfs_block_count = 1;
|
||||
bytes_buff = (PedSector) hfs_block_count
|
||||
* PED_BE32_TO_CPU (priv_data->mdb->block_size);
|
||||
} else
|
||||
hfs_block_count = BLOCK_MAX_BUFF;
|
||||
|
||||
/* If the cache code requests more space, give it to him */
|
||||
if (bytes_buff < hfsc_cache_needed_buffer (cache))
|
||||
bytes_buff = hfsc_cache_needed_buffer (cache);
|
||||
|
||||
hfs_block = (uint8_t*) ped_malloc (bytes_buff);
|
||||
if (!hfs_block)
|
||||
goto error_cache;
|
||||
|
||||
if (!hfs_read_bad_blocks (fs)) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Bad blocks list could not be loaded."));
|
||||
goto error_alloc;
|
||||
}
|
||||
|
||||
while (fblock < PED_BE16_TO_CPU (mdb->total_blocks)) {
|
||||
if (TST_BLOC_OCCUPATION(priv_data->alloc_map,fblock)
|
||||
&& (!hfs_is_bad_block (fs, fblock))) {
|
||||
if (!(ret = hfs_move_extent_starting_at (fs, &fblock,
|
||||
&to_fblock, cache)))
|
||||
to_fblock = ++fblock;
|
||||
else if (ret == -1) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("An error occurred during extent "
|
||||
"relocation."));
|
||||
goto error_alloc;
|
||||
}
|
||||
} else {
|
||||
fblock++;
|
||||
}
|
||||
|
||||
ped_timer_update(timer, (float)(to_fblock - start)/divisor);
|
||||
}
|
||||
|
||||
free (hfs_block); hfs_block = NULL; hfs_block_count = 0;
|
||||
hfsc_delete_cache (cache);
|
||||
return 1;
|
||||
|
||||
error_alloc:
|
||||
free (hfs_block); hfs_block = NULL; hfs_block_count = 0;
|
||||
error_cache:
|
||||
hfsc_delete_cache (cache);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 _RELOC_H
|
||||
#define _RELOC_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfs_update_mdb (PedFileSystem *fs);
|
||||
|
||||
int
|
||||
hfs_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
|
||||
PedTimer* timer, unsigned int to_free);
|
||||
|
||||
#endif /* _RELOC_H */
|
||||
@@ -1,948 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(String) dgettext (PACKAGE, String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
#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
|
||||
hfsplus_effect_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock,
|
||||
unsigned int *ptr_to_fblock, unsigned int size)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
unsigned int i, ok = 0;
|
||||
unsigned int next_to_fblock;
|
||||
unsigned int start, stop;
|
||||
|
||||
PED_ASSERT (hfsp_block != NULL);
|
||||
PED_ASSERT (*ptr_to_fblock <= *ptr_fblock);
|
||||
/* quiet GCC */
|
||||
start = stop = 0;
|
||||
|
||||
/*
|
||||
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 = stop = *ptr_fblock < *ptr_to_fblock+size ?
|
||||
*ptr_fblock : *ptr_to_fblock+size;
|
||||
while (start && stop-start != size) {
|
||||
--start;
|
||||
if (TST_BLOC_OCCUPATION(priv_data->alloc_map,start))
|
||||
stop = start;
|
||||
}
|
||||
ok = (stop-start == size);
|
||||
}
|
||||
|
||||
/* Forward search */
|
||||
/* 1 pass relocation in the gap merged with 2 pass reloc after source */
|
||||
if (!ok && *ptr_to_fblock != *ptr_fblock) {
|
||||
start = stop = *ptr_to_fblock+1;
|
||||
while (stop < PED_BE32_TO_CPU(priv_data->vh->total_blocks)
|
||||
&& stop-start != size) {
|
||||
if (TST_BLOC_OCCUPATION(priv_data->alloc_map,stop))
|
||||
start = stop + 1;
|
||||
++stop;
|
||||
}
|
||||
ok = (stop-start == size);
|
||||
}
|
||||
|
||||
/* new non overlapping room has been found ? */
|
||||
if (ok) {
|
||||
/* enough room */
|
||||
PedSector abs_sector;
|
||||
unsigned int ai, j, block;
|
||||
unsigned int block_sz = (PED_BE32_TO_CPU (
|
||||
priv_data->vh->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT);
|
||||
|
||||
if (stop > *ptr_to_fblock && stop <= *ptr_fblock)
|
||||
/* Fit in the gap */
|
||||
next_to_fblock = stop;
|
||||
else
|
||||
/* Before or after the gap */
|
||||
next_to_fblock = *ptr_to_fblock;
|
||||
|
||||
/* move blocks */
|
||||
for (i = 0; i < size; /*i++*/) {
|
||||
j = size - i; j = (j < hfsp_block_count) ?
|
||||
j : hfsp_block_count ;
|
||||
|
||||
abs_sector = (PedSector) (*ptr_fblock + i) * block_sz;
|
||||
if (!ped_geometry_read (priv_data->plus_geom,
|
||||
hfsp_block, abs_sector,
|
||||
block_sz * j))
|
||||
return -1;
|
||||
|
||||
abs_sector = (PedSector) (start + i) * block_sz;
|
||||
if (!ped_geometry_write (priv_data->plus_geom,
|
||||
hfsp_block, abs_sector,
|
||||
block_sz * j))
|
||||
return -1;
|
||||
|
||||
for (ai = i+j; i < ai; i++) {
|
||||
/* free source block */
|
||||
block = *ptr_fblock + i;
|
||||
CLR_BLOC_OCCUPATION(priv_data->alloc_map,block);
|
||||
SET_BLOC_OCCUPATION(priv_data->dirty_alloc_map,
|
||||
block/(PED_SECTOR_SIZE_DEFAULT*8));
|
||||
|
||||
/* set dest block */
|
||||
block = start + i;
|
||||
SET_BLOC_OCCUPATION(priv_data->alloc_map,block);
|
||||
SET_BLOC_OCCUPATION(priv_data->dirty_alloc_map,
|
||||
block/(PED_SECTOR_SIZE_DEFAULT*8));
|
||||
}
|
||||
}
|
||||
if (!ped_geometry_sync_fast (priv_data->plus_geom))
|
||||
return -1;
|
||||
|
||||
*ptr_fblock += size;
|
||||
*ptr_to_fblock = next_to_fblock;
|
||||
} else {
|
||||
if (*ptr_fblock != *ptr_to_fblock)
|
||||
/* not enough room */
|
||||
ped_exception_throw (PED_EXCEPTION_WARNING,
|
||||
PED_EXCEPTION_IGNORE,
|
||||
_("An extent has not been relocated."));
|
||||
start = *ptr_fblock;
|
||||
*ptr_fblock = *ptr_to_fblock = start + size;
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
/* Returns 0 on error */
|
||||
/* 1 on succes */
|
||||
int
|
||||
hfsplus_update_vh (PedFileSystem *fs)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
uint8_t node[PED_SECTOR_SIZE_DEFAULT];
|
||||
|
||||
if (!ped_geometry_read (priv_data->plus_geom, node, 2, 1))
|
||||
return 0;
|
||||
memcpy (node, priv_data->vh, sizeof (HfsPVolumeHeader));
|
||||
if (!ped_geometry_write (priv_data->plus_geom, node, 2, 1)
|
||||
|| !ped_geometry_write (priv_data->plus_geom, node,
|
||||
priv_data->plus_geom->length - 2, 1)
|
||||
|| !ped_geometry_sync_fast (priv_data->plus_geom))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfsplus_do_move (PedFileSystem* fs, unsigned int *ptr_src,
|
||||
unsigned int *ptr_dest, HfsCPrivateCache* cache,
|
||||
HfsCPrivateExtent* ref)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPPrivateFile* file;
|
||||
HfsPExtDescriptor* extent;
|
||||
HfsCPrivateExtent* move;
|
||||
int new_start;
|
||||
|
||||
new_start = hfsplus_effect_move_extent (fs, ptr_src, ptr_dest,
|
||||
ref->ext_length);
|
||||
|
||||
if (new_start == -1) return -1;
|
||||
|
||||
if (ref->ext_start != (unsigned) new_start) {
|
||||
switch (ref->where) {
|
||||
/************ VH ************/
|
||||
case CR_PRIM_CAT :
|
||||
priv_data->catalog_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_PRIM;
|
||||
case CR_PRIM_EXT :
|
||||
priv_data->extents_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_PRIM;
|
||||
case CR_PRIM_ATTR :
|
||||
priv_data->attributes_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_PRIM;
|
||||
case CR_PRIM_ALLOC :
|
||||
priv_data->allocation_file
|
||||
->first[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_PRIM;
|
||||
case CR_PRIM_START :
|
||||
/* No startup file opened */
|
||||
CR_PRIM :
|
||||
extent = ( HfsPExtDescriptor* )
|
||||
( (uint8_t*)priv_data->vh + ref->ref_offset );
|
||||
extent[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
if (!hfsplus_update_vh(fs))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
/************** BTREE *************/
|
||||
case CR_BTREE_CAT_JIB :
|
||||
if (!hfsj_update_jib(fs, new_start))
|
||||
return -1;
|
||||
goto BTREE_CAT;
|
||||
|
||||
case CR_BTREE_CAT_JL :
|
||||
if (!hfsj_update_jl(fs, new_start))
|
||||
return -1;
|
||||
goto BTREE_CAT;
|
||||
|
||||
BTREE_CAT:
|
||||
case CR_BTREE_CAT :
|
||||
file = priv_data->catalog_file;
|
||||
goto CR_BTREE;
|
||||
|
||||
case CR_BTREE_ATTR :
|
||||
file = priv_data->attributes_file;
|
||||
goto CR_BTREE;
|
||||
|
||||
case CR_BTREE_EXT_ATTR :
|
||||
if (priv_data->attributes_file
|
||||
->cache[ref->ref_index].start_block
|
||||
== PED_CPU_TO_BE32(ref->ext_start))
|
||||
priv_data->attributes_file
|
||||
->cache[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_BTREE_EXT;
|
||||
case CR_BTREE_EXT_CAT :
|
||||
if (priv_data->catalog_file
|
||||
->cache[ref->ref_index].start_block
|
||||
== PED_CPU_TO_BE32(ref->ext_start))
|
||||
priv_data->catalog_file
|
||||
->cache[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_BTREE_EXT;
|
||||
case CR_BTREE_EXT_ALLOC :
|
||||
if (priv_data->allocation_file
|
||||
->cache[ref->ref_index].start_block
|
||||
== PED_CPU_TO_BE32(ref->ext_start))
|
||||
priv_data->allocation_file
|
||||
->cache[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
goto CR_BTREE_EXT;
|
||||
case CR_BTREE_EXT_START :
|
||||
/* No startup file opened */
|
||||
CR_BTREE_EXT :
|
||||
case CR_BTREE_EXT_0 :
|
||||
file = priv_data->extents_file;
|
||||
|
||||
CR_BTREE :
|
||||
PED_ASSERT(PED_SECTOR_SIZE_DEFAULT * ref->sect_by_block
|
||||
> ref->ref_offset);
|
||||
if (!hfsplus_file_read(file, hfsp_block,
|
||||
(PedSector)ref->ref_block * ref->sect_by_block,
|
||||
ref->sect_by_block))
|
||||
return -1;
|
||||
extent = ( HfsPExtDescriptor* )
|
||||
( hfsp_block + ref->ref_offset );
|
||||
extent[ref->ref_index].start_block =
|
||||
PED_CPU_TO_BE32(new_start);
|
||||
if (!hfsplus_file_write(file, hfsp_block,
|
||||
(PedSector)ref->ref_block * ref->sect_by_block,
|
||||
ref->sect_by_block)
|
||||
|| !ped_geometry_sync_fast (priv_data->plus_geom))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
/********** BUG *********/
|
||||
default :
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("A reference to an extent comes from a place "
|
||||
"it should not. You should check the file "
|
||||
"system!"));
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
move = hfsc_cache_move_extent(cache, ref->ext_start, new_start);
|
||||
if (!move) return -1;
|
||||
PED_ASSERT(move == ref);
|
||||
}
|
||||
|
||||
return new_start;
|
||||
}
|
||||
|
||||
/* save any dirty sector of the allocation bitmap file */
|
||||
static int
|
||||
hfsplus_save_allocation(PedFileSystem *fs)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
unsigned int map_sectors, i, j;
|
||||
int ret = 1;
|
||||
|
||||
map_sectors = ( PED_BE32_TO_CPU (priv_data->vh->total_blocks)
|
||||
+ PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8);
|
||||
|
||||
for (i = 0; i < map_sectors;) {
|
||||
for (j = i;
|
||||
(TST_BLOC_OCCUPATION(priv_data->dirty_alloc_map,j));
|
||||
++j)
|
||||
CLR_BLOC_OCCUPATION(priv_data->dirty_alloc_map,j);
|
||||
if (j-i) {
|
||||
ret = hfsplus_file_write(priv_data->allocation_file,
|
||||
priv_data->alloc_map + i * PED_SECTOR_SIZE_DEFAULT,
|
||||
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
|
||||
hfsplus_move_extent_starting_at (PedFileSystem *fs, unsigned int *ptr_fblock,
|
||||
unsigned int *ptr_to_fblock,
|
||||
HfsCPrivateCache* cache)
|
||||
{
|
||||
HfsCPrivateExtent* ref;
|
||||
unsigned int old_start, new_start;
|
||||
|
||||
ref = hfsc_cache_search_extent(cache, *ptr_fblock);
|
||||
if (!ref) return 0;
|
||||
|
||||
old_start = *ptr_fblock;
|
||||
new_start = hfsplus_do_move(fs, ptr_fblock, ptr_to_fblock, cache, ref);
|
||||
if (new_start == (unsigned)-1) return -1;
|
||||
if (new_start > old_start) {
|
||||
new_start = hfsplus_do_move(fs, &new_start, ptr_to_fblock,
|
||||
cache, ref);
|
||||
if (new_start == (unsigned)-1 || new_start > old_start)
|
||||
return -1;
|
||||
}
|
||||
|
||||
hfsplus_save_allocation(fs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfsplus_cache_from_vh(HfsCPrivateCache* cache, PedFileSystem* fs,
|
||||
PedTimer* timer)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPExtDescriptor* extent;
|
||||
unsigned int j;
|
||||
|
||||
extent = priv_data->vh->allocation_file.extents;
|
||||
for (j = 0; j < HFSP_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE32_TO_CPU(extent[j].start_block),
|
||||
PED_BE32_TO_CPU(extent[j].block_count),
|
||||
0, /* unused for vh */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
|
||||
1, /* load / save 1 sector */
|
||||
CR_PRIM_ALLOC,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = priv_data->vh->extents_file.extents;
|
||||
for (j = 0; j < HFSP_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE32_TO_CPU(extent[j].start_block),
|
||||
PED_BE32_TO_CPU(extent[j].block_count),
|
||||
0, /* unused for vh */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
|
||||
1, /* load / save 1 sector */
|
||||
CR_PRIM_EXT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = priv_data->vh->catalog_file.extents;
|
||||
for (j = 0; j < HFSP_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE32_TO_CPU(extent[j].start_block),
|
||||
PED_BE32_TO_CPU(extent[j].block_count),
|
||||
0, /* unused for vh */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
|
||||
1, /* load / save 1 sector */
|
||||
CR_PRIM_CAT,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = priv_data->vh->attributes_file.extents;
|
||||
for (j = 0; j < HFSP_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE32_TO_CPU(extent[j].start_block),
|
||||
PED_BE32_TO_CPU(extent[j].block_count),
|
||||
0, /* unused for vh */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
|
||||
1, /* load / save 1 sector */
|
||||
CR_PRIM_ATTR,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extent = priv_data->vh->startup_file.extents;
|
||||
for (j = 0; j < HFSP_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE32_TO_CPU(extent[j].start_block),
|
||||
PED_BE32_TO_CPU(extent[j].block_count),
|
||||
0, /* unused for vh */
|
||||
((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
|
||||
1, /* load / save 1 sector */
|
||||
CR_PRIM_START,
|
||||
j )
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfsplus_cache_from_catalog(HfsCPrivateCache* cache, PedFileSystem* fs,
|
||||
PedTimer* timer)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
uint8_t node_1[PED_SECTOR_SIZE_DEFAULT];
|
||||
uint8_t* node;
|
||||
HfsPHeaderRecord* header;
|
||||
HfsPCatalogKey* catalog_key;
|
||||
HfsPCatalog* catalog_data;
|
||||
HfsPExtDescriptor* extent;
|
||||
unsigned int leaf_node, record_number;
|
||||
unsigned int i, j, size, bsize;
|
||||
uint32_t jib = priv_data->jib_start_block,
|
||||
jl = priv_data->jl_start_block;
|
||||
uint16_t catalog_pos;
|
||||
|
||||
if (!priv_data->catalog_file->sect_nb) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_INFORMATION,
|
||||
PED_EXCEPTION_OK,
|
||||
_("This HFS+ volume has no catalog file. "
|
||||
"This is very unusual!"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Search the extent starting at *ptr_block in the catalog file */
|
||||
if (!hfsplus_file_read_sector (priv_data->catalog_file, node_1, 0))
|
||||
return 0;
|
||||
header = (HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC);
|
||||
leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
|
||||
bsize = PED_BE16_TO_CPU (header->node_size);
|
||||
size = bsize / PED_SECTOR_SIZE_DEFAULT;
|
||||
PED_ASSERT(size < 256);
|
||||
|
||||
node = (uint8_t*) ped_malloc(bsize);
|
||||
if (!node) return 0;
|
||||
HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node;
|
||||
|
||||
for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) {
|
||||
if (!hfsplus_file_read (priv_data->catalog_file, node,
|
||||
(PedSector) leaf_node * size, size)) {
|
||||
free (node);
|
||||
return 0;
|
||||
}
|
||||
record_number = PED_BE16_TO_CPU (desc->rec_nb);
|
||||
for (i = 1; i <= record_number; i++) {
|
||||
unsigned int skip;
|
||||
uint8_t where;
|
||||
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
|
||||
catalog_pos = PED_BE16_TO_CPU(value);
|
||||
catalog_key = (HfsPCatalogKey*)(node + catalog_pos);
|
||||
skip = ( 2 + PED_BE16_TO_CPU (catalog_key->key_length)
|
||||
+ 1) & ~1;
|
||||
catalog_data = (HfsPCatalog*)
|
||||
(((uint8_t*)catalog_key) + skip);
|
||||
/* check for obvious error in FS */
|
||||
if ((catalog_pos < HFS_FIRST_REC)
|
||||
|| ((uint8_t*)catalog_data - node
|
||||
>= (signed) bsize
|
||||
- 2 * (signed)(record_number+1))) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("The file system contains errors."));
|
||||
free (node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (PED_BE16_TO_CPU(catalog_data->type)!=HFS_CAT_FILE)
|
||||
continue;
|
||||
|
||||
extent = catalog_data->sel.file.data_fork.extents;
|
||||
for (j = 0; j < HFSP_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
where = CR_BTREE_CAT;
|
||||
if ( PED_BE32_TO_CPU(extent[j].start_block)
|
||||
== jib ) {
|
||||
jib = 0;
|
||||
where = CR_BTREE_CAT_JIB;
|
||||
} else
|
||||
if ( PED_BE32_TO_CPU(extent[j].start_block)
|
||||
== jl ) {
|
||||
jl = 0;
|
||||
where = CR_BTREE_CAT_JL;
|
||||
}
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE32_TO_CPU(extent[j].start_block),
|
||||
PED_BE32_TO_CPU(extent[j].block_count),
|
||||
leaf_node,
|
||||
(uint8_t*)extent - node,
|
||||
size,
|
||||
where,
|
||||
j )
|
||||
) {
|
||||
free (node);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extent = catalog_data->sel.file.res_fork.extents;
|
||||
for (j = 0; j < HFSP_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE32_TO_CPU(extent[j].start_block),
|
||||
PED_BE32_TO_CPU(extent[j].block_count),
|
||||
leaf_node,
|
||||
(uint8_t*)extent - node,
|
||||
size,
|
||||
CR_BTREE_CAT,
|
||||
j )
|
||||
) {
|
||||
free (node);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free (node);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfsplus_cache_from_extent(HfsCPrivateCache* cache, PedFileSystem* fs,
|
||||
PedTimer* timer)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
uint8_t node_1[PED_SECTOR_SIZE_DEFAULT];
|
||||
uint8_t* node;
|
||||
HfsPHeaderRecord* header;
|
||||
HfsPExtentKey* extent_key;
|
||||
HfsPExtDescriptor* extent;
|
||||
unsigned int leaf_node, record_number;
|
||||
unsigned int i, j, size, bsize;
|
||||
uint16_t extent_pos;
|
||||
|
||||
if (!priv_data->extents_file->sect_nb) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_INFORMATION,
|
||||
PED_EXCEPTION_OK,
|
||||
_("This HFS+ volume has no extents overflow "
|
||||
"file. This is quite unusual!"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!hfsplus_file_read_sector (priv_data->extents_file, node_1, 0))
|
||||
return 0;
|
||||
header = ((HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC));
|
||||
leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
|
||||
bsize = PED_BE16_TO_CPU (header->node_size);
|
||||
size = bsize / PED_SECTOR_SIZE_DEFAULT;
|
||||
PED_ASSERT(size < 256);
|
||||
|
||||
node = (uint8_t*) ped_malloc (bsize);
|
||||
if (!node) return -1;
|
||||
HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node;
|
||||
|
||||
for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) {
|
||||
if (!hfsplus_file_read (priv_data->extents_file, node,
|
||||
(PedSector) leaf_node * size, size)) {
|
||||
free (node);
|
||||
return 0;
|
||||
}
|
||||
record_number = PED_BE16_TO_CPU (desc->rec_nb);
|
||||
for (i = 1; i <= record_number; i++) {
|
||||
uint8_t where;
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
|
||||
extent_pos = PED_BE16_TO_CPU(value);
|
||||
extent_key = (HfsPExtentKey*)(node + extent_pos);
|
||||
extent = (HfsPExtDescriptor*)
|
||||
(((uint8_t*)extent_key) + sizeof (HfsPExtentKey));
|
||||
/* check for obvious error in FS */
|
||||
if ((extent_pos < HFS_FIRST_REC)
|
||||
|| ((uint8_t*)extent - node
|
||||
>= (signed)bsize
|
||||
- 2 * (signed)(record_number+1))) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("The file system contains errors."));
|
||||
free (node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (extent_key->file_ID) {
|
||||
case PED_CPU_TO_BE32 (HFS_XTENT_ID) :
|
||||
if (ped_exception_throw (
|
||||
PED_EXCEPTION_WARNING,
|
||||
PED_EXCEPTION_IGNORE_CANCEL,
|
||||
_("The extents overflow file should not"
|
||||
" contain its own extents! You should "
|
||||
"check the file system."))
|
||||
!= PED_EXCEPTION_IGNORE)
|
||||
return 0;
|
||||
where = CR_BTREE_EXT_EXT;
|
||||
break;
|
||||
case PED_CPU_TO_BE32 (HFS_CATALOG_ID) :
|
||||
where = CR_BTREE_EXT_CAT;
|
||||
break;
|
||||
case PED_CPU_TO_BE32 (HFSP_ALLOC_ID) :
|
||||
where = CR_BTREE_EXT_ALLOC;
|
||||
break;
|
||||
case PED_CPU_TO_BE32 (HFSP_STARTUP_ID) :
|
||||
where = CR_BTREE_EXT_START;
|
||||
break;
|
||||
case PED_CPU_TO_BE32 (HFSP_ATTRIB_ID) :
|
||||
where = CR_BTREE_EXT_ATTR;
|
||||
break;
|
||||
default :
|
||||
where = CR_BTREE_EXT_0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (j = 0; j < HFSP_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE32_TO_CPU(extent[j].start_block),
|
||||
PED_BE32_TO_CPU(extent[j].block_count),
|
||||
leaf_node,
|
||||
(uint8_t*)extent - node,
|
||||
size,
|
||||
where,
|
||||
j )
|
||||
) {
|
||||
free (node);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free (node);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
hfsplus_cache_from_attributes(HfsCPrivateCache* cache, PedFileSystem* fs,
|
||||
PedTimer* timer)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
uint8_t node_1[PED_SECTOR_SIZE_DEFAULT];
|
||||
uint8_t* node;
|
||||
HfsPHeaderRecord* header;
|
||||
HfsPPrivateGenericKey* generic_key;
|
||||
HfsPForkDataAttr* fork_ext_data;
|
||||
HfsPExtDescriptor* extent;
|
||||
unsigned int leaf_node, record_number;
|
||||
unsigned int i, j, size, bsize;
|
||||
uint16_t generic_pos;
|
||||
|
||||
/* attributes file is facultative */
|
||||
if (!priv_data->attributes_file->sect_nb)
|
||||
return 1;
|
||||
|
||||
/* Search the extent starting at *ptr_block in the catalog file */
|
||||
if (!hfsplus_file_read_sector (priv_data->attributes_file, node_1, 0))
|
||||
return 0;
|
||||
header = ((HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC));
|
||||
leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
|
||||
bsize = PED_BE16_TO_CPU (header->node_size);
|
||||
size = bsize / PED_SECTOR_SIZE_DEFAULT;
|
||||
PED_ASSERT(size < 256);
|
||||
|
||||
node = (uint8_t*) ped_malloc(bsize);
|
||||
if (!node) return 0;
|
||||
HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node;
|
||||
|
||||
for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) {
|
||||
if (!hfsplus_file_read (priv_data->attributes_file, node,
|
||||
(PedSector) leaf_node * size, size)) {
|
||||
free (node);
|
||||
return 0;
|
||||
}
|
||||
record_number = PED_BE16_TO_CPU (desc->rec_nb);
|
||||
for (i = 1; i <= record_number; i++) {
|
||||
unsigned int skip;
|
||||
uint16_t value;
|
||||
memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
|
||||
generic_pos = PED_BE16_TO_CPU(value);
|
||||
generic_key = (HfsPPrivateGenericKey*)(node + generic_pos);
|
||||
skip = ( 2 + PED_BE16_TO_CPU (generic_key->key_length)
|
||||
+ 1 ) & ~1;
|
||||
fork_ext_data = (HfsPForkDataAttr*)(node+generic_pos+skip);
|
||||
/* check for obvious error in FS */
|
||||
if ((generic_pos < HFS_FIRST_REC)
|
||||
|| ((uint8_t*)fork_ext_data - node
|
||||
>= (signed) bsize
|
||||
- 2 * (signed)(record_number+1))) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("The file system contains errors."));
|
||||
free (node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fork_ext_data->record_type
|
||||
== PED_CPU_TO_BE32 ( HFSP_ATTR_FORK ) ) {
|
||||
extent = fork_ext_data->fork_res.fork.extents;
|
||||
for (j = 0; j < HFSP_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE32_TO_CPU (
|
||||
extent[j].start_block ),
|
||||
PED_BE32_TO_CPU (
|
||||
extent[j].block_count ),
|
||||
leaf_node,
|
||||
(uint8_t*)extent-node,
|
||||
size,
|
||||
CR_BTREE_ATTR,
|
||||
j )
|
||||
) {
|
||||
free(node);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else if (fork_ext_data->record_type
|
||||
== PED_CPU_TO_BE32 ( HFSP_ATTR_EXTENTS ) ) {
|
||||
extent = fork_ext_data->fork_res.extents;
|
||||
for (j = 0; j < HFSP_EXT_NB; ++j) {
|
||||
if (!extent[j].block_count) break;
|
||||
if (!hfsc_cache_add_extent(
|
||||
cache,
|
||||
PED_BE32_TO_CPU (
|
||||
extent[j].start_block ),
|
||||
PED_BE32_TO_CPU (
|
||||
extent[j].block_count ),
|
||||
leaf_node,
|
||||
(uint8_t*)extent-node,
|
||||
size,
|
||||
CR_BTREE_ATTR,
|
||||
j )
|
||||
) {
|
||||
free(node);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else continue;
|
||||
}
|
||||
}
|
||||
|
||||
free (node);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static HfsCPrivateCache*
|
||||
hfsplus_cache_extents(PedFileSystem* fs, PedTimer* timer)
|
||||
{
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsCPrivateCache* ret;
|
||||
unsigned int file_number, block_number;
|
||||
|
||||
file_number = PED_BE32_TO_CPU(priv_data->vh->file_count);
|
||||
block_number = PED_BE32_TO_CPU(priv_data->vh->total_blocks);
|
||||
ret = hfsc_new_cache(block_number, file_number);
|
||||
if (!ret) return NULL;
|
||||
|
||||
if (!hfsplus_cache_from_vh(ret, fs, timer) ||
|
||||
!hfsplus_cache_from_catalog(ret, fs, timer) ||
|
||||
!hfsplus_cache_from_extent(ret, fs, timer) ||
|
||||
!hfsplus_cache_from_attributes(ret, fs, timer)) {
|
||||
ped_exception_throw(
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Could not cache the file system in memory."));
|
||||
hfsc_delete_cache(ret);
|
||||
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
|
||||
hfsplus_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
|
||||
PedTimer* timer, unsigned int to_free)
|
||||
{
|
||||
PedSector bytes_buff;
|
||||
HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
|
||||
fs->type_specific;
|
||||
HfsPVolumeHeader* vh = priv_data->vh;
|
||||
HfsCPrivateCache* cache;
|
||||
unsigned int to_fblock = fblock;
|
||||
unsigned int start = fblock;
|
||||
unsigned int divisor = PED_BE32_TO_CPU (vh->total_blocks)
|
||||
+ 1 - start - to_free;
|
||||
int ret;
|
||||
|
||||
PED_ASSERT (!hfsp_block);
|
||||
|
||||
cache = hfsplus_cache_extents (fs, timer);
|
||||
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 */
|
||||
bytes_buff = PED_BE32_TO_CPU (priv_data->vh->block_size)
|
||||
* (PedSector) BLOCK_MAX_BUFF;
|
||||
if (bytes_buff > BYTES_MAX_BUFF) {
|
||||
hfsp_block_count = BYTES_MAX_BUFF
|
||||
/ PED_BE32_TO_CPU (priv_data->vh->block_size);
|
||||
if (!hfsp_block_count)
|
||||
hfsp_block_count = 1;
|
||||
bytes_buff = (PedSector) hfsp_block_count
|
||||
* PED_BE32_TO_CPU (priv_data->vh->block_size);
|
||||
} else
|
||||
hfsp_block_count = BLOCK_MAX_BUFF;
|
||||
|
||||
/* If the cache code requests more space, give it to him */
|
||||
if (bytes_buff < hfsc_cache_needed_buffer (cache))
|
||||
bytes_buff = hfsc_cache_needed_buffer (cache);
|
||||
|
||||
hfsp_block = (uint8_t*) ped_malloc (bytes_buff);
|
||||
if (!hfsp_block)
|
||||
goto error_cache;
|
||||
|
||||
if (!hfsplus_read_bad_blocks (fs)) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("Bad blocks list could not be loaded."));
|
||||
goto error_alloc;
|
||||
}
|
||||
|
||||
while ( fblock < ( priv_data->plus_geom->length - 2 )
|
||||
/ ( PED_BE32_TO_CPU (vh->block_size)
|
||||
/ PED_SECTOR_SIZE_DEFAULT ) ) {
|
||||
if (TST_BLOC_OCCUPATION (priv_data->alloc_map, fblock)
|
||||
&& (!hfsplus_is_bad_block (fs, fblock))) {
|
||||
if (!(ret = hfsplus_move_extent_starting_at (fs,
|
||||
&fblock, &to_fblock, cache)))
|
||||
to_fblock = ++fblock;
|
||||
else if (ret == -1) {
|
||||
ped_exception_throw (
|
||||
PED_EXCEPTION_ERROR,
|
||||
PED_EXCEPTION_CANCEL,
|
||||
_("An error occurred during extent "
|
||||
"relocation."));
|
||||
goto error_alloc;
|
||||
}
|
||||
} else {
|
||||
fblock++;
|
||||
}
|
||||
|
||||
ped_timer_update(timer, (float)(to_fblock - start) / divisor);
|
||||
}
|
||||
|
||||
free (hfsp_block); hfsp_block = NULL; hfsp_block_count = 0;
|
||||
hfsc_delete_cache (cache);
|
||||
return 1;
|
||||
|
||||
error_alloc:
|
||||
free (hfsp_block); hfsp_block = NULL; hfsp_block_count = 0;
|
||||
error_cache:
|
||||
hfsc_delete_cache (cache);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !DISCOVER_ONLY */
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
libparted - a library for manipulating disk partitions
|
||||
Copyright (C) 2004, 2007, 2009-2014, 2019-2023 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
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 _RELOC_PLUS_H
|
||||
#define _RELOC_PLUS_H
|
||||
|
||||
#include <parted/parted.h>
|
||||
#include <parted/endian.h>
|
||||
#include <parted/debug.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
int
|
||||
hfsplus_update_vh (PedFileSystem *fs);
|
||||
|
||||
int
|
||||
hfsplus_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
|
||||
PedTimer* timer, unsigned int to_free);
|
||||
|
||||
|
||||
#endif /* _RELOC_PLUS_H */
|
||||
Reference in New Issue
Block a user