summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter van den Abeele <pvdabeel@gentoo.org>2003-05-29 16:37:23 +0000
committerPieter van den Abeele <pvdabeel@gentoo.org>2003-05-29 16:37:23 +0000
commit05d5efc9122940164319f46547ac29f1da522a4e (patch)
tree97bbb50d00c87d65ef51168db5d00ff0ec4d014f /sys-apps
parentadding Manifest (diff)
downloadgentoo-2-05d5efc9122940164319f46547ac29f1da522a4e.tar.gz
gentoo-2-05d5efc9122940164319f46547ac29f1da522a4e.tar.bz2
gentoo-2-05d5efc9122940164319f46547ac29f1da522a4e.zip
hfs resizing support
Diffstat (limited to 'sys-apps')
-rw-r--r--sys-apps/parted/ChangeLog8
-rw-r--r--sys-apps/parted/files/parted-1.6.5-hfs-8.patch3635
-rw-r--r--sys-apps/parted/parted-1.6.5-r1.ebuild47
3 files changed, 3689 insertions, 1 deletions
diff --git a/sys-apps/parted/ChangeLog b/sys-apps/parted/ChangeLog
index 35355a325c47..fc772c2de3f7 100644
--- a/sys-apps/parted/ChangeLog
+++ b/sys-apps/parted/ChangeLog
@@ -1,6 +1,12 @@
# ChangeLog for sys-apps/parted
# Copyright 2002-2003 Gentoo Technologies, Inc.; Distributed under the GPL v2
-# $Header: /var/cvsroot/gentoo-x86/sys-apps/parted/ChangeLog,v 1.14 2003/03/26 02:44:23 seemant Exp $
+# $Header: /var/cvsroot/gentoo-x86/sys-apps/parted/ChangeLog,v 1.15 2003/05/29 16:37:23 pvdabeel Exp $
+
+*parted-1.6.5-r1 (29 May 2003)
+
+ 29 May 2003; root <root@gentoo.org> parted-1.6.5-r1.ebuild,
+ files/parted-1.6.5-hfs-8.patch:
+ HFS resizing support. Emerged fine on my box.
*parted-1.6.3 (25 Mar 2003)
diff --git a/sys-apps/parted/files/parted-1.6.5-hfs-8.patch b/sys-apps/parted/files/parted-1.6.5-hfs-8.patch
new file mode 100644
index 000000000000..ffaea6de7261
--- /dev/null
+++ b/sys-apps/parted/files/parted-1.6.5-hfs-8.patch
@@ -0,0 +1,3635 @@
+diff -u -r -N parted-1.6.5/AUTHORS parted-1.6.5-hfs/AUTHORS
+--- parted-1.6.5/AUTHORS Wed Jun 26 04:29:49 2002
++++ parted-1.6.5-hfs/AUTHORS Tue Apr 29 05:46:52 2003
+@@ -137,3 +137,6 @@
+ Bernardo João Torres da Silveira <bernardojt@ig.com.br>
+ * pt_BR translation of FAQ and parted.texi
+
++Guillaume Knispel <k_guillaume@libertysurf.fr>
++ * nearly all hfs and hfs+ code (libparted/fs_hfs)
++ * hfs+ support for mac partitions (libparted/disk_mac.c)
+diff -u -r -N parted-1.6.5/libparted/disk_mac.c parted-1.6.5-hfs/libparted/disk_mac.c
+--- parted-1.6.5/libparted/disk_mac.c Mon Apr 8 12:08:03 2002
++++ parted-1.6.5-hfs/libparted/disk_mac.c Tue Apr 29 05:47:10 2003
+@@ -1068,7 +1068,8 @@
+ return 1;
+ }
+
+- if (fs_type && !strcmp (fs_type->name, "hfs")) {
++ if (fs_type && ( !strcmp (fs_type->name, "hfs")
++ || !strcmp (fs_type->name, "hfs+"))) {
+ strcpy (mac_data->system_name, "Apple_HFS");
+ mac_data->status |= 0x7f;
+ } else {
+@@ -1082,7 +1083,6 @@
+ static int
+ mac_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+ {
+- PedFileSystemType* hfs = ped_file_system_type_get ("hfs");
+ MacPartitionData* mac_data;
+
+ PED_ASSERT (part != NULL, return 0);
+diff -u -r -N parted-1.6.5/libparted/fs_hfs/hfs.c parted-1.6.5-hfs/libparted/fs_hfs/hfs.c
+--- parted-1.6.5/libparted/fs_hfs/hfs.c Mon Apr 8 12:10:25 2002
++++ parted-1.6.5-hfs/libparted/fs_hfs/hfs.c Tue Apr 29 05:48:04 2003
+@@ -1,6 +1,6 @@
+ /*
+ libparted - a library for manipulating disk partitions
+- Copyright (C) 2000 Free Software Foundation, Inc.
++ Copyright (C) 2000, 2003 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
+@@ -17,10 +17,52 @@
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
++/*
++ Technical doc about Apple HFS and HFS+ file systems is available at :
++ * For HFS, section "Data Organization on Volumes",
++ "Chapter 2 - File Manager"
++ of the book "Inside Macintosh: Files"
++ http://developer.apple.com/techpubs/mac/Files/Files-99.html#HEADING99-0
++ * For HFS+, "Technical Note TN1150", "HFS Plus Volume Format"
++ http://developer.apple.com/technotes/tn/tn1150.html
++
++ Some useful HFS precisions concerning alignement and bit ordering
++ are in the HFS+ TN
++*/
++
++/* HISTORY :
++## modifications dd-mm-yyyy
++---------------------- PATCH FOR PARTED 1.6.5 ----------------------------
++ 1 initial revision 07-04-2003
++ 2 one pass resizing, removal of debug info 08-04-2003
++ 3 safe abort if resize failed, code cleanups, timer, 10-04-2003
++ source file split, won't resize if not unmounted,
++ only relocate data if needed, minimize disk operations
++ 4 memory leaks removal, code cleanups, resize hfs+ code, 17-04-2003
++ more checks, minor hfs resize bugfix, probe code
++ returns real geometry
++ 5 hfs+ resize bugfixes : 19-04-2003
++ * fragmented fs could be corrupted
++ * VH wasn't written on error during alloc map writing
++ * attributes file could be corrupted
++ 6 Use PedSector to be able to use > 2 To HD 23-04-2003
++ Minor probe bugfix, Cleanups, HFS+ Timer tuning,
++ 7 80 columns indentation 23-04-2003
++ 8 Bugfix free blocks calculation in wrapper
++ (makes Mac OS boot !) 28-04-2003
++*/
++
++/* TODO : Think about a mean to do more allocation bitmap
++ saves when shrinking hfs+ */
++
+ #include "config.h"
+
++#include <stdlib.h>
++#include <string.h>
+ #include <parted/parted.h>
+ #include <parted/endian.h>
++#include <parted/debug.h>
++#include <stdint.h>
+
+ #if ENABLE_NLS
+ # include <libintl.h>
+@@ -31,32 +73,2902 @@
+
+ #include <string.h>
+
+-#define HFS_SIGNATURE 0x4244
++#include "hfs.h"
++
++
++
++/* -------------------- */
++/* -- CODE -- */
++/* -------------------- */
++
++/* 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 */
++static PedGeometry*
++hfs_and_wrapper_probe (PedGeometry* geom)
++{
++ uint8_t buf[PED_SECTOR_SIZE];
++ HfsMasterDirectoryBlock *mdb;
++ PedGeometry* geom_ret;
++ PedSector search, max;
++
++ mdb = (HfsMasterDirectoryBlock *) buf;
++
++ if ((geom->length < 5)
++ || (!ped_geometry_read (geom, buf, 2, 1))
++ || (PED_BE16_TO_CPU (mdb->signature) != 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 )));
++ max = search + ( PED_BE32_TO_CPU (mdb->block_size) / PED_SECTOR_SIZE );
++ 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 (PED_BE16_TO_CPU (mdb->signature) == HFS_SIGNATURE)
++ return geom_ret;
++ }
++
++ ped_geometry_destroy (geom_ret);
++ return NULL;
++}
++
++static PedGeometry*
++hfsplus_probe (PedGeometry* geom)
++{
++ PedGeometry* geom_ret;
++ uint8_t buf[PED_SECTOR_SIZE];
++
++ if ((geom_ret = hfs_and_wrapper_probe(geom))) {
++ /* HFS+ is embedded in an HFS volume ? */
++ HfsMasterDirectoryBlock *mdb;
++ mdb = (HfsMasterDirectoryBlock *) buf;
++
++ if (!ped_geometry_read (geom, buf, 2, 1)
++ || (PED_BE16_TO_CPU (mdb->old_new.embedded.signature)
++ != HFSP_SIGNATURE)) {
++ ped_geometry_destroy (geom_ret);
++ return NULL;
++ } else
++ return geom_ret;
++ } else {
++ /* This is a standalone HFS+ volume ? */
++ PedSector search, max;
++ HfsPVolumeHeader *vh;
++ vh = (HfsPVolumeHeader *) buf;
++
++ if (!ped_geometry_read (geom, buf, 2, 1)
++ || (PED_BE16_TO_CPU (vh->signature) != HFSP_SIGNATURE))
++ return NULL;
++
++ max = (PedSector) PED_BE32_TO_CPU (vh->total_blocks)
++ * ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE );
++ search = max - ( PED_BE32_TO_CPU (vh->block_size)
++ / PED_SECTOR_SIZE ) - 1;
++ 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 (PED_BE16_TO_CPU (vh->signature) == HFSP_SIGNATURE)
++ return geom_ret;
++ }
++
++ ped_geometry_destroy (geom_ret);
++ return NULL;
++ }
++}
+
+ static PedGeometry*
+ hfs_probe (PedGeometry* geom)
+ {
+- char buf[512];
++ PedGeometry* geom_base;
++ PedGeometry* geom_plus = NULL;
++
++ if ((geom_base = hfs_and_wrapper_probe(geom))
++ && (!(geom_plus = hfsplus_probe(geom_base))))
++ return geom_base;
++ else {
++ if (geom_base) ped_geometry_destroy (geom_base);
++ if (geom_plus) ped_geometry_destroy (geom_plus);
++ return NULL;
++ }
++}
++
++#ifndef DISCOVER_ONLY
++/* declaration used by hfs_btree_search (indirect recursion) */
++static int
++hfs_file_read_sector (HfsPrivateFile* file, void *buf, PedSector sector);
++
++static int
++hfs_clobber (PedGeometry* geom)
++{
++ uint8_t buf[PED_SECTOR_SIZE];
++
++ memset (buf, 0, PED_SECTOR_SIZE);
++
++ /* destroy boot blocks, mdb, alternate mdb ... */
++ return ped_geometry_write (geom, buf, 0, 1) &
++ ped_geometry_write (geom, buf, 1, 1) &
++ ped_geometry_write (geom, buf, 2, 1) &
++ ped_geometry_write (geom, buf, geom->length - 2, 1) &
++ ped_geometry_write (geom, buf, geom->length - 1, 1);
++}
++
++static int
++hfsplus_clobber (PedGeometry* geom)
++{
++ unsigned int i = 1;
++ uint8_t buf[PED_SECTOR_SIZE];
++ HfsMasterDirectoryBlock *mdb;
++
++ mdb = (HfsMasterDirectoryBlock *) buf;
++
++ if (!ped_geometry_read (geom, buf, 2, 1))
++ return 0;
++
++
++ if (PED_BE16_TO_CPU (mdb->signature) == HFS_SIGNATURE) {
++ /* embedded hfs+ */
++ PedGeometry *embedded;
++
++ i = (PED_BE32_TO_CPU(mdb->block_size) / PED_SECTOR_SIZE);
++ embedded = ped_geometry_new (
++ geom->dev,
++ (PedSector) geom->start
++ + PED_BE16_TO_CPU (mdb->start_block)
++ + (PedSector) PED_BE16_TO_CPU (
++ mdb->old_new.embedded.location.start_block ) * i,
++ (PedSector) PED_BE16_TO_CPU (
++ mdb->old_new.embedded.location.block_count ) * i );
++ i = hfs_clobber (embedded);
++ ped_geometry_destroy (embedded);
++ }
++
++ /* non-embedded or envelop destroy as hfs */
++ return ( hfs_clobber (geom) && i );
++}
++
++/* Open the data fork of a file with its first three extents and its CNID */
++static HfsPrivateFile*
++hfs_file_open (PedFileSystem *fs, uint32_t CNID,
++ HfsExtDataRec ext_desc, PedSector sect_nb)
++{
++ HfsPrivateFile* file;
++
++ file = (HfsPrivateFile*) ped_malloc (sizeof (HfsPrivateFile));
++
++ file->fs = fs;
++ file->sect_nb = sect_nb;
++ file->CNID = CNID;
++ memcpy(file->first, ext_desc, sizeof (HfsExtDataRec));
++ memcpy(file->cache, ext_desc, sizeof (HfsExtDataRec));
++ file->start_cache = 0;
++
++ return file;
++}
++
++/* Close an HFS file */
++static void
++hfs_file_close (HfsPrivateFile* file)
++{
++ ped_free (file);
++}
++
++/* 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 */
++static 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];
++ HfsHeaderRecord* header;
++ HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
++ HfsPrivateGenericKey* record_key = NULL;
++ unsigned int node_number, record_number;
++ int i;
++
++ /* Read the header node */
++ if (!hfs_file_read_sector(b_tree_file, node, 0))
++ return 0;
++ header = ((HfsHeaderRecord*) (node + PED_BE16_TO_CPU(*((uint16_t *)
++ (node+(PED_SECTOR_SIZE-2))))));
++
++ /* Get the node number of the root */
++ node_number = PED_BE32_TO_CPU(header->root_node);
++
++ /* 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--) {
++ int cmp, min_length;
++
++ record_key = (HfsPrivateGenericKey*)
++ (node + PED_BE16_TO_CPU(*((uint16_t *)
++ (node+(PED_SECTOR_SIZE - 2*i)))));
++ /* check for obvious error in FS */
++ if (((uint8_t*)record_key - node < HFS_FIRST_REC)
++ || ((uint8_t*)record_key - node
++ >= PED_SECTOR_SIZE
++ - 2 * (signed)(record_number+1)))
++ return 0;
++ min_length = ( (key->key_length
++ > record_key->key_length) ?
++ (record_key->key_length) :
++ (key->key_length) );
++ cmp = memcmp (record_key->key_content,
++ key->key_content, min_length);
++ if (cmp < 0 || ( cmp == 0 && record_key->key_length
++ <= key->key_length))
++ break;
++ }
++ if (!i) return 0;
++ if (desc->type == HFS_IDX_NODE) {
++ unsigned int skip;
++
++ skip = (1 + record_key->key_length + 1) & ~1;
++ node_number = PED_BE32_TO_CPU (*((uint32_t *)
++ (((uint8_t *) record_key) + skip)));
++ 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 = (uint8_t*)record_key - node;
++ record_ref->record_number = i;
++ }
++
++ /* success */
++ return 1;
++}
++
++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;
++ HfsMasterDirectoryBlock* mdb = priv_data->mdb;
++ unsigned int i, s, vol_block;
++ unsigned int block = sector
++ / (PED_BE32_TO_CPU (mdb->block_size)
++ / PED_SECTOR_SIZE);
++ unsigned int offset = sector
++ % (PED_BE32_TO_CPU (mdb->block_size)
++ / PED_SECTOR_SIZE);
++
++ /* in the three first extent */
++ for (s = 0, i = 0; i < HFS_EXT_NB; i++,
++ s += PED_BE16_TO_CPU (file->first[i].block_count)) {
++ 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;
++ }
++ }
++
++ /* in the three cached extent */
++ for (s = file->start_cache, i = 0; i < HFS_EXT_NB; i++,
++ s += PED_BE16_TO_CPU (file->cache[i].block_count)) {
++ 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;
++ }
++ }
++
++ /* update cache */
++ if (!hfs_get_extent_containing (file, block, file->cache,
++ &(file->start_cache)))
++ return 0;
++
++ /* in the three cached extent */
++ for (s = file->start_cache, i = 0; i < HFS_EXT_NB; i++,
++ s += PED_BE16_TO_CPU (file->cache[i].block_count)) {
++ 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;
++ }
++ }
++
++ return 0;
++
++ sector_found:
++ return (PedSector) PED_BE16_TO_CPU (mdb->start_block)
++ + (PedSector) vol_block * (PED_BE32_TO_CPU (mdb->block_size)
++ / PED_SECTOR_SIZE)
++ + offset;
++}
++
++/* Read the nth sector of a file */
++/* return 0 on error */
++static int
++hfs_file_read_sector (HfsPrivateFile* file, void *buf, PedSector sector)
++{
++ PedSector abs_sector;
++
++ if (sector >= file->sect_nb)
++ return 0;
++
++ abs_sector = hfs_file_find_sector (file, sector);
++ return abs_sector && ped_geometry_read (file->fs->geom, buf,
++ abs_sector, 1);
++}
++
++/* Write the nth sector of a file */
++/* return 0 on error */
++static int
++hfs_file_write_sector (HfsPrivateFile* file, void *buf, PedSector sector)
++{
++ PedSector abs_sector;
++
++ if (sector >= file->sect_nb)
++ return 0;
++
++ abs_sector = hfs_file_find_sector (file, sector);
++ return abs_sector && ped_geometry_write (file->fs->geom, buf,
++ abs_sector, 1);
++}
++
++/* This function reads bad blocks extents in the extents file
++ and store it in f.s. specific data of fs */
++static int
++hfs_read_bad_blocks (const PedFileSystem *fs)
++{
++ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
++ fs->type_specific;
++
++ if (!priv_data->bad_blocks_loaded) {
++ 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)) {
++ if (first_pass)
++ break;
++ else
++ return 0;
++ }
++ if (ret_key->file_ID != search.file_ID
++ || ret_key->type != search.type)
++ break;
++ 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));
++ 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;
++}
++
++/* free the bad blocks linked list */
++static void
++hfs_free_bad_blocks_list(HfsPrivateLinkExtent* first)
++{
++ HfsPrivateLinkExtent* next;
++
++ while (first) {
++ next = first->next;
++ ped_free (first);
++ first = next;
++ }
++}
++
++/* This function check if fblock is a bad block */
++static int
++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 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;
++ uint8_t* block;
++ unsigned int i;
++ unsigned int new_start;
++
++ /* try to find enough room to fit the extent */
++ for (i = *ptr_to_fblock;
++ i < *ptr_to_fblock + size && i < *ptr_fblock;
++ i++) {
++ if (hfs_is_bad_block (fs, i))
++ *ptr_to_fblock = i+1;
++ }
++
++ if (*ptr_to_fblock < *ptr_fblock) {
++ /* enough room */
++ block = (uint8_t*) ped_malloc(PED_BE32_TO_CPU (
++ priv_data->mdb->block_size));
++
++ new_start = *ptr_to_fblock;
++
++ /* move blocks one by one */
++ for (i = 0; i < size; i++) {
++ PedSector abs_sector;
++ unsigned int bit, byte;
++ unsigned int to_bit, to_byte;
++
++ abs_sector = (PedSector) PED_BE16_TO_CPU (
++ priv_data->mdb->start_block)
++ + (PedSector) (*ptr_fblock + i)
++ * (PED_BE32_TO_CPU (
++ priv_data->mdb->block_size)
++ / PED_SECTOR_SIZE);
++ if (!ped_geometry_read (fs->geom, block, abs_sector,
++ PED_BE32_TO_CPU (
++ priv_data->mdb->block_size)
++ / PED_SECTOR_SIZE))
++ return -1;
++
++ abs_sector = (PedSector) PED_BE16_TO_CPU (
++ priv_data->mdb->start_block)
++ + (PedSector) (*ptr_to_fblock + i)
++ * (PED_BE32_TO_CPU (
++ priv_data->mdb->block_size)
++ / PED_SECTOR_SIZE);
++ if (!ped_geometry_write (fs->geom, block, abs_sector,
++ PED_BE32_TO_CPU (
++ priv_data->mdb->block_size)
++ / PED_SECTOR_SIZE))
++ return -1;
++
++ bit = 7 - ((*ptr_fblock + i) & 7);
++ byte = (*ptr_fblock + i) / 8;
++
++ to_bit = 7 - ((*ptr_to_fblock + i) & 7);
++ to_byte = (*ptr_to_fblock + i) / 8;
++
++ /* free source block */
++ priv_data->alloc_map[byte] &= ~(1 << bit);
++
++ /* set dest block */
++ priv_data->alloc_map[to_byte] |= (1 << to_bit);
++ }
++
++ /* save the allocation map */
++ if (!ped_geometry_write(fs->geom, priv_data->alloc_map,
++ PED_BE16_TO_CPU (
++ priv_data->mdb->volume_bitmap_block),
++ ( PED_BE16_TO_CPU (
++ priv_data->mdb->total_blocks)
++ + PED_SECTOR_SIZE * 8 - 1)
++ / (PED_SECTOR_SIZE * 8)))
++ return -1;
++
++ ped_free (block);
++
++ *ptr_fblock += size;
++ *ptr_to_fblock += size;
++ } else {
++ /* not enough room */
++ new_start = *ptr_fblock;
++ *ptr_fblock = *ptr_to_fblock = new_start + size;
++ }
++
++ return new_start;
++}
++
++/* Search an extent in the catalog file and move it if found */
++/* Return 1 if everything was fine */
++/* Return -1 if an error occured */
++/* Return 0 if no extent was found */
++static int
++hfs_search_move_catalog (PedFileSystem *fs, unsigned int *ptr_fblock,
++ unsigned int *ptr_to_fblock)
++{
++ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
++ fs->type_specific;
++ uint8_t node[PED_SECTOR_SIZE];
++ HfsHeaderRecord* header;
++ HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
++ HfsCatalogKey* catalog_key;
++ HfsCatalog* catalog_data;
++ unsigned int leaf_node, record_number;
++ unsigned int i, j;
++ int new_start;
++
++ /* Search the extent starting at *ptr_block in the catalog file */
++ if (!hfs_file_read_sector (priv_data->catalog_file, node, 0))
++ return -1;
++ header = ((HfsHeaderRecord*) (node + PED_BE16_TO_CPU(*((uint16_t *)
++ (node+(PED_SECTOR_SIZE-2))))));
++ leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
++
++ for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) {
++ if (!hfs_file_read_sector (priv_data->catalog_file, node,
++ leaf_node))
++ return -1;
++ record_number = PED_BE16_TO_CPU (desc->rec_nb);
++ for (i = 1; i <= record_number; i++) {
++ /* fucking undocumented alignement powered by apple :p */
++ unsigned int skip;
++ catalog_key = (HfsCatalogKey*) (node + PED_BE16_TO_CPU(
++ *((uint16_t *)(node+(PED_SECTOR_SIZE - 2*i)))));
++ skip = (1 + catalog_key->key_length + 1) & ~1;
++ catalog_data = (HfsCatalog*)(((uint8_t*)catalog_key)
++ + skip);
++ /* check for obvious error in FS */
++ if (((uint8_t*)catalog_key - node < HFS_FIRST_REC)
++ || ((uint8_t*)catalog_data - node
++ >= PED_SECTOR_SIZE
++ - 2 * (signed)(record_number+1)))
++ return -1;
++ if (catalog_data->type != HFS_CAT_FILE) continue;
++ for (j = 0; j < HFS_EXT_NB; j++) {
++ if (catalog_data
++ ->sel.file.extents_data[j].block_count
++ && PED_BE16_TO_CPU (catalog_data
++ ->sel.file.extents_data[j].start_block)
++ == (*ptr_fblock))
++ goto catalog_data_found;
++ if (catalog_data
++ ->sel.file.extents_res[j].block_count
++ && PED_BE16_TO_CPU (catalog_data
++ ->sel.file.extents_res[j].start_block)
++ == (*ptr_fblock))
++ goto catalog_res_found;
++ }
++ }
++ }
++ /* no extent starting a *ptr_block has been found in the catalog file */
++ return 0;
++
++
++ /* an extent part of a data fork has been found in the catalog file */
++ catalog_data_found:
++ new_start = hfs_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE16_TO_CPU (catalog_data
++ ->sel.file.extents_data[j]
++ .block_count));
++ if (new_start != -1) {
++ int old_start;
++ old_start = catalog_data->sel.file.extents_data[j].start_block;
++ catalog_data->sel.file.extents_data[j].start_block =
++ PED_CPU_TO_BE16 (new_start);
++ /* write if any changes */
++ if ((old_start != PED_CPU_TO_BE16 (new_start))
++ && !hfs_file_write_sector (priv_data->catalog_file,
++ node, leaf_node))
++ return -1;
++ return 1;
++ } else
++ return -1;
++
++ /* an extent part of a resource fork has been found in the catalog file */
++ catalog_res_found:
++ new_start = hfs_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE16_TO_CPU (catalog_data
++ ->sel.file.extents_res[j]
++ .block_count));
++ if (new_start != -1) {
++ int old_start;
++ old_start = catalog_data->sel.file.extents_res[j].start_block;
++ catalog_data->sel.file.extents_res[j].start_block =
++ PED_CPU_TO_BE16 (new_start);
++ /* write if any changes */
++ if ((old_start != PED_CPU_TO_BE16 (new_start))
++ && !hfs_file_write_sector (priv_data->catalog_file,
++ node, leaf_node))
++ return -1;
++ return 1;
++ } else
++ return -1;
++}
++
++/* Search an extent in the extent file and move it if found */
++/* Return 1 if everything was fine */
++/* Return -1 if an error occured */
++/* Return 0 if no extent was found */
++static int
++hfs_search_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock,
++ unsigned int *ptr_to_fblock)
++{
++ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
++ fs->type_specific;
++ uint8_t node[PED_SECTOR_SIZE];
++ HfsHeaderRecord* header;
++ HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
++ HfsExtentKey* extent_key;
++ HfsExtDescriptor* extent_data;
++ unsigned int leaf_node, record_number;
++ unsigned int i, j;
++ int new_start;
++
++ /* Search the extent in the extent file */
++ if (!hfs_file_read_sector (priv_data->extent_file, node, 0))
++ return -1;
++ header = ((HfsHeaderRecord*) (node + PED_BE16_TO_CPU(*((uint16_t *)
++ (node+(PED_SECTOR_SIZE-2))))));
++ leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
++
++ for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) {
++ if (!hfs_file_read_sector (priv_data->extent_file, node,
++ leaf_node))
++ return -1;
++ record_number = PED_BE16_TO_CPU (desc->rec_nb);
++ for (i = 1; i <= record_number; i++) {
++ extent_key = (HfsExtentKey*)
++ (node + PED_BE16_TO_CPU(*((uint16_t *)
++ (node+(PED_SECTOR_SIZE - 2*i)))));
++ extent_data = (HfsExtDescriptor*)(((uint8_t*)extent_key)
++ + sizeof (HfsExtentKey));
++ /* check for obvious error in FS */
++ if (((uint8_t*)extent_key - node < HFS_FIRST_REC)
++ || ((uint8_t*)extent_data - node
++ >= PED_SECTOR_SIZE
++ - 2 * (signed)(record_number+1)))
++ return -1;
++ for (j = 0; j < HFS_EXT_NB; j++) {
++ if (extent_data[j].block_count
++ && PED_BE16_TO_CPU (
++ extent_data[j].start_block)
++ == (*ptr_fblock))
++ goto extent_found;
++ }
++ }
++ }
++ /* no extent starting a *ptr_block has been found in the extents file */
++ return 0;
++
++ /* an extent has been found in the extents file */
++ extent_found:
++ new_start = hfs_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE16_TO_CPU (extent_data[j]
++ .block_count));
++ if (new_start != -1) {
++ int old_start;
++ old_start = extent_data[j].start_block;
++ extent_data[j].start_block = PED_CPU_TO_BE16 (new_start);
++ /* This extent might have been cached into the file structure
++ of the extent or catalog file */
++ if (priv_data->catalog_file->cache[j].start_block == old_start)
++ memcpy (priv_data->catalog_file->cache, extent_data,
++ sizeof (HfsExtDataRec));
++ if (priv_data->extent_file->cache[j].start_block == old_start)
++ memcpy (priv_data->extent_file->cache, extent_data,
++ sizeof (HfsExtDataRec));
++ /* write if any changes */
++ if ((old_start != PED_CPU_TO_BE16 (new_start))
++ && !hfs_file_write_sector (priv_data->extent_file, node,
++ leaf_node))
++ return -1;
++ return 1;
++ } else
++ return -1;
++}
+
+- if (geom->length < 2)
++/* Search an extent in the extent file and move it if found */
++/* Return 1 if everything was fine */
++/* Return -1 if an error occured */
++/* Return 0 if no extent was found */
++static int
++hfs_search_move_primary (PedFileSystem *fs, unsigned int *ptr_fblock,
++ unsigned int *ptr_to_fblock)
++{
++ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
++ fs->type_specific;
++ uint8_t node[PED_SECTOR_SIZE];
++ unsigned int j;
++ int new_start;
++
++ /* Search an extent in the MDB */
++ for (j = 0; j < HFS_EXT_NB; j++) {
++ if (priv_data->mdb->extents_file_rec[j].block_count
++ && PED_BE16_TO_CPU (priv_data->mdb->extents_file_rec[j]
++ .start_block)
++ == (*ptr_fblock))
++ goto ext_file_found;
++ if (priv_data->mdb->catalog_file_rec[j].block_count
++ && PED_BE16_TO_CPU (priv_data->mdb->catalog_file_rec[j]
++ .start_block)
++ == (*ptr_fblock))
++ goto cat_file_found;
++ }
++ return 0;
++
++ ext_file_found:
++ new_start = hfs_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE16_TO_CPU (priv_data->mdb
++ ->extents_file_rec[j]
++ .block_count));
++ if (new_start != -1) {
++ priv_data->mdb->extents_file_rec[j].start_block =
++ PED_CPU_TO_BE16 (new_start);
++ memcpy (priv_data->extent_file->first,
++ priv_data->mdb->extents_file_rec,
++ sizeof (HfsExtDataRec));
++ if (!priv_data->extent_file->start_cache)
++ memcpy (priv_data->extent_file->cache,
++ priv_data->extent_file->first,
++ sizeof (HfsExtDataRec));
++ goto update_mdb;
++ } else
++ return -1;
++
++
++ cat_file_found:
++ new_start = hfs_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE16_TO_CPU (priv_data->mdb
++ ->catalog_file_rec[j]
++ .block_count));
++ if (new_start != -1) {
++ priv_data->mdb->catalog_file_rec[j].start_block =
++ PED_CPU_TO_BE16 (new_start);
++ memcpy (priv_data->catalog_file->first,
++ priv_data->mdb->catalog_file_rec,
++ sizeof (HfsExtDataRec));
++ if (!priv_data->catalog_file->start_cache)
++ memcpy (priv_data->catalog_file->cache,
++ priv_data->catalog_file->first,
++ sizeof (HfsExtDataRec));
++ goto update_mdb;
++ } else
++ return -1;
++
++ update_mdb:
++ if (!ped_geometry_read (fs->geom, node, 2, 1))
++ return -1;
++ memcpy (node, priv_data->mdb, sizeof (HfsMasterDirectoryBlock));
++ if (!ped_geometry_write (fs->geom, node, 2, 1))
++ return -1;
++ if (!ped_geometry_write (fs->geom, node, fs->geom->length - 2, 1))
++ return -1;
++ return 1;
++}
++
++/* 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 occured */
++/* Return 0 if no extent was found */
++static int
++hfs_move_extent_starting_at (PedFileSystem *fs, unsigned int *ptr_fblock,
++ unsigned int *ptr_to_fblock)
++{
++ int ret;
++
++ /* order = decreasing probability to be found */
++ if ((ret = hfs_search_move_catalog (fs, ptr_fblock, ptr_to_fblock))
++ || (ret = hfs_search_move_extent (fs, ptr_fblock, ptr_to_fblock))
++ || (ret = hfs_search_move_primary (fs, ptr_fblock, ptr_to_fblock))) {
++ return ret;
++ }
++
++ return 0;
++}
++
++/* This function moves file's data to compact used and free space,
++ starting at fblock block */
++/* return 0 on error */
++static int
++hfs_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
++ PedTimer* timer)
++{
++ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
++ fs->type_specific;
++ HfsMasterDirectoryBlock* mdb = priv_data->mdb;
++ unsigned int to_fblock = fblock;
++ unsigned int start = fblock;
++ unsigned int div = PED_BE16_TO_CPU (mdb->total_blocks)
++ + 1 - start;
++ int byte, bit, ret;
++ int to_byte, to_bit;
++
++ to_byte = byte = fblock / 8;
++ to_bit = bit = 7 - (fblock & 7);
++
++ if (!hfs_read_bad_blocks (fs))
++ return 0;
++
++ while (fblock < PED_BE16_TO_CPU (mdb->total_blocks)) {
++ if (((priv_data->alloc_map[byte] >> bit) & 1)
++ && (!hfs_is_bad_block (fs, fblock))) {
++ if (!(ret = hfs_move_extent_starting_at (fs, &fblock,
++ &to_fblock)))
++ to_fblock = ++fblock;
++ else if (ret == -1)
++ return 0;
++ } else {
++ fblock++;
++ }
++
++ byte = fblock / 8;
++ bit = 7 - (fblock & 7);
++
++ to_byte = to_fblock / 8;
++ to_bit = 7 - (to_fblock & 7);
++
++ ped_timer_update(timer, (float)(fblock - start)/div);
++ }
++
++ return 1;
++}
++
++/* 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 */
++static PedSector
++hfs_get_empty_end (const PedFileSystem *fs)
++{
++ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
++ fs->type_specific;
++ HfsMasterDirectoryBlock* mdb = priv_data->mdb;
++ HfsPrivateLinkExtent* link;
++ unsigned int block, last_bad, end_free_blocks;
++ int byte, bit;
++
++ /* find the next block to the last bad block of the volume */
++ if (!hfs_read_bad_blocks (fs))
+ return 0;
++
++ last_bad = 0;
++ for (link = priv_data->bad_blocks_xtent_list; link; link = link->next) {
++ if ((unsigned int) PED_BE16_TO_CPU (link->extent.start_block)
++ + PED_BE16_TO_CPU (link->extent.block_count) > last_bad)
++ last_bad = PED_BE16_TO_CPU (link->extent.start_block)
++ + PED_BE16_TO_CPU (link->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++) {
++ byte = block / 8;
++ bit = 7 - (block & 7);
++ if (!((priv_data->alloc_map[byte]>>bit)&1))
++ 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);
++}
++
++/* return the block which should be used to pack data to have at
++ least free fblock blocks at the end of the volume */
++static unsigned int
++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 (!((priv_data->alloc_map[block / 8]
++ >> (7 - (block & 7))) & 1))
++ fblock--;
++ }
++
++ while (block && !((priv_data->alloc_map[block / 8]
++ >> (7 - (block & 7))) & 1))
++ block--;
++ if ((priv_data->alloc_map[block / 8] >> (7 - (block & 7))) & 1)
++ block++;
++
++ return block;
++}
++
++static PedFileSystem*
++hfs_open (PedGeometry* geom)
++{
++ uint8_t buf[PED_SECTOR_SIZE];
++ PedFileSystem* fs;
++ HfsMasterDirectoryBlock* mdb;
++ HfsPrivateFSData* priv_data;
++
++ /* Read MDB */
+ if (!ped_geometry_read (geom, buf, 2, 1))
++ return NULL;
++
++ /* Allocate memory */
++ fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
++ mdb = (HfsMasterDirectoryBlock*) ped_malloc (
++ sizeof (HfsMasterDirectoryBlock));
++ priv_data = (HfsPrivateFSData*) ped_malloc (
++ sizeof (HfsPrivateFSData));
++
++ memcpy (mdb, buf, sizeof (HfsMasterDirectoryBlock));
++
++ /* init structures */
++ priv_data->mdb = mdb;
++ priv_data->bad_blocks_loaded = 0;
++ priv_data->bad_blocks_xtent_nb = 0;
++ priv_data->bad_blocks_xtent_list = NULL;
++ priv_data->extent_file =
++ hfs_file_open (fs, PED_CPU_TO_BE32 (HFS_XTENT_ID),
++ mdb->extents_file_rec,
++ PED_CPU_TO_BE32 (mdb->extents_file_size)
++ / PED_SECTOR_SIZE);
++ priv_data->catalog_file =
++ hfs_file_open (fs, PED_CPU_TO_BE32 (HFS_CATALOG_ID),
++ mdb->catalog_file_rec,
++ PED_CPU_TO_BE32 (mdb->catalog_file_size)
++ / PED_SECTOR_SIZE);
++
++ /* Read allocation blocks */
++ if (!ped_geometry_read(geom, priv_data->alloc_map,
++ PED_BE16_TO_CPU (mdb->volume_bitmap_block),
++ ( PED_BE16_TO_CPU (mdb->total_blocks)
++ + PED_SECTOR_SIZE * 8 - 1 )
++ / (PED_SECTOR_SIZE * 8) ) ) {
++ hfs_file_close (priv_data->extent_file);
++ hfs_file_close (priv_data->catalog_file);
++ ped_free(fs); ped_free(mdb); ped_free(priv_data);
++ return NULL;
++ }
++
++ fs->type = &hfs_type;
++ fs->geom = ped_geometry_duplicate (geom);
++ fs->type_specific = (void*) priv_data;
++ fs->checked = ( PED_BE16_TO_CPU (mdb->volume_attributes)
++ >> HFS_UNMOUNTED ) & 1;
++
++ return fs;
++}
++
++static int
++hfs_close (PedFileSystem *fs)
++{
++ hfs_file_close (((HfsPrivateFSData*)(fs->type_specific))->extent_file);
++ hfs_file_close (((HfsPrivateFSData*)(fs->type_specific))->catalog_file);
++ if (((HfsPrivateFSData*)(fs->type_specific))->bad_blocks_loaded)
++ hfs_free_bad_blocks_list (
++ ((HfsPrivateFSData*)(fs->type_specific))
++ ->bad_blocks_xtent_list);
++ ped_free (((HfsPrivateFSData*)(fs->type_specific))->mdb);
++ ped_free (fs->type_specific);
++ ped_geometry_destroy (fs->geom);
++ ped_free (fs);
++
++ return 1;
++}
++
++static PedConstraint*
++hfs_get_resize_constraint (const PedFileSystem *fs)
++{
++ PedDevice* dev = fs->geom->dev;
++ PedAlignment start_align;
++ PedGeometry start_sector;
++ PedGeometry full_dev;
++ PedSector min_size;
++
++ if (!ped_alignment_init (&start_align, fs->geom->start, 0))
++ return NULL;
++ if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
++ return NULL;
++ if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
++ return NULL;
++ /* 2 = last two sectors (alternate MDB and unused sector) */
++ min_size = hfs_get_empty_end(fs) + 2;
++
++ return ped_constraint_new (&start_align, ped_alignment_any,
++ &start_sector, &full_dev, min_size,
++ fs->geom->length);
++}
++
++static int
++hfs_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
++{
++ uint8_t buf[PED_SECTOR_SIZE];
++ unsigned int nblock, nfree;
++ unsigned int block;
++ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
++ fs->type_specific;
++ HfsMasterDirectoryBlock* mdb = priv_data->mdb;
++ int resize = 1;
++ unsigned int hfs_sect_block = ( PED_BE32_TO_CPU (
++ mdb->block_size)
++ / PED_SECTOR_SIZE);
++
++
++ /* check preconditions */
++ PED_ASSERT (fs->geom->dev == geom->dev, return 0);
++
++ if (fs->geom->start != geom->start)
++ {
++ ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
++ PED_EXCEPTION_CANCEL,
++ _("Sorry, can't move the start of hfs partitions yet!"));
++ return 0;
++ }
++
++ if (geom->length > fs->geom->length
++ || geom->length < hfs_get_empty_end(fs) + 2)
++ return 0;
++
++ /* Clear the unmounted bit */
++ mdb->volume_attributes &= PED_CPU_TO_BE16 (~( 1 << HFS_UNMOUNTED ));
++ if (!ped_geometry_read (fs->geom, buf, 2, 1))
++ return 0;
++ memcpy (buf, mdb, sizeof (HfsMasterDirectoryBlock));
++ if (!ped_geometry_write (fs->geom, buf, 2, 1))
++ return 0;
++
++ ped_timer_reset (timer);
++ ped_timer_set_state_name(timer, _("shrinking"));
++ ped_timer_update(timer, 0.0);
++ /* relocate data */
++ block = hfs_find_start_pack (fs, ( fs->geom->length - geom->length
++ + hfs_sect_block - 1 )
++ / hfs_sect_block );
++ if (!hfs_pack_free_space_from_block (fs, block, timer)) {
++ resize = 0;
++ goto write_MDB;
++ }
++
++ /* Calculate new block number and other MDB field */
++ nblock = ( geom->length - (PED_BE16_TO_CPU (mdb->start_block) + 2) )
++ / hfs_sect_block;
++ nfree = PED_BE16_TO_CPU (mdb->free_blocks)
++ - ( PED_BE16_TO_CPU (mdb->total_blocks) - nblock );
++
++ /* Check that all block after future end are really free */
++ for (block = nblock;
++ block < PED_BE16_TO_CPU (mdb->total_blocks);
++ block++) {
++ int byte, bit;
++ byte = block / 8;
++ bit = 7 - (block & 7);
++ if ((priv_data->alloc_map[byte]>>bit)&1) {
++ resize = 0;
++ goto write_MDB;
++ }
++ }
++
++ /* Update geometry */
++ if (resize) {
++ /* update in fs structure */
++ if (PED_BE16_TO_CPU (mdb->next_allocation) >= nblock)
++ mdb->next_allocation = PED_CPU_TO_BE16 (0);
++ mdb->total_blocks = PED_CPU_TO_BE16 (nblock);
++ mdb->free_blocks = PED_CPU_TO_BE16 (nfree);
++ /* update parted structure */
++ fs->geom->length = geom->length;
++ fs->geom->end = fs->geom->start + geom->length - 1;
++ }
++
++ /* Set the unmounted bit */
++ mdb->volume_attributes |= PED_CPU_TO_BE16 ( 1 << HFS_UNMOUNTED );
++
++ /* Effective write */
++ write_MDB:
++ ped_timer_set_state_name(timer,_("writing HFS Master Directory Block"));
++ if (!ped_geometry_read (fs->geom, buf, 2, 1))
++ return 0;
++ memcpy (buf, mdb, sizeof (HfsMasterDirectoryBlock));
++ if (!ped_geometry_write (fs->geom, buf, 2, 1))
+ return 0;
++ if (!ped_geometry_write (fs->geom, buf, fs->geom->length - 2, 1))
++ return 0;
++ ped_timer_update(timer, 1.0);
++
++ return (resize);
++}
++
++/* ----- HFS+ ----- */
++
++/* Open the data fork of a file with its first eight extents and its CNID */
++static HfsPPrivateFile*
++hfsplus_file_open (PedFileSystem *fs, HfsPNodeID CNID,
++ HfsPExtDataRec ext_desc, PedSector sect_nb)
++{
++ HfsPPrivateFile* file;
++
++ file = (HfsPPrivateFile*) ped_malloc (sizeof (HfsPPrivateFile));
++
++ file->fs = fs;
++ file->sect_nb = sect_nb;
++ file->CNID = CNID;
++ memcpy(file->first, ext_desc, sizeof (HfsPExtDataRec));
++ memcpy(file->cache, ext_desc, sizeof (HfsPExtDataRec));
++ file->start_cache = 0;
++
++ return file;
++}
+
+- if (PED_BE16_TO_CPU (*(uint16_t*) buf) == HFS_SIGNATURE)
+- return ped_geometry_duplicate (geom);
+- else
++/* Close an HFS+ file */
++static void
++hfsplus_file_close (HfsPPrivateFile* file)
++{
++ ped_free (file);
++}
++
++/* declaration of hfsplus_file_read(_sector)
++ because it's used by hfsplus_btree_search (indirect recursion) */
++static int
++hfsplus_file_read_sector (HfsPPrivateFile* file, void *buf, PedSector sector);
++static int
++hfsplus_file_read(HfsPPrivateFile* file, void *buf,
++ PedSector sector, unsigned int nb);
++
++/* 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) */
++static 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];
++ uint8_t* node;
++ HfsPHeaderRecord* header;
++ HfsPNodeDescriptor* desc = (HfsPNodeDescriptor*) node_1;
++ HfsPPrivateGenericKey* record_key = NULL;
++ unsigned int node_number, record_number, size, bsize;
++ int i;
++
++ /* 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);
++
++ /* Get the size of a node in sectors and allocate buffer */
++ size = (bsize = PED_BE16_TO_CPU (header->node_size)) / PED_SECTOR_SIZE;
++ node = (uint8_t*) ped_malloc (bsize);
++ 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--) {
++ int cmp, min_length;
++
++ record_key = (HfsPPrivateGenericKey*)
++ (node + PED_BE16_TO_CPU(*((uint16_t *)
++ (node+(bsize - 2*i)))));
++ /* check for obvious error in FS */
++ if (((uint8_t*)record_key - node < HFS_FIRST_REC)
++ || ((uint8_t*)record_key - node
++ >= (signed)bsize
++ - 2 * (signed)(record_number+1))) {
++ ped_free (node);
++ return 0;
++ }
++ min_length = ((PED_BE16_TO_CPU(key->key_length)
++ >PED_BE16_TO_CPU(record_key->key_length))?
++ PED_BE16_TO_CPU(record_key->key_length) :
++ PED_BE16_TO_CPU(key->key_length) );
++ cmp = memcmp (record_key->key_content, key->key_content,
++ min_length);
++ if (cmp < 0 || ( cmp == 0 && PED_BE16_TO_CPU (
++ record_key->key_length)
++ <= PED_BE16_TO_CPU (
++ key->key_length)))
++ break;
++ }
++ if (!i) { ped_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;
++ node_number = PED_BE32_TO_CPU (*((uint32_t *)
++ (((uint8_t *) record_key) + skip)));
++ if (!hfsplus_file_read(b_tree_file, node,
++ (PedSector) node_number * size,
++ size)) {
++ ped_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 = (uint8_t*)record_key - node;
++ record_ref->record_number = i;
++ }
++
++ /* success */
++ ped_free (node);
++ return 1;
++}
++
++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 the nth sector of a file */
++/* return 0 on error */
++static PedSector
++hfsplus_file_find_sector (HfsPPrivateFile* file, PedSector sector)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ file->fs->type_specific;
++ HfsPVolumeHeader* vh = priv_data-> vh;
++ unsigned int i, s, vol_block;
++ unsigned int block = sector
++ / ( PED_BE32_TO_CPU (vh->block_size)
++ / PED_SECTOR_SIZE );
++ unsigned int offset = sector
++ % ( PED_BE32_TO_CPU (vh->block_size)
++ / PED_SECTOR_SIZE );
++
++ /* in the three first extent */
++ for (s = 0, i = 0;
++ i < HFSP_EXT_NB;
++ i++, s += PED_BE32_TO_CPU (file->first[i].block_count)) {
++ 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);
++ goto plus_sector_found;
++ }
++ }
++
++ /* in the three cached extent */
++ for (s = file->start_cache, i = 0;
++ i < HFSP_EXT_NB;
++ i++, s += PED_BE32_TO_CPU (file->cache[i].block_count)) {
++ 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);
++ goto plus_sector_found;
++ }
++ }
++
++ /* update cache */
++ if (!hfsplus_get_extent_containing (file, block, file->cache,
++ &(file->start_cache)))
++ return 0;
++
++ /* in the three cached extent */
++ for (s = file->start_cache, i = 0;
++ i < HFSP_EXT_NB;
++ i++, s += PED_BE32_TO_CPU (file->cache[i].block_count)) {
++ 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);
++ goto plus_sector_found;
++ }
++ }
++
++ return 0;
++
++ plus_sector_found:
++ return (PedSector) vol_block * ( PED_BE32_TO_CPU (vh->block_size)
++ / PED_SECTOR_SIZE ) + offset;
++}
++
++/* Read the nth sector of a file */
++/* return 0 on error */
++static int
++hfsplus_file_read_sector (HfsPPrivateFile* file, void *buf, PedSector sector)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ file->fs->type_specific;
++ PedSector abs_sector;
++
++ if (sector >= file->sect_nb)
++ return 0;
++
++ abs_sector = hfsplus_file_find_sector (file, sector);
++ return abs_sector && ped_geometry_read (priv_data->plus_geom, buf,
++ abs_sector, 1);
++}
++
++static int
++hfsplus_file_read(HfsPPrivateFile* file, void *buf, PedSector sector,
++ unsigned int nb)
++{
++ while (nb) {
++ if (!hfsplus_file_read_sector (file, buf, sector))
++ return 0;
++
++ buf += PED_SECTOR_SIZE;
++ nb--;
++ sector++;
++ }
++
++ return 1;
++}
++
++/* Write the nth sector of a file */
++/* return 0 on error */
++static int
++hfsplus_file_write_sector (HfsPPrivateFile* file, void *buf, PedSector sector)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ file->fs->type_specific;
++ PedSector abs_sector;
++
++ if (sector >= file->sect_nb)
++ return 0;
++
++ abs_sector = hfsplus_file_find_sector (file, sector);
++ return abs_sector && ped_geometry_write (priv_data->plus_geom, buf,
++ abs_sector, 1);
++}
++
++static int
++hfsplus_file_write (HfsPPrivateFile* file, void *buf, PedSector sector,
++ unsigned int nb)
++{
++ while (nb) {
++ if (!hfsplus_file_write_sector (file, buf, sector))
++ return 0;
++
++ buf += PED_SECTOR_SIZE;
++ nb--;
++ sector++;
++ }
++
++ return 1;
++}
++
++/* This function reads bad blocks extents in the extents file
++ and store it in f.s. specific data of fs */
++static int
++hfsplus_read_bad_blocks (const PedFileSystem *fs)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++
++ if (!priv_data->bad_blocks_loaded) {
++ 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)) {
++ if (first_pass)
++ break;
++ else
++ return 0;
++ }
++ if (ret_key->file_ID != search.file_ID
++ || ret_key->type != search.type)
++ break;
++ 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));
++ 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;
++}
++
++/* free the bad blocks linked list */
++static void
++hfsplus_free_bad_blocks_list(HfsPPrivateLinkExtent* first)
++{
++ HfsPPrivateLinkExtent* next;
++
++ while (first) {
++ next = first->next;
++ ped_free (first);
++ first = next;
++ }
++}
++
++/* This function check if fblock is a bad block */
++static int
++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;
++}
++
++static int
++hfsplus_close (PedFileSystem *fs)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++
++ if (priv_data->wrapper) hfs_close(priv_data->wrapper);
++ if (priv_data->free_geom) ped_geometry_destroy (priv_data->plus_geom);
++ ped_free(priv_data->alloc_map);
++ hfsplus_file_close (priv_data->extents_file);
++ hfsplus_file_close (priv_data->catalog_file);
++ hfsplus_file_close (priv_data->attributes_file);
++ if (priv_data->bad_blocks_loaded)
++ hfsplus_free_bad_blocks_list(priv_data->bad_blocks_xtent_list);
++ ped_free (priv_data->vh);
++ ped_free (priv_data);
++ ped_geometry_destroy (fs->geom);
++ ped_free (fs);
++
++ return 1;
++}
++
++static PedFileSystem*
++hfsplus_open (PedGeometry* geom)
++{
++ uint8_t buf[PED_SECTOR_SIZE];
++ PedFileSystem* fs;
++ HfsPVolumeHeader* vh;
++ HfsPPrivateFSData* priv_data;
++ PedGeometry* wrapper_geom;
++ HfsPPrivateFile* allocation_file;
++ unsigned int map_sectors;
++
++ fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
++ vh = (HfsPVolumeHeader*) ped_malloc (sizeof (HfsPVolumeHeader));
++ priv_data = (HfsPPrivateFSData*)ped_malloc (sizeof (HfsPPrivateFSData));
++
++ fs->geom = ped_geometry_duplicate (geom);
++ fs->type_specific = (void*) priv_data;
++
++ if ((wrapper_geom = hfs_and_wrapper_probe (geom))) {
++ HfsPrivateFSData* hfs_priv_data;
++ PedSector abs_sect, length;
++ unsigned int bs;
++
++ ped_geometry_destroy (wrapper_geom);
++ priv_data->wrapper = hfs_open(geom);
++ hfs_priv_data = (HfsPrivateFSData*)
++ priv_data->wrapper->type_specific;
++ bs = PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
++ / PED_SECTOR_SIZE;
++ abs_sect = (PedSector) geom->start
++ + (PedSector) PED_BE16_TO_CPU (
++ hfs_priv_data->mdb->start_block)
++ + (PedSector) PED_BE16_TO_CPU (
++ hfs_priv_data->mdb->old_new
++ .embedded.location.start_block )
++ * bs;
++ length = (PedSector) PED_BE16_TO_CPU (
++ hfs_priv_data->mdb->old_new
++ .embedded.location.block_count)
++ * bs;
++ priv_data->plus_geom = ped_geometry_new (geom->dev, abs_sect,
++ length);
++ priv_data->free_geom = 1;
++ } else {
++ priv_data->wrapper = NULL;
++ priv_data->plus_geom = fs->geom;
++ priv_data->free_geom = 0;
++ }
++
++ if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1)) {
++ if (priv_data->wrapper)
++ hfs_close(priv_data->wrapper);
++ if (priv_data->free_geom)
++ ped_geometry_destroy (priv_data->plus_geom);
++ ped_free (vh);
++ ped_free (priv_data);
++ ped_geometry_destroy (fs->geom);
++ ped_free (fs);
+ return NULL;
++ }
++
++ memcpy (vh, buf, sizeof (HfsPVolumeHeader));
++
++ priv_data->vh = vh;
++ priv_data->bad_blocks_loaded = 0;
++ priv_data->bad_blocks_xtent_nb = 0;
++ priv_data->bad_blocks_xtent_list = NULL;
++ priv_data->extents_file =
++ hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_XTENT_ID),
++ vh->extents_file.extents,
++ PED_BE64_TO_CPU (
++ vh->extents_file.logical_size )
++ / PED_SECTOR_SIZE);
++ priv_data->catalog_file =
++ hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_CATALOG_ID),
++ vh->catalog_file.extents,
++ PED_BE64_TO_CPU (
++ vh->catalog_file.logical_size )
++ / PED_SECTOR_SIZE);
++ priv_data->attributes_file =
++ hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ATTRIB_ID),
++ vh->attributes_file.extents,
++ PED_BE64_TO_CPU (
++ vh->attributes_file.logical_size)
++ / PED_SECTOR_SIZE);
++ map_sectors = ( PED_BE32_TO_CPU (vh->total_blocks)
++ + PED_SECTOR_SIZE * 8 - 1 ) / (PED_SECTOR_SIZE * 8);
++ priv_data->alloc_map = (uint8_t*)
++ ped_malloc (map_sectors * PED_SECTOR_SIZE);
++
++ allocation_file =
++ hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ALLOC_ID),
++ vh->allocation_file.extents,
++ PED_BE64_TO_CPU (
++ vh->allocation_file.logical_size)
++ / PED_SECTOR_SIZE);
++ if (!hfsplus_file_read (allocation_file, priv_data->alloc_map, 0,
++ map_sectors)) {
++ hfsplus_file_close (allocation_file);
++ hfsplus_close(fs);
++ return NULL;
++ }
++ hfsplus_file_close (allocation_file);
++
++ fs->type = &hfsplus_type;
++ fs->checked = ((PED_BE32_TO_CPU (vh->attributes) >> HFS_UNMOUNTED) & 1)
++ && !((PED_BE32_TO_CPU (vh->attributes) >> HFSP_INCONSISTENT) & 1);
++
++ return fs;
+ }
+
+-#ifndef DISCOVER_ONLY
++/* 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_clobber (PedGeometry* geom)
++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;
++ uint8_t* block;
++ unsigned int i;
++ unsigned int new_start;
++
++ /* try to find enough room to fit the extent */
++ for (i = *ptr_to_fblock;
++ i < *ptr_to_fblock + size && i < *ptr_fblock;
++ i++) {
++ if (hfsplus_is_bad_block (fs, i))
++ *ptr_to_fblock = i+1;
++ }
++
++ if (*ptr_to_fblock < *ptr_fblock) {
++ /* enough room */
++ block = (uint8_t*) ped_malloc(PED_BE32_TO_CPU (
++ priv_data->vh->block_size));
++
++ new_start = *ptr_to_fblock;
++
++ /* move blocks one by one */
++ for (i = 0; i < size; i++) {
++ PedSector abs_sector;
++ unsigned int bit, byte;
++ unsigned int to_bit, to_byte;
++
++ abs_sector = (PedSector) (*ptr_fblock + i)
++ * ( PED_BE32_TO_CPU (priv_data->vh->block_size)
++ / PED_SECTOR_SIZE );
++ if (!ped_geometry_read (priv_data->plus_geom, block,
++ abs_sector,
++ PED_BE32_TO_CPU (
++ priv_data->vh->block_size )
++ / PED_SECTOR_SIZE))
++ return -1;
++
++ abs_sector = (PedSector) (*ptr_to_fblock + i)
++ * ( PED_BE32_TO_CPU (priv_data->vh->block_size)
++ / PED_SECTOR_SIZE );
++ if (!ped_geometry_write (priv_data->plus_geom, block,
++ abs_sector,
++ PED_BE32_TO_CPU (
++ priv_data->vh->block_size )
++ / PED_SECTOR_SIZE))
++ return -1;
++
++ bit = 7 - ((*ptr_fblock + i) & 7);
++ byte = (*ptr_fblock + i) / 8;
++
++ to_bit = 7 - ((*ptr_to_fblock + i) & 7);
++ to_byte = (*ptr_to_fblock + i) / 8;
++
++ /* free source block */
++ priv_data->alloc_map[byte] &= ~(1 << bit);
++
++ /* set dest block */
++ priv_data->alloc_map[to_byte] |= (1 << to_bit);
++ }
++
++/* TODO : a better handling of allocation map saving process */
++#if 0
++ /* save the allocation map */
++ if (!ped_geometry_write(fs->geom, priv_data->alloc_map, PED_BE16_TO_CPU (priv_data->mdb->volume_bitmap_block),
++ (PED_BE16_TO_CPU (priv_data->mdb->total_blocks) + PED_SECTOR_SIZE * 8 - 1) / (PED_SECTOR_SIZE * 8)))
++ return -1;
++#endif
++
++ ped_free (block);
++
++ *ptr_fblock += size;
++ *ptr_to_fblock += size;
++ } else {
++ /* not enough room */
++ new_start = *ptr_fblock;
++ *ptr_fblock = *ptr_to_fblock = new_start + size;
++ }
++
++ return new_start;
++}
++
++/* Search an extent in the catalog file and move it if found */
++/* Return 1 if everything was fine */
++/* Return -1 if an error occured */
++/* Return 0 if no extent was found */
++static int
++hfsplus_search_move_catalog (PedFileSystem *fs, unsigned int *ptr_fblock,
++ unsigned int *ptr_to_fblock)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++ uint8_t node_1[PED_SECTOR_SIZE];
++ uint8_t* node;
++ HfsPHeaderRecord* header;
++ HfsPNodeDescriptor* desc = (HfsPNodeDescriptor*) node_1;
++ HfsPCatalogKey* catalog_key;
++ HfsPCatalog* catalog_data;
++ unsigned int leaf_node, record_number;
++ unsigned int i, j, size, bsize;
++ int new_start;
++
++ /* Search the extent starting at *ptr_block in the catalog file */
++ if (!hfsplus_file_read_sector (priv_data->catalog_file, node_1, 0))
++ return -1;
++ 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;
++
++ node = (uint8_t*) ped_malloc (bsize);
++ 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)) {
++ ped_free (node);
++ return -1;
++ }
++ record_number = PED_BE16_TO_CPU (desc->rec_nb);
++ for (i = 1; i <= record_number; i++) {
++ unsigned int skip;
++ catalog_key = (HfsPCatalogKey*)
++ ( node + PED_BE16_TO_CPU (*((uint16_t *)
++ (node+(bsize - 2*i)))) );
++ 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 (((uint8_t*)catalog_key - node < HFS_FIRST_REC)
++ || ((uint8_t*)catalog_data - node
++ >= (signed) bsize
++ - 2 * (signed)(record_number+1))) {
++ ped_free (node);
++ return -1;
++ }
++ if (PED_BE16_TO_CPU(catalog_data->type)!=HFS_CAT_FILE)
++ continue;
++ for (j = 0; j < HFSP_EXT_NB; j++) {
++ if ( catalog_data->sel.file
++ .data_fork.extents[j].block_count
++ && PED_BE32_TO_CPU (catalog_data->sel
++ .file.data_fork.extents[j].start_block)
++ == (*ptr_fblock) )
++ goto plus_catalog_data_found;
++ if ( catalog_data->sel.file.res_fork
++ .extents[j].block_count
++ && PED_BE32_TO_CPU (catalog_data->sel
++ .file.res_fork.extents[j].start_block)
++ == (*ptr_fblock) )
++ goto plus_catalog_res_found;
++ }
++ }
++ }
++ /* no extent starting a *ptr_block has been found in the catalog file */
++ ped_free (node);
++ return 0;
++
++
++ /* an extent part of a data fork has been found in the catalog file */
++ plus_catalog_data_found:
++ new_start = hfsplus_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE32_TO_CPU (
++ catalog_data->sel.file
++ .data_fork.extents[j]
++ .block_count ));
++ if (new_start != -1) {
++ unsigned int old_start;
++ old_start = catalog_data->sel.file.data_fork
++ .extents[j].start_block;
++ catalog_data->sel.file.data_fork.extents[j].start_block =
++ PED_CPU_TO_BE32 (new_start);
++ /* write if any changes */
++ if ((old_start != (unsigned) PED_CPU_TO_BE32 (new_start))
++ && !hfsplus_file_write (priv_data->catalog_file, node,
++ (PedSector) leaf_node * size,
++ size)) {
++ ped_free (node);
++ return -1;
++ }
++ ped_free (node);
++ return 1;
++ } else {
++ ped_free (node);
++ return -1;
++ }
++
++ /* an extent part of a resource fork has been found
++ in the catalog file */
++ plus_catalog_res_found:
++ new_start = hfsplus_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE32_TO_CPU (
++ catalog_data->sel.file
++ .res_fork.extents[j]
++ .block_count ));
++ if (new_start != -1) {
++ unsigned int old_start;
++ old_start = catalog_data->sel.file.res_fork
++ .extents[j].start_block;
++ catalog_data->sel.file.res_fork.extents[j].start_block =
++ PED_CPU_TO_BE32 (new_start);
++ /* write if any changes */
++ if ((old_start != (unsigned) PED_CPU_TO_BE32 (new_start))
++ && !hfsplus_file_write (priv_data->catalog_file, node,
++ (PedSector) leaf_node * size,
++ size)) {
++ ped_free (node);
++ return -1;
++ }
++ ped_free (node);
++ return 1;
++ } else {
++ ped_free (node);
++ return -1;
++ }
++}
++
++/* Search an extent in the attributes file and move it if found */
++/* Return 1 if everything was fine */
++/* Return -1 if an error occured */
++/* Return 0 if no extent was found */
++static int
++hfsplus_search_move_attributes (PedFileSystem *fs, unsigned int *ptr_fblock,
++ unsigned int *ptr_to_fblock)
+ {
+- char buf[512];
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++ uint8_t node_1[PED_SECTOR_SIZE];
++ uint8_t* node;
++ HfsPHeaderRecord* header;
++ HfsPNodeDescriptor* desc = (HfsPNodeDescriptor*) node_1;
++ HfsPPrivateGenericKey* generic_key;
++ HfsPForkDataAttr* fork_ext_data;
++ unsigned int leaf_node, record_number;
++ unsigned int i, j, size, bsize;
++ int new_start;
++
++ /* attributes file is facultative */
++ if (!priv_data->attributes_file->sect_nb)
++ return 0;
++
++ /* Search the extent starting at *ptr_block in the catalog file */
++ if (!hfsplus_file_read_sector (priv_data->attributes_file, node_1, 0))
++ return -1;
++ 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;
++
++ node = (uint8_t*) ped_malloc (bsize);
++ 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)) {
++ ped_free (node);
++ return -1;
++ }
++ record_number = PED_BE16_TO_CPU (desc->rec_nb);
++ for (i = 1; i <= record_number; i++) {
++ unsigned int skip;
++ generic_key = (HfsPPrivateGenericKey*)
++ (node + PED_BE16_TO_CPU(*((uint16_t *)
++ (node+(bsize - 2*i)))));
++ skip = ( 2 + PED_BE16_TO_CPU (generic_key->key_length)
++ + 1 ) & ~1;
++ fork_ext_data = (HfsPForkDataAttr*)
++ (((uint8_t*)generic_key) + skip);
++ /* check for obvious error in FS */
++ if (((uint8_t*)generic_key - node < HFS_FIRST_REC)
++ || ((uint8_t*)fork_ext_data - node
++ >= (signed) bsize
++ - 2 * (signed)(record_number+1))) {
++ ped_free (node);
++ return -1;
++ }
++ if ( PED_BE32_TO_CPU (fork_ext_data->record_type )
++ == HFSP_ATTR_FORK) {
++ for (j = 0; j < HFSP_EXT_NB; j++) {
++ if ( fork_ext_data->fork_res.fork
++ .extents[j].block_count
++ && PED_BE32_TO_CPU (
++ fork_ext_data->fork_res
++ .fork.extents[j].start_block )
++ == (*ptr_fblock) )
++ goto plus_attr_fork_found;
++ }
++ } else if ( PED_BE32_TO_CPU (fork_ext_data->record_type)
++ == HFSP_ATTR_EXTENTS ) {
++ for (j = 0; j < HFSP_EXT_NB; j++) {
++ if ( fork_ext_data->fork_res
++ .extents[j].block_count
++ && PED_BE32_TO_CPU (
++ fork_ext_data->fork_res
++ .extents[j].start_block)
++ == (*ptr_fblock) )
++ goto plus_attr_ext_found;
++ }
++ } else continue;
++ }
++ }
++ /* no extent starting a *ptr_block has been found in the catalog file */
++ ped_free (node);
++ return 0;
+
+- memset (buf, 0, 512);
+- return ped_geometry_write (geom, buf, 2, 1);
++
++ /* an extent part of a attr fork has been found in the catalog file */
++ plus_attr_fork_found:
++ new_start = hfsplus_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE32_TO_CPU (
++ fork_ext_data->fork_res
++ .fork.extents[j]
++ .block_count));
++ if (new_start != -1) {
++ unsigned int old_start;
++ old_start = fork_ext_data->fork_res.fork.extents[j].start_block;
++ fork_ext_data->fork_res.fork.extents[j].start_block =
++ PED_CPU_TO_BE32 (new_start);
++ /* write if any changes */
++ if ((old_start != (unsigned) PED_CPU_TO_BE32 (new_start))
++ && !hfsplus_file_write (priv_data->attributes_file, node,
++ (PedSector) leaf_node * size,
++ size)) {
++ ped_free (node);
++ return -1;
++ }
++ ped_free (node);
++ return 1;
++ } else {
++ ped_free (node);
++ return -1;
++ }
++
++ /* an extent part of a attr ext has been found in the catalog file */
++ plus_attr_ext_found:
++ new_start = hfsplus_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE32_TO_CPU (
++ fork_ext_data->fork_res
++ .extents[j].block_count));
++ if (new_start != -1) {
++ unsigned int old_start;
++ old_start = fork_ext_data->fork_res.extents[j].start_block;
++ fork_ext_data->fork_res.extents[j].start_block =
++ PED_CPU_TO_BE32 (new_start);
++ /* write if any changes */
++ if ((old_start != (unsigned) PED_CPU_TO_BE32 (new_start))
++ && !hfsplus_file_write (priv_data->attributes_file, node,
++ (PedSector) leaf_node * size,
++ size)) {
++ ped_free (node);
++ return -1;
++ }
++ ped_free (node);
++ return 1;
++ } else {
++ ped_free (node);
++ return -1;
++ }
++}
++
++/* Search an extent in the extent file and move it if found */
++/* Return 1 if everything was fine */
++/* Return -1 if an error occured */
++/* Return 0 if no extent was found */
++static int
++hfsplus_search_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock,
++ unsigned int *ptr_to_fblock)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++ uint8_t node_1[PED_SECTOR_SIZE];
++ uint8_t* node;
++ HfsPHeaderRecord* header;
++ HfsPNodeDescriptor* desc = (HfsPNodeDescriptor*) node;
++ HfsPExtentKey* extent_key;
++ HfsPExtDescriptor* extent_data;
++ unsigned int leaf_node, record_number;
++ unsigned int i, j, size, bsize;
++ int new_start;
++
++ /* Search the extent in the extent file */
++ if (!hfsplus_file_read_sector (priv_data->extents_file, node_1, 0))
++ return -1;
++ 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;
++
++ node = (uint8_t*) ped_malloc (bsize);
++ 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)) {
++ ped_free (node);
++ return -1;
++ }
++ record_number = PED_BE16_TO_CPU (desc->rec_nb);
++ for (i = 1; i <= record_number; i++) {
++ extent_key = (HfsPExtentKey*)
++ (node + PED_BE16_TO_CPU(*((uint16_t *)
++ (node+(bsize - 2*i)))));
++ extent_data = (HfsPExtDescriptor*)
++ (((uint8_t*)extent_key) + sizeof (HfsPExtentKey));
++ /* check for obvious error in FS */
++ if (((uint8_t*)extent_key - node < HFS_FIRST_REC)
++ || ((uint8_t*)extent_data - node
++ >= (signed)bsize
++ - 2 * (signed)(record_number+1))) {
++ ped_free (node);
++ return -1;
++ }
++ for (j = 0; j < HFSP_EXT_NB; j++) {
++ if ( extent_data[j].block_count
++ && PED_BE32_TO_CPU (
++ extent_data[j].start_block)
++ == (*ptr_fblock) )
++ goto plus_extent_found;
++ }
++ }
++ }
++ /* no extent starting a *ptr_block has been found in the extents file */
++ ped_free (node);
++ return 0;
++
++ /* an extent has been found in the extents file */
++ plus_extent_found:
++ new_start = hfsplus_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE32_TO_CPU (
++ extent_data[j]
++ .block_count));
++ if (new_start != -1) {
++ unsigned int old_start;
++ old_start = extent_data[j].start_block;
++ extent_data[j].start_block = PED_CPU_TO_BE32 (new_start);
++ /* This extent might have been cached into the file structure
++ of the extent or catalog file */
++ if (priv_data->catalog_file->cache[j].start_block == old_start)
++ memcpy (priv_data->catalog_file->cache, extent_data,
++ sizeof (HfsPExtDataRec));
++ if (priv_data->extents_file->cache[j].start_block == old_start)
++ memcpy (priv_data->extents_file->cache, extent_data,
++ sizeof (HfsPExtDataRec));
++ if (priv_data->attributes_file->cache[j].start_block
++ == old_start)
++ memcpy (priv_data->attributes_file->cache,
++ extent_data, sizeof (HfsPExtDataRec));
++ /* write if any changes */
++ if ((old_start != (unsigned) PED_CPU_TO_BE32 (new_start))
++ && !hfsplus_file_write (priv_data->extents_file, node,
++ (PedSector) leaf_node * size,
++ size)) {
++ ped_free (node);
++ return -1;
++ }
++ ped_free (node);
++ return 1;
++ } else {
++ ped_free (node);
++ return -1;
++ }
++}
++
++/* Search an extent in the extent file and move it if found */
++/* Return 1 if everything was fine */
++/* Return -1 if an error occured */
++/* Return 0 if no extent was found */
++static int
++hfsplus_search_move_primary (PedFileSystem *fs, unsigned int *ptr_fblock,
++ unsigned int *ptr_to_fblock)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++ uint8_t node[PED_SECTOR_SIZE];
++ unsigned int j;
++ int new_start;
++
++ /* Search an extent in the MDB */
++ for (j = 0; j < HFSP_EXT_NB; j++) {
++ if ( priv_data->vh->extents_file.extents[j].block_count
++ && PED_BE32_TO_CPU (
++ priv_data->vh->extents_file.extents[j].start_block)
++ == (*ptr_fblock) )
++ goto plus_ext_file_found;
++ if ( priv_data->vh->catalog_file.extents[j].block_count
++ && PED_BE32_TO_CPU (
++ priv_data->vh->catalog_file.extents[j].start_block)
++ == (*ptr_fblock) )
++ goto plus_cat_file_found;
++ if ( priv_data->vh->allocation_file.extents[j].block_count
++ && PED_BE32_TO_CPU (
++ priv_data->vh->allocation_file.extents[j].start_block)
++ == (*ptr_fblock) )
++ goto plus_alloc_file_found;
++ if ( priv_data->vh->attributes_file.extents[j].block_count
++ && PED_BE32_TO_CPU (
++ priv_data->vh->attributes_file.extents[j].start_block)
++ == (*ptr_fblock) )
++ goto plus_attrib_file_found;
++ if ( priv_data->vh->startup_file.extents[j].block_count
++ && PED_BE32_TO_CPU (
++ priv_data->vh->startup_file.extents[j].start_block)
++ == (*ptr_fblock) )
++ goto plus_start_file_found;
++ }
++ return 0;
++
++ plus_start_file_found:
++ new_start = hfsplus_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE32_TO_CPU (
++ priv_data->vh->startup_file
++ .extents[j].block_count));
++ if (new_start != -1) {
++ priv_data->vh->startup_file.extents[j].start_block =
++ PED_CPU_TO_BE32 (new_start);
++#if 0
++ memcpy (priv_data->startup_file->first, priv_data->vh->startup_file.extents, sizeof (HfsPExtDataRec));
++ if (!priv_data->startup_file->start_cache)
++ memcpy (priv_data->startup_file->cache, priv_data->startup_file->first, sizeof (HfsPExtDataRec));
++#endif
++ goto plus_update_vh;
++ } else
++ return -1;
++
++ plus_attrib_file_found:
++ new_start = hfsplus_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE32_TO_CPU (
++ priv_data->vh
++ ->attributes_file
++ .extents[j].block_count));
++ if (new_start != -1) {
++ priv_data->vh->attributes_file.extents[j].start_block =
++ PED_CPU_TO_BE32 (new_start);
++ memcpy (priv_data->attributes_file->first,
++ priv_data->vh->attributes_file.extents,
++ sizeof (HfsPExtDataRec));
++ if (!priv_data->attributes_file->start_cache)
++ memcpy (priv_data->attributes_file->cache,
++ priv_data->attributes_file->first,
++ sizeof (HfsPExtDataRec));
++ goto plus_update_vh;
++ } else
++ return -1;
++
++ plus_alloc_file_found:
++ new_start = hfsplus_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE32_TO_CPU (
++ priv_data->vh
++ ->allocation_file
++ .extents[j].block_count));
++ if (new_start != -1) {
++ priv_data->vh->allocation_file.extents[j].start_block =
++ PED_CPU_TO_BE32 (new_start);
++#if 0
++ memcpy (priv_data->allocation_file->first, priv_data->vh->allocation_file.extents, sizeof (HfsPExtDataRec));
++ if (!priv_data->allocation_file->start_cache)
++ memcpy (priv_data->allocation_file->cache, priv_data->allocation_file->first, sizeof (HfsPExtDataRec));
++#endif
++ goto plus_update_vh;
++ } else
++ return -1;
++
++ plus_ext_file_found:
++ new_start = hfsplus_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE32_TO_CPU (
++ priv_data->vh->extents_file
++ .extents[j].block_count));
++ if (new_start != -1) {
++ priv_data->vh->extents_file.extents[j].start_block =
++ PED_CPU_TO_BE32 (new_start);
++ memcpy (priv_data->extents_file->first,
++ priv_data->vh->extents_file.extents,
++ sizeof (HfsPExtDataRec));
++ if (!priv_data->extents_file->start_cache)
++ memcpy (priv_data->extents_file->cache,
++ priv_data->extents_file->first,
++ sizeof (HfsPExtDataRec));
++ goto plus_update_vh;
++ } else
++ return -1;
++
++ plus_cat_file_found:
++ new_start = hfsplus_effect_move_extent (fs, ptr_fblock, ptr_to_fblock,
++ PED_BE32_TO_CPU (
++ priv_data->vh->catalog_file
++ .extents[j].block_count));
++ if (new_start != -1) {
++ priv_data->vh->catalog_file.extents[j].start_block =
++ PED_CPU_TO_BE32 (new_start);
++ memcpy (priv_data->catalog_file->first,
++ priv_data->vh->catalog_file.extents,
++ sizeof (HfsPExtDataRec));
++ if (!priv_data->catalog_file->start_cache)
++ memcpy (priv_data->catalog_file->cache,
++ priv_data->catalog_file->first,
++ sizeof (HfsPExtDataRec));
++ goto plus_update_vh;
++ } else
++ return -1;
++
++ plus_update_vh:
++ if (!ped_geometry_read (priv_data->plus_geom, node, 2, 1))
++ return -1;
++ memcpy (node, priv_data->vh, sizeof (HfsPVolumeHeader));
++ if (!ped_geometry_write (priv_data->plus_geom, node, 2, 1))
++ return -1;
++ if (!ped_geometry_write (priv_data->plus_geom, node,
++ priv_data->plus_geom->length - 2, 1))
++ return -1;
++ return 1;
++}
++
++/* 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 occured */
++/* 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)
++{
++ int ret;
++
++ /* order = decreasing probability to be found */
++ if ((ret = hfsplus_search_move_catalog (fs, ptr_fblock, ptr_to_fblock))
++ || (ret = hfsplus_search_move_extent (fs, ptr_fblock,
++ ptr_to_fblock))
++ || (ret = hfsplus_search_move_primary (fs, ptr_fblock,
++ ptr_to_fblock))
++ || (ret = hfsplus_search_move_attributes (fs, ptr_fblock,
++ ptr_to_fblock))) {
++ return ret;
++ }
++
++ return 0;
++}
++
++/* This function moves file's data to compact used and free space,
++ starting at fblock block */
++/* return 0 on error */
++static int
++hfsplus_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
++ PedTimer* timer)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++ HfsPVolumeHeader* vh = priv_data->vh;
++ unsigned int to_fblock = fblock;
++ int byte, bit, ret;
++ int to_byte, to_bit;
++ unsigned int start = fblock;
++ unsigned int div = PED_BE32_TO_CPU (vh->total_blocks)
++ + 1 - start;
++
++ to_byte = byte = fblock / 8;
++ to_bit = bit = 7 - (fblock & 7);
++
++ if (!hfsplus_read_bad_blocks (fs))
++ return 0;
++
++ while ( fblock < ( priv_data->plus_geom->length - 2 )
++ / ( PED_BE32_TO_CPU (vh->block_size)
++ / PED_SECTOR_SIZE ) ) {
++ if (((priv_data->alloc_map[byte] >> bit) & 1)
++ && (!hfsplus_is_bad_block (fs, fblock))) {
++ if (!(ret = hfsplus_move_extent_starting_at (fs,
++ &fblock,
++ &to_fblock)))
++ to_fblock = ++fblock;
++ else if (ret == -1)
++ return 0;
++ } else {
++ fblock++;
++ }
++
++ byte = fblock / 8;
++ bit = 7 - (fblock & 7);
++
++ to_byte = to_fblock / 8;
++ to_bit = 7 - (to_fblock & 7);
++
++ ped_timer_update(timer, (float)(fblock - start) / div);
++ }
++
++ return 1;
++}
++
++/* 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 */
++static PedSector
++hfsplus_get_empty_end (const PedFileSystem *fs)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++ HfsPVolumeHeader* vh = priv_data->vh;
++ HfsPPrivateLinkExtent* link;
++ unsigned int block, last_bad, end_free_blocks;
++ int byte, bit;
++
++ /* find the next block to the last bad block of the volume */
++ if (!hfsplus_read_bad_blocks (fs))
++ return 0;
++
++ last_bad = 0;
++ for (link = priv_data->bad_blocks_xtent_list; link; link = link->next) {
++ if ((unsigned int) PED_BE32_TO_CPU (link->extent.start_block)
++ + PED_BE32_TO_CPU (link->extent.block_count) > last_bad)
++ last_bad = PED_BE32_TO_CPU (link->extent.start_block)
++ + PED_BE32_TO_CPU (link->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++) {
++ byte = block / 8;
++ bit = 7 - (block & 7);
++ if (!((priv_data->alloc_map[byte]>>bit)&1))
++ 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 );
++}
++
++static 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
++ is part of allocation blocks in HFS+ */
++ min_size = hfsplus_get_empty_end(fs);
++
++ if (priv_data->wrapper) {
++ HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*)
++ priv_data->wrapper->type_specific;
++ unsigned int hfs_sect_block;
++ hfs_sect_block =
++ PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
++ / PED_SECTOR_SIZE;
++ /*
++ * 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
++ */
++ min_size = ((min_size + hfs_sect_block - 1) / hfs_sect_block)
++ * hfs_sect_block
++ + hfs_get_empty_end(priv_data->wrapper) + 2
++ - (PedSector) PED_BE16_TO_CPU ( hfs_priv_data->mdb
++ ->old_new.embedded
++ .location.block_count )
++ * hfs_sect_block;
++ }
++
++ return min_size;
++}
++
++static PedConstraint*
++hfsplus_get_resize_constraint (const PedFileSystem *fs)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++ PedDevice* dev = fs->geom->dev;
++ PedAlignment start_align;
++ PedGeometry start_sector;
++ PedGeometry full_dev;
++ PedSector min_size;
++
++ if (!ped_alignment_init (&start_align, fs->geom->start, 0))
++ return NULL;
++ if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
++ return NULL;
++ if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
++ return NULL;
++
++ min_size = hfsplus_get_min_size (fs);
++
++ return ped_constraint_new (&start_align, ped_alignment_any,
++ &start_sector, &full_dev, min_size,
++ fs->geom->length);
++}
++
++/* return the block which should be used to pack data to have
++ at least free fblock blocks at the end of the volume */
++static unsigned int
++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 (!((priv_data->alloc_map[block / 8]
++ >> (7 - (block & 7))) & 1))
++ fblock--;
++ }
++
++ while (block && !((priv_data->alloc_map[block / 8]
++ >> (7 - (block & 7))) & 1))
++ block--;
++ if ((priv_data->alloc_map[block / 8] >> (7 - (block & 7))) & 1)
++ block++;
++
++ return block;
++}
++
++static int
++hfsplus_volume_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
++{
++ uint8_t buf[PED_SECTOR_SIZE];
++ unsigned int nblock, nfree;
++ unsigned int block;
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++ HfsPVolumeHeader* vh = priv_data->vh;
++ int resize = 1;
++ unsigned int hfsp_sect_block =
++ ( PED_BE32_TO_CPU (vh->block_size)
++ / PED_SECTOR_SIZE );
++ HfsPPrivateFile* allocation_file;
++ unsigned int map_sectors;
++
++ /* Clear the unmounted bit */
++ vh->attributes &= PED_CPU_TO_BE32 (~( 1 << HFS_UNMOUNTED ));
++ if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1))
++ return 0;
++ memcpy (buf, vh, sizeof (HfsPVolumeHeader));
++ if (!ped_geometry_write (priv_data->plus_geom, buf, 2, 1))
++ return 0;
++
++ ped_timer_reset (timer);
++ ped_timer_set_state_name(timer, _("shrinking"));
++ ped_timer_update(timer, 0.0);
++ /* relocate data */
++ block = hfsplus_find_start_pack (fs, ( priv_data->plus_geom->length
++ - geom->length + hfsp_sect_block
++ - 1 ) / hfsp_sect_block );
++ if (!hfsplus_pack_free_space_from_block (fs, block, timer)) {
++ resize = 0;
++ goto write_VH;
++ }
++
++ /* Calculate new block number and other VH field */
++ nblock = (geom->length + hfsp_sect_block - 1) / hfsp_sect_block;
++ nfree = PED_BE32_TO_CPU (vh->free_blocks)
++ - (PED_BE32_TO_CPU (vh->total_blocks) - nblock);
++ if (priv_data->plus_geom->length % hfsp_sect_block == 1)
++ nfree++;
++ if (geom->length % hfsp_sect_block == 1)
++ nfree--;
++
++ /* Check that all block after future end are really free */
++ for ( block = nblock;
++ block < ( priv_data->plus_geom->length - 2 )
++ / ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE );
++ block++ ) {
++ int byte, bit;
++ byte = block / 8;
++ bit = 7 - (block & 7);
++ if ((priv_data->alloc_map[byte]>>bit)&1) {
++ resize = 0;
++ goto write_VH;
++ }
++ }
++
++ /* Update geometry */
++ if (resize) {
++ /* update in fs structure */
++ if (PED_BE32_TO_CPU (vh->next_allocation) >= nblock)
++ vh->next_allocation = PED_CPU_TO_BE32 (0);
++ vh->total_blocks = PED_CPU_TO_BE32 (nblock);
++ vh->free_blocks = PED_CPU_TO_BE32 (nfree);
++ /* update parted structure */
++ priv_data->plus_geom->length = geom->length;
++ priv_data->plus_geom->end = priv_data->plus_geom->start
++ + geom->length - 1;
++ }
++
++ /* Effective write */
++ write_VH:
++ /* lasts two sectors are allocated by the alternate VH
++ and a reserved sector */
++ block = (priv_data->plus_geom->length - 1) / hfsp_sect_block;
++ priv_data->alloc_map[block / 8] |= 1 << (7 - (block & 7));
++ block = (priv_data->plus_geom->length - 2) / hfsp_sect_block;
++ priv_data->alloc_map[block / 8] |= 1 << (7 - (block & 7));
++ map_sectors = ( PED_BE32_TO_CPU (vh->total_blocks)
++ + PED_SECTOR_SIZE * 8 - 1 ) / (PED_SECTOR_SIZE * 8);
++ allocation_file =
++ hfsplus_file_open ( fs, PED_CPU_TO_BE32 (HFSP_ALLOC_ID),
++ vh->allocation_file.extents,
++ PED_BE64_TO_CPU (
++ vh->allocation_file.logical_size )
++ / PED_SECTOR_SIZE );
++ if (!hfsplus_file_write (allocation_file, priv_data->alloc_map,
++ 0, map_sectors))
++ resize = 0;
++ hfsplus_file_close (allocation_file);
++
++ if (resize) {
++ /* Set the unmounted bit and clear the inconsistent bit */
++ vh->attributes |= PED_CPU_TO_BE32 ( 1 << HFS_UNMOUNTED );
++ vh->attributes &= ~ PED_CPU_TO_BE32 ( 1 << HFSP_INCONSISTENT );
++ }
++
++ ped_timer_set_state_name(timer, _("writing HFS+ Volume Header"));
++ if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1 ))
++ return 0;
++ memcpy (buf, vh, sizeof (HfsPVolumeHeader));
++ if (!ped_geometry_write (priv_data->plus_geom, buf, 2, 1 ))
++ return 0;
++ if (!ped_geometry_write ( priv_data->plus_geom, buf,
++ priv_data->plus_geom->length - 2, 1 ))
++ return 0;
++ ped_timer_update(timer, 1.0);
++
++ return (resize);
++}
++
++/* Update the HFS wrapper mdb and bad blocks file to reflect
++ the new geometry of the embedded HFS+ volume */
++static int
++hfsplus_wrapper_update (PedFileSystem* fs)
++{
++ uint8_t node[PED_SECTOR_SIZE];
++ HfsCPrivateLeafRec ref;
++ HfsExtentKey key;
++ HfsNodeDescriptor* node_desc = (HfsNodeDescriptor*) node;
++ HfsExtentKey* ret_key;
++ HfsExtDescriptor* ret_data;
++ unsigned int i, j;
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++ HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*)
++ priv_data->wrapper->type_specific;
++ unsigned int hfs_sect_block =
++ PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
++ / PED_SECTOR_SIZE ;
++ PedSector hfsplus_sect = (PedSector)
++ PED_BE32_TO_CPU (priv_data->vh->total_blocks)
++ * ( PED_BE32_TO_CPU (priv_data->vh->block_size)
++ / PED_SECTOR_SIZE );
++ unsigned int hfs_blocks_embedded =
++ (hfsplus_sect + hfs_sect_block - 1)
++ / hfs_sect_block;
++ unsigned int hfs_blocks_embedded_old;
++
++ /* update HFS wrapper MDB */
++ hfs_blocks_embedded_old = PED_BE16_TO_CPU (
++ hfs_priv_data->mdb->old_new
++ .embedded.location.block_count );
++ hfs_priv_data->mdb->old_new.embedded.location.block_count =
++ PED_CPU_TO_BE16 (hfs_blocks_embedded);
++ /* maybe macOS will boot with this */
++ hfs_priv_data->mdb->free_blocks =
++ PED_CPU_TO_BE16 ( PED_BE16_TO_CPU (hfs_priv_data->mdb->free_blocks)
++ + hfs_blocks_embedded_old
++ - hfs_blocks_embedded );
++
++ if (!ped_geometry_read (fs->geom, node, 2, 1))
++ return 0;
++ memcpy (node, hfs_priv_data->mdb, sizeof (HfsMasterDirectoryBlock));
++ if (!ped_geometry_write (fs->geom, node, 2, 1))
++ return 0;
++ if (!ped_geometry_write (fs->geom, node, fs->geom->length - 2, 1))
++ return 0;
++
++ /* force reload bad block list */
++ if (hfs_priv_data->bad_blocks_loaded) {
++ hfs_free_bad_blocks_list (hfs_priv_data->bad_blocks_xtent_list);
++ hfs_priv_data->bad_blocks_xtent_list = NULL;
++ hfs_priv_data->bad_blocks_xtent_nb = 0;
++ hfs_priv_data->bad_blocks_loaded = 0;
++ }
++
++ /* clean HFS wrapper allocation map */
++ for (i = PED_BE16_TO_CPU (
++ hfs_priv_data->mdb->old_new.embedded
++ .location.start_block )
++ + hfs_blocks_embedded;
++ i < PED_BE16_TO_CPU (
++ hfs_priv_data->mdb->old_new.embedded
++ .location.start_block )
++ + hfs_blocks_embedded_old;
++ i++ ) {
++ hfs_priv_data->alloc_map[i/8] &= ~(1 << (7 - (i & 7)));
++ }
++ /* and save it */
++ if (!ped_geometry_write (fs->geom, hfs_priv_data->alloc_map,
++ PED_BE16_TO_CPU (
++ hfs_priv_data->mdb->volume_bitmap_block ),
++ ( PED_BE16_TO_CPU (
++ hfs_priv_data->mdb->total_blocks )
++ + PED_SECTOR_SIZE * 8 - 1 )
++ / (PED_SECTOR_SIZE * 8)))
++ return 0;
++
++
++ /* search and update the bad blocks file */
++ key.key_length = sizeof(key) - 1;
++ key.type = HFS_DATA_FORK;
++ key.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID);
++ key.start = 0;
++ if (!hfs_btree_search (hfs_priv_data->extent_file,
++ (HfsPrivateGenericKey*) &key, NULL, 0, &ref))
++ return 0;
++ if (!hfs_file_read_sector (hfs_priv_data->extent_file, node,
++ ref.node_number))
++ return 0;
++ ret_key = (HfsExtentKey*) (node + ref.record_pos);
++ ret_data = (HfsExtDescriptor*) ( node + ref.record_pos
++ + sizeof (HfsExtentKey) );
++
++ while (ret_key->type == key.type && ret_key->file_ID == key.file_ID) {
++ for (i = 0; i < HFS_EXT_NB; i++) {
++ if ( ret_data[i].start_block
++ == hfs_priv_data->mdb->old_new
++ .embedded.location.start_block) {
++ ret_data[i].block_count =
++ hfs_priv_data->mdb->old_new
++ .embedded.location.block_count;
++ /* found ! : update */
++ if (!hfs_file_write_sector (
++ hfs_priv_data->extent_file,
++ node, ref.node_number))
++ return 0;
++ return 1;
++ }
++ }
++
++ if (ref.record_number < PED_BE16_TO_CPU (node_desc->rec_nb)) {
++ ref.record_number++;
++ } else {
++ ref.node_number = PED_BE32_TO_CPU (node_desc->next);
++ if (!ref.node_number
++ || !hfs_file_read_sector(hfs_priv_data->extent_file,
++ node, ref.node_number))
++ return 0;
++ ref.record_number = 1;
++ }
++
++ ref.record_pos = PED_BE16_TO_CPU (*((uint16_t *)
++ (node+(PED_SECTOR_SIZE - 2*ref.record_number))));
++ ret_key = (HfsExtentKey*) (node + ref.record_pos);
++ ret_data = (HfsExtDescriptor*) ( node + ref.record_pos
++ + sizeof (HfsExtentKey) );
++ }
++
++ /* not found : not a valid hfs+ wrapper : failure */
++ return 0;
++}
++
++static int
++hfsplus_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
++{
++ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
++ fs->type_specific;
++ PedTimer* timer_plus;
++ PedGeometry* embedded_geom;
++
++ /* check preconditions */
++ PED_ASSERT (fs->geom->dev == geom->dev, return 0);
++
++ if (fs->geom->start != geom->start)
++ {
++ ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
++ PED_EXCEPTION_CANCEL,
++ _("Sorry, can't move the start of hfs partitions yet!"));
++ return 0;
++ }
++
++ if (geom->length > fs->geom->length
++ || geom->length < hfsplus_get_min_size (fs))
++ return 0;
++
++ if (priv_data->wrapper) {
++ PedSector red, hgee;
++ HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*)
++ priv_data->wrapper->type_specific;
++ unsigned int hfs_sect_block =
++ PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
++ / PED_SECTOR_SIZE;
++
++ /* There is a wrapper so we must calculate the new geometry
++ of the embedded HFS+ volume */
++ red = ( (fs->geom->length - geom->length + hfs_sect_block - 1)
++ / hfs_sect_block ) * hfs_sect_block;
++ /* Can't we shrink the hfs+ volume by the desired size ? */
++ if ( red > priv_data->plus_geom->length
++ - (hgee = hfsplus_get_empty_end (fs))) {
++ /* No, shrink hfs+ by the greatest possible value */
++ hgee = ((hgee + hfs_sect_block - 1) / hfs_sect_block)
++ * hfs_sect_block;
++ red = priv_data->plus_geom->length - hgee;
++ }
++ embedded_geom = ped_geometry_new (geom->dev,
++ priv_data->plus_geom->start,
++ priv_data->plus_geom->length
++ - red);
++
++ /* There is a wrapper so the resize process is a two stages
++ process (embedded resizing then wrapper resizing) :
++ we create a sub timer */
++ ped_timer_reset (timer);
++ ped_timer_set_state_name (timer,
++ _("shrinking embedded HFS+ volume"));
++ ped_timer_update(timer, 0.0);
++ timer_plus = ped_timer_new_nested (timer, 0.98);
++ } else {
++ /* No wrapper : the desired geometry is the desired
++ HFS+ volume geometry */
++ embedded_geom = geom;
++ timer_plus = timer;
++ }
++
++ /* Resize the HFS+ volume */
++ if (!hfsplus_volume_resize (fs, embedded_geom, timer_plus)) {
++ if (timer_plus != timer) ped_timer_destroy_nested (timer_plus);
++ return 0;
++ }
++
++ if (priv_data->wrapper) {
++ ped_geometry_destroy (embedded_geom);
++ ped_timer_destroy_nested (timer_plus);
++ ped_timer_set_state_name(timer, _("shrinking HFS wrapper"));
++ timer_plus = ped_timer_new_nested (timer, 0.02);
++ /* There's a wrapper : second stage = resizing it */
++ if (!hfsplus_wrapper_update (fs)
++ || !hfs_resize (priv_data->wrapper, geom, timer_plus)) {
++ ped_timer_destroy_nested (timer_plus);
++ return 0;
++ }
++ ped_timer_destroy_nested (timer_plus);
++ }
++ ped_timer_update(timer, 1.0);
++
++ return 1;
+ }
+ #endif /* !DISCOVER_ONLY */
+
+@@ -64,9 +2976,44 @@
+ probe: hfs_probe,
+ #ifndef DISCOVER_ONLY
+ clobber: hfs_clobber,
++ open: hfs_open,
++ create: NULL,
++ close: hfs_close,
++ check: NULL,
++ copy: NULL,
++ resize: hfs_resize,
++ get_create_constraint: NULL,
++ get_resize_constraint: hfs_get_resize_constraint,
++ get_copy_constraint: NULL,
+ #else
+ clobber: NULL,
++ open: NULL,
++ create: NULL,
++ close: NULL,
++ check: NULL,
++ copy: NULL,
++ resize: NULL,
++ get_create_constraint: NULL,
++ get_resize_constraint: NULL,
++ get_copy_constraint: NULL,
+ #endif
++};
++
++static PedFileSystemOps hfsplus_ops = {
++ probe: hfsplus_probe,
++#ifndef DISCOVER_ONLY
++ clobber: hfsplus_clobber,
++ open: hfsplus_open,
++ create: NULL,
++ close: hfsplus_close,
++ check: NULL,
++ copy: NULL,
++ resize: hfsplus_resize,
++ get_create_constraint: NULL,
++ get_resize_constraint: hfsplus_get_resize_constraint,
++ get_copy_constraint: NULL,
++#else
++ clobber: NULL,
+ open: NULL,
+ create: NULL,
+ close: NULL,
+@@ -76,23 +3023,32 @@
+ get_create_constraint: NULL,
+ get_resize_constraint: NULL,
+ get_copy_constraint: NULL,
++#endif
+ };
+
++
+ static PedFileSystemType hfs_type = {
+ next: NULL,
+ ops: &hfs_ops,
+ name: "hfs"
+ };
+
++static PedFileSystemType hfsplus_type = {
++ next: NULL,
++ ops: &hfsplus_ops,
++ name: "hfs+"
++};
++
+ void
+ ped_file_system_hfs_init ()
+ {
+ ped_file_system_type_register (&hfs_type);
++ ped_file_system_type_register (&hfsplus_type);
+ }
+
+ void
+ ped_file_system_hfs_done ()
+ {
+ ped_file_system_type_unregister (&hfs_type);
++ ped_file_system_type_unregister (&hfsplus_type);
+ }
+-
+diff -u -r -N parted-1.6.5/libparted/fs_hfs/hfs.h parted-1.6.5-hfs/libparted/fs_hfs/hfs.h
+--- parted-1.6.5/libparted/fs_hfs/hfs.h Thu Jan 1 01:00:00 1970
++++ parted-1.6.5-hfs/libparted/fs_hfs/hfs.h Tue Apr 29 05:48:04 2003
+@@ -0,0 +1,543 @@
++/*
++ libparted - a library for manipulating disk partitions
++ Copyright (C) 2003 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 2 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, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++*/
++
++#ifndef _HFS_H
++#define _HFS_H
++
++
++#undef HFS_DEBUG
++
++#define HFS_SIGNATURE 0x4244
++#define HFSP_SIGNATURE 0x482B
++
++#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 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 HFS_EXT_NB 3
++#define HFSP_EXT_NB 8
++
++static PedFileSystemType hfs_type;
++static PedFileSystemType hfsplus_type;
++
++
++
++/* ----------------------------------- */
++/* -- 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 {
++ int8_t key_length; /* length of the key without key_length */
++ int8_t reserved;
++ uint32_t parent_ID;
++ int8_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 {
++ int8_t key_length; /* length of the key without key_length */
++ int8_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 -- */
++/* ------------------------------------ */
++
++/* Permission struct is reserved in HFS+ official specification */
++/* May be it could be used in unix implementations of HFS+ */
++struct __attribute__ ((packed)) _HfsPPerms {
++ uint32_t owner_ID; /* reserved */
++ uint32_t group_ID; /* reserved */
++ uint32_t permissions; /* reserved */
++ uint32_t special_devices; /* reserved */
++};
++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 reserved;
++
++ 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 reserved2;
++ 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;
++
++
++
++/* ---------------------------------------- */
++/* -- 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;
++ char bad_blocks_loaded;
++ unsigned int bad_blocks_xtent_nb;
++ HfsPrivateLinkExtent* bad_blocks_xtent_list;
++};
++typedef struct _HfsPrivateFSData HfsPrivateFSData;
++
++/* Generic btree key */
++struct __attribute__ ((packed)) _HfsPrivateGenericKey {
++ int8_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;
++
++/* To store bad block list */
++struct _HfsPPrivateLinkExtent {
++ HfsPExtDescriptor extent;
++ struct _HfsPPrivateLinkExtent* next;
++};
++typedef struct _HfsPPrivateLinkExtent HfsPPrivateLinkExtent;
++
++/* HFS+ filesystem specific data */
++struct _HfsPPrivateFSData {
++ PedFileSystem* wrapper; /* NULL if hfs+ is not embedded */
++ PedGeometry* plus_geom; /* Geometry of HFS+ _volume_ */
++ char free_geom; /* 1 = plus_geom must be freed */
++ uint8_t* alloc_map;
++ HfsPVolumeHeader* vh;
++ HfsPPrivateFile* extents_file;
++ HfsPPrivateFile* catalog_file;
++ HfsPPrivateFile* attributes_file;
++ char bad_blocks_loaded;
++ unsigned int bad_blocks_xtent_nb;
++ HfsPPrivateLinkExtent* bad_blocks_xtent_list;
++};
++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;
++
++
++
++#endif /* _HFS_H */
diff --git a/sys-apps/parted/parted-1.6.5-r1.ebuild b/sys-apps/parted/parted-1.6.5-r1.ebuild
new file mode 100644
index 000000000000..02d1270d6447
--- /dev/null
+++ b/sys-apps/parted/parted-1.6.5-r1.ebuild
@@ -0,0 +1,47 @@
+# Copyright 1999-2003 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/sys-apps/parted/parted-1.6.5-r1.ebuild,v 1.1 2003/05/29 16:37:23 pvdabeel Exp $
+
+IUSE="nls static readline"
+
+S=${WORKDIR}/${P}
+DESCRIPTION="Create, destroy, resize, check, copy partitions and file systems"
+HOMEPAGE="http://www.gnu.org/software/parted"
+SRC_URI="ftp://ftp.gnu.org/gnu/${PN}/${P}.tar.gz"
+
+SLOT="0"
+LICENSE="GPL-2"
+KEYWORDS="~ppc"
+
+inherit eutils
+
+DEPEND=">=sys-apps/e2fsprogs-1.27
+ >=sys-libs/ncurses-5.2
+ nls? ( sys-devel/gettext )
+ readline? ( >=sys-libs/readline-4.1-r4 )"
+
+RDEPEND="${DEPEND}
+ =dev-libs/progsreiserfs-0.3.0*"
+
+src_unpack() {
+ unpack ${A}
+ epatch ${FILESDIR}/parted-1.6.5-hfs-8.patch
+}
+
+src_compile() {
+ local myconf
+ use nls || myconf="${myconf} --disable-nls"
+ use readline || myconf="${myconf} --without-readline"
+ [ -z "${DEBUGBUILD}" ] && myconf="${myconf} --disable-debug"
+ use static && myconf="${myconf} --enable-all-static"
+ econf --target=${CHOST} ${myconf} || die "Configure failed"
+ emake || die "Make failed"
+}
+
+src_install() {
+ einstall || die "Install failed"
+ dodoc ABOUT-NLS AUTHORS BUGS COPYING ChangeLog \
+ INSTALL NEWS README THANKS TODO
+ docinto doc; cd doc
+ dodoc API COPYING.DOC FAQ FAT USER USER.jp
+}