summaryrefslogtreecommitdiffstats
path: root/libparted/fs/hfs
diff options
context:
space:
mode:
Diffstat (limited to 'libparted/fs/hfs')
-rw-r--r--libparted/fs/hfs/DOC92
-rw-r--r--libparted/fs/hfs/HISTORY115
-rw-r--r--libparted/fs/hfs/TODO27
-rw-r--r--libparted/fs/hfs/hfs.c92
-rw-r--r--libparted/fs/hfs/hfs.h648
-rw-r--r--libparted/fs/hfs/probe.c238
-rw-r--r--libparted/fs/hfs/probe.h44
7 files changed, 1256 insertions, 0 deletions
diff --git a/libparted/fs/hfs/DOC b/libparted/fs/hfs/DOC
new file mode 100644
index 0000000..9ee8b4d
--- /dev/null
+++ b/libparted/fs/hfs/DOC
@@ -0,0 +1,92 @@
+WARNING : Both HFS and HFS+ implementations of Linux 2.4 are buggy, at
+least when used before or after this implementation. Some workarounds
+are used in this implementation, but there can still be incompatibilities.
+Try Linux 2.6 if you want to play with HFS(+) resizing (though some bugs
+might also be there in 2.6, there is of course no warranty)
+
+---
+
+ 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/documentation/mac/Files/Files-99.html
+ * For HFS+, "Technical Note TN1150", "HFS Plus Volume Format"
+ http://developer.apple.com/technotes/tn/tn1150.html
+
+ Some useful HFS precisions concerning alignement, bit ordering, and
+ order of fields for extent key comparaisons are only in the HFS+ TN
+
+ These Apple Creator Codes are reserved for us :
+ Shnk traP GP16 GnuP PH+x Xpnd Resz GP17 GP18 GP19 GP20
+
+---
+
+* Cache design *
+
+Versions before HFS Patch 15 were very slow when data relocation was needed,
+because every extent to relocate involved scanning the whole file system,
+looking for a reference to its physical position on the volume (this was a
+dummy algorithm, I know :)
+
+HFS Patch 16 introduced a cache that allows to efficiently retrieve the place
+of the reference in the file system given the physical position of an extent.
+The cache is designed for : - efficiency
+ - scaling
+ - simplicity
+ - avoiding memory allocation while resizing
+
+This cache involves quite big worst case memory consumption, but without it
+the time needed to complete the operation in the worst case would be huge
+anyway (maybe several years...) so this isn't really an issue. The cache size
+is nearly proportional to the number of files you have, or if you have very few
+files, to the size of your volume, so worst cases situations occure when you
+fill a drive with millions of < 4 ko files :p For this very special usage you
+will just need a very special amount of RAM (on typical systems about
+(FS size) / 256 )... On a more "normal" volume it's about
+(# of files) * 20 bytes. With very few files it's about (FS Size) / 1024 / 256.
+
+At the beginning of the resize process, the cache is filed by scanning the FS.
+The position of each extent is cut into 2 parts : high order is used as
+an index into a table of pointer to a linked list which contains :
+- the next ptr (sizeof struct *)
+- the extent start (4 bytes)
+- the extent size (4 bytes)
+- number of BTree block or 0 if in prim (4 bytes)
+- offset of the extent start reference
+ from the block beginning (2 bytes)
+- sectors by BTree block, or
+ 1 for VH/MDB (1 byte)
+- FS special file / primary structure
+ where the extent reference is stored (1 byte)
+ (3 bits for the extent index, 5 for
+ the actual ref)
+
+ 0 : dont exists --- reserved
+ 1 : mdb / vh : catalog ---
+ 2 : mdb / vh : extent ---
+ 3 : vh : attributes X+-
+ 4 : vh : allocation X+-
+ 5 : vh : startup X+-
+ 6 : catalog ---
+ 7 : attributes X+-
+ 8 : extent (nothing to update) ---
+ 9 : extent (update catalog) ---
+ 10 : extent (update extent !?!) --- should not exist
+ 11 : extent (update attributes) X+-
+ 12 : extent (update allocation) X+-
+ 13 : extent (update startup) X+- reserved
+ 14 : vh : journal info block X+J
+ 15 : jib: journal X+J
+ 16 - 31 : ---
+
+mdb : Master Directory Block
+vh : Volume Header
+X+ : HFSX or HFS+ only
+J : Journaled only
+
+Large amount of memory is allocated at once (first enough memory to fit
+every files if there isn't any fragmentation +6.25%, then this value / 4,
+if this wasn't enough). On a typical FS, the first allocation should be enough.
+
+---
diff --git a/libparted/fs/hfs/HISTORY b/libparted/fs/hfs/HISTORY
new file mode 100644
index 0000000..5e138a6
--- /dev/null
+++ b/libparted/fs/hfs/HISTORY
@@ -0,0 +1,115 @@
+## 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 2To+ 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
+---------------------- PATCH FOR PARTED 1.6.6 ----------------------------
+ 9 Don't destroy the file being worked on in case of
+ interruption of Parted 28-10-2003
+---------------------- PATCH FOR PARTED 1.6.10 ---------------------------
+10 Regression tests, URL correction, In effect_move_extent :
+ corrected memory leak & corrected a bug in precondition checks
+ Added error messages, Check ped_alloc results
+ Use macro for test / set / clear in the allocation bitmap
+ Light probe correction, Check return value of get_empty_end
+ Moved dynamic memory allocation out of effect_move_extent
+ Check HFS+ version, Set implementation creator code
+ Check journal absence, Corrected a bug in HFS+ block number
+ calculation 24-04-2004
+--------------------- PATCH FOR PARTED 1.6.11 ----------------------------
+11-Some pointer dereference moved after non nul assertion
+ -Error messages for HFS(+) file IO
+ -Memory leak correction in hfs(plus)_read_bad_blocks
+ -Mark out of volume blocks as used
+ (improve compatibility with broken HFS+ Linux
+ implementation)
+ WARNING : this fix is not 100% tn1150 compatible :
+ "The allocation file may be larger than the minimum
+ number of bits required for the given volume size.
+ Any unused bits in the bitmap must be set to _zero_."
+ Anyway neither is the Linux implementation, nor was my
+ previous implementations
+ Maybe I should ask Apple to change the specifications
+ -HISTORY, DOC and TODO files 29-04-2004
+12 Corrected a bug in hfsplus_volume_resize : size of alloc
+ bitmap could be miscalculated 29-04-2004
+--------------------- PATCH FOR PARTED 1.6.12 ----------------------------
+13-Finally partial rewrite of *_search_move_*
+ Easier to maintain and prepare for extent search and
+ relocation algorithm changes for better ones.
+ -"An extent has not been relocated!" message now only when
+ relocation requested
+ -Slightly better and simpler relocation algorithm
+ -Update of Makefile.in and Makefile.am in fs_hfs
+ -Sign correction for some 8bits HFS integers
+ -Added the option --enable-hfs-extract-fs in 'configure'
+ -Added every ped_geometry_sync where needed
+ -Bugfix : "A root node does not need to exist
+ (if the tree is empty)."
+ - now handled correctly in btree_search
+ -Bugfix : failure wasn't detected in some cases
+ during 2 pass relocation (*_search_move_*)
+ -Bugfix : The extent key comparaison was done in a wrong order
+ and a pad field was used during the comparaison
+ -Bugfix : in hfs_file_find_sector and hfsplus_file_find_sector
+ the absolute position of a file sector could be
+ miscalculated in case of fragmentation, resulting
+ in potential data corruption, or various errors
+ -Bugfix : The end of the HFS bitmap compatibility block was
+ miscalculated ( (1<<16)/8 instead of (1<<16) )
+ in hfs_resize
+ 07-09-2004
+--------------------- PATCH FOR PARTED 1.6.14 ----------------------------
+14 Port of Patch 13 for Parted 1.6.14 (update timestamps)
+ 08-09-2004
+--------------------- PATCH FOR PARTED 1.6.15 ----------------------------
+15-hfsplus_open : added a warning message if the "attributes"
+ special file exists
+ -hfsplus_open : added a test to check if the "allocation"
+ special file has been correctly opened
+ -optimisation of hfs+ block access : don't recalculate
+ the address of each sector, and avoid checking the cache if
+ obviously not useful
+ ( hfsplus_file_read && hfsplus_file_write
+ && hfsplus_file_find_extent && hfs_file_find_sector)
+ -cut the "hfs.c" file in several parts
+ -Bugfix: in hfsplus_do_move_primary, hfs_effect_move_extent
+ was called instead of hfsplus_effect_move_extent !!!
+ This could not produce data corruption, because of a welcome
+ ASSERT in *_effect_move_extent that would detect the bug :)
+ -Bugfix: in hfs_effect_move_extent, do
+ PED_ASSERT(*ptr_to_fblock <= *ptr_fblock, return -1);
+ instead of
+ PED_ASSERT(*ptr_to_fblock < *ptr_fblock, return -1);
+ and added that assertion to hfsplus_effect_move_extent
+ -Bugfix: bugs introduced in rewrite of hfsplus_file_read
+ && hfsplus_file_write : last sector was incorrectly detected
+ as out of file.
+ -Cache the extent references (speed improvement ?)
+ 23-09-2004
+16-Bugfix: in hfsplus_do_move (reloc_plus.c), case CR_BTREE_EXT_ATTR
+ incorrectly updated the cached part of priv_data->catalog_file
+ instead of priv_data->attributes_file
+ -Bugfix: in hfs_read_bad_blocks && hfsplus_read_bad_blocks,
+ now generate an error if file_ID or type mismatch after the
+ first pass
+ Also check return value of ped_malloc
+ -Bugfix: in hfsplus_btree_search, check return value of ped_malloc
+ 29-09-2004
+---------------- INTEGRATION IN PARTED 1.6.22 (cvs) ----------------------
+Futur changes will be described in ../../ChangeLog
+ 02-02-2005
diff --git a/libparted/fs/hfs/TODO b/libparted/fs/hfs/TODO
new file mode 100644
index 0000000..6e408e3
--- /dev/null
+++ b/libparted/fs/hfs/TODO
@@ -0,0 +1,27 @@
+--- TODO ---
+
+ * Continue to write regressions tests and try on 2.6 kernel -- (high)
+ * Fix timer progression calculation, according to the new
+ caching code -- (high)
+ * write doc, website, ... -- (high)
+ * Check block allocation in linux 2.4 and remove
+ compatibility code if possible -- (high)
+
+ * In hfs(plus)_btree_search , use a static variable to detect
+ illegal recursion and abort in that case. (find the right
+ number of recursion before reporting bug) -- easy -- (medium)
+ * Finish the HFS Extractor -- (medium)
+ (add mdb & vh extraction, and maybe journal)
+
+ * Write code to allow enlarging and moving HFS[+x] -- (low)
+ * Use a bitmap to internaly store the bad blocks -- (low)
+ * Less bitmap saves ? -- (low)
+ * Continue to change the relocation algorithm
+ for a better one :) -- (low)
+
+--- NOT todo ---
+
+ * debug HFS(+) Linux implementation (block allocation for HFS+,
+ hard and sym links for HFS+, filename length for HFS, ...) -- (dont)
+ /// Linux 2.6 contains HFS(+) implementations with less bugs
+ /// Linux 2.4 should not be used anymore to access HFS(+)
diff --git a/libparted/fs/hfs/hfs.c b/libparted/fs/hfs/hfs.c
new file mode 100644
index 0000000..3684646
--- /dev/null
+++ b/libparted/fs/hfs/hfs.c
@@ -0,0 +1,92 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000, 2003-2005, 2007, 2009-2014, 2019-2023 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ Author : Guillaume Knispel <k_guillaume@libertysurf.fr>
+ Report bug to <bug-parted@gnu.org>
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+#include "probe.h"
+
+uint8_t* hfs_block = NULL;
+uint8_t* hfsp_block = NULL;
+unsigned hfs_block_count;
+unsigned hfsp_block_count;
+
+static PedFileSystemOps hfs_ops = {
+ probe: hfs_probe,
+};
+
+static PedFileSystemOps hfsplus_ops = {
+ probe: hfsplus_probe,
+};
+
+static PedFileSystemOps hfsx_ops = {
+ probe: hfsx_probe,
+};
+
+
+static PedFileSystemType hfs_type = {
+ next: NULL,
+ ops: &hfs_ops,
+ name: "hfs",
+};
+
+static PedFileSystemType hfsplus_type = {
+ next: NULL,
+ ops: &hfsplus_ops,
+ name: "hfs+",
+};
+
+static PedFileSystemType hfsx_type = {
+ next: NULL,
+ ops: &hfsx_ops,
+ name: "hfsx",
+};
+
+void
+ped_file_system_hfs_init ()
+{
+ ped_file_system_type_register (&hfs_type);
+ ped_file_system_type_register (&hfsplus_type);
+ ped_file_system_type_register (&hfsx_type);
+}
+
+void
+ped_file_system_hfs_done ()
+{
+ ped_file_system_type_unregister (&hfs_type);
+ ped_file_system_type_unregister (&hfsplus_type);
+ ped_file_system_type_unregister (&hfsx_type);
+}
diff --git a/libparted/fs/hfs/hfs.h b/libparted/fs/hfs/hfs.h
new file mode 100644
index 0000000..5b9138c
--- /dev/null
+++ b/libparted/fs/hfs/hfs.h
@@ -0,0 +1,648 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2003-2005, 2007, 2009-2014, 2019-2023 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _HFS_H
+#define _HFS_H
+
+/* WARNING : bn is used 2 times in theses macro */
+/* so _never_ use side effect operators when using them */
+#define TST_BLOC_OCCUPATION(tab,bn) \
+ (((tab)[(bn)/8]) & (1<<(7-((bn)&7))))
+#define SET_BLOC_OCCUPATION(tab,bn) \
+ (((tab)[(bn)/8]) |= (1<<(7-((bn)&7))))
+#define CLR_BLOC_OCCUPATION(tab,bn) \
+ (((tab)[(bn)/8]) &= ~(1<<(7-((bn)&7))))
+
+/* Maximum number of blocks for the copy buffers */
+#define BLOCK_MAX_BUFF 256
+/* Maximum size of the copy buffers, in bytes */
+#define BYTES_MAX_BUFF 8388608
+
+/* Apple Creator Codes follow */
+#define HFSP_IMPL_Shnk 0x53686e6b /* in use */
+#define HFSP_IMPL_Xpnd 0x58706e64 /* reserved */
+#define HFSP_IMPL_Resz 0x5265737a /* reserved */
+#define HFSP_IMPL_PHpx 0x50482b78 /* reserved */
+#define HFSP_IMPL_traP 0x74726150 /* reserved */
+#define HFSP_IMPL_GnuP 0x476e7550 /* reserved */
+
+#define HFS_SIGNATURE 0x4244 /* 'BD' */
+#define HFSP_SIGNATURE 0x482B /* 'H+' */
+#define HFSX_SIGNATURE 0x4858 /* 'HX' */
+
+#define HFSP_VERSION 4
+#define HFSX_VERSION 5
+
+#define HFS_HARD_LOCK 7
+#define HFS_UNMOUNTED 8
+#define HFS_BAD_SPARED 9
+#define HFS_SOFT_LOCK 15
+#define HFSP_NO_CACHE 10
+#define HFSP_INCONSISTENT 11
+#define HFSP_REUSE_CNID 12
+#define HFSP_JOURNALED 13
+
+#define HFS_IDX_NODE 0x00
+#define HFS_HDR_NODE 0x01
+#define HFS_MAP_NODE 0x02
+#define HFS_LEAF_NODE 0xFF
+
+#define HFS_FIRST_REC 0x0E
+#define HFS_NSD_HD_REC 0x78
+#define HFS_MAP_REC 0xF8
+
+#define HFS_DATA_FORK 0x00
+#define HFS_RES_FORK 0xFF
+
+#define HFS_CAT_DIR 0x01
+#define HFS_CAT_FILE 0x02
+#define HFS_CAT_DIR_TH 0x03
+#define HFS_CAT_FILE_TH 0x04
+
+#define HFSP_ATTR_INLINE 0x10
+#define HFSP_ATTR_FORK 0x20
+#define HFSP_ATTR_EXTENTS 0x30
+
+#define HFS_ROOT_PAR_ID 0x01
+#define HFS_ROOT_DIR_ID 0x02
+#define HFS_XTENT_ID 0x03
+#define HFS_CATALOG_ID 0x04
+#define HFS_BAD_BLOCK_ID 0x05
+#define HFSP_ALLOC_ID 0x06
+#define HFSP_STARTUP_ID 0x07
+#define HFSP_ATTRIB_ID 0x08
+#define HFSP_BOGUS_ID 0x0F
+#define HFSP_FIRST_AV_ID 0x10
+
+#define HFSJ_JOURN_IN_FS 0x00
+#define HFSJ_JOURN_OTHER_DEV 0x01
+#define HFSJ_JOURN_NEED_INIT 0x02
+
+#define HFSJ_HEADER_MAGIC 0x4a4e4c78
+#define HFSJ_ENDIAN_MAGIC 0x12345678
+
+#define HFSX_CASE_FOLDING 0xCF /* case insensitive HFSX */
+#define HFSX_BINARY_COMPARE 0xBC /* case sensitive HFSX */
+
+#define HFS_EXT_NB 3
+#define HFSP_EXT_NB 8
+
+/* Define the filenames used by the FS extractor */
+#ifdef HFS_EXTRACT_FS
+
+#define HFS_MDB_FILENAME "mdb.hfs"
+#define HFS_CATALOG_FILENAME "catalog.hfs"
+#define HFS_EXTENTS_FILENAME "extents.hfs"
+#define HFS_BITMAP_FILENAME "bitmap.hfs"
+
+#define HFSP_VH_FILENAME "vh.hfsplus"
+#define HFSP_CATALOG_FILENAME "catalog.hfsplus"
+#define HFSP_EXTENTS_FILENAME "extents.hfsplus"
+#define HFSP_BITMAP_FILENAME "bitmap.hfsplus"
+#define HFSP_ATTRIB_FILENAME "attributes.hfsplus"
+#define HFSP_STARTUP_FILENAME "startup.hfsplus"
+
+#endif /* HFS_EXTRACT_FS */
+
+
+
+/* ----------------------------------- */
+/* -- HFS DATA STRUCTURES -- */
+/* ----------------------------------- */
+
+/* Extent descriptor */
+struct __attribute__ ((packed)) _HfsExtDescriptor {
+ uint16_t start_block;
+ uint16_t block_count;
+};
+typedef struct _HfsExtDescriptor HfsExtDescriptor;
+typedef HfsExtDescriptor HfsExtDataRec[HFS_EXT_NB];
+
+/* Volume header */
+struct __attribute__ ((packed)) _HfsMasterDirectoryBlock {
+ uint16_t signature;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint16_t volume_attributes;
+ uint16_t files_in_root;
+ uint16_t volume_bitmap_block; /* in sectors */
+ uint16_t next_allocation;
+ uint16_t total_blocks;
+ uint32_t block_size; /* in bytes */
+ uint32_t def_clump_size; /* in bytes */
+ uint16_t start_block; /* in sectors */
+ uint32_t next_free_node;
+ uint16_t free_blocks;
+ uint8_t name_length;
+ char name[27];
+ uint32_t backup_date;
+ uint16_t backup_number;
+ uint32_t write_count;
+ uint32_t extents_clump;
+ uint32_t catalog_clump;
+ uint16_t dirs_in_root;
+ uint32_t file_count;
+ uint32_t dir_count;
+ uint32_t finder_info[8];
+ union __attribute__ ((packed)) {
+ struct __attribute__ ((packed)) {
+ uint16_t volume_cache_size; /* in blocks */
+ uint16_t bitmap_cache_size; /* in blocks */
+ uint16_t common_cache_size; /* in blocks */
+ } legacy;
+ struct __attribute__ ((packed)) {
+ uint16_t signature;
+ HfsExtDescriptor location;
+ } embedded;
+ } old_new;
+ uint32_t extents_file_size; /* in bytes, block size multiple */
+ HfsExtDataRec extents_file_rec;
+ uint32_t catalog_file_size; /* in bytes, block size multiple */
+ HfsExtDataRec catalog_file_rec;
+};
+typedef struct _HfsMasterDirectoryBlock HfsMasterDirectoryBlock;
+
+/* B*-Tree Node Descriptor */
+struct __attribute__ ((packed)) _HfsNodeDescriptor {
+ uint32_t next;
+ uint32_t previous;
+ int8_t type;
+ uint8_t height;
+ uint16_t rec_nb;
+ uint16_t reserved;
+};
+typedef struct _HfsNodeDescriptor HfsNodeDescriptor;
+
+/* Header record of a whole B*-Tree */
+struct __attribute__ ((packed)) _HfsHeaderRecord {
+ uint16_t depth;
+ uint32_t root_node;
+ uint32_t leaf_records;
+ uint32_t first_leaf_node;
+ uint32_t last_leaf_node;
+ uint16_t node_size;
+ uint16_t max_key_len;
+ uint32_t total_nodes;
+ uint32_t free_nodes;
+ int8_t reserved[76];
+};
+typedef struct _HfsHeaderRecord HfsHeaderRecord;
+
+/* Catalog key for B*-Tree lookup in the catalog file */
+struct __attribute__ ((packed)) _HfsCatalogKey {
+ uint8_t key_length; /* length of the key without key_length */
+ uint8_t reserved;
+ uint32_t parent_ID;
+ uint8_t name_length;
+ char name[31]; /* in fact physicaly 1 upto 31 */
+};
+typedef struct _HfsCatalogKey HfsCatalogKey;
+
+/* Extents overflow key for B*-Tree lookup */
+struct __attribute__ ((packed)) _HfsExtentKey {
+ uint8_t key_length; /* length of the key without key_length */
+ uint8_t type; /* data or ressource fork */
+ uint32_t file_ID;
+ uint16_t start;
+};
+typedef struct _HfsExtentKey HfsExtentKey;
+
+/* Catalog subdata case directory */
+struct __attribute__ ((packed)) _HfsDir {
+ uint16_t flags;
+ uint16_t valence; /* number of files in this directory */
+ uint32_t dir_ID;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ int8_t DInfo[16]; /* used by Finder, handle as reserved */
+ int8_t DXInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t reserved[4];
+};
+typedef struct _HfsDir HfsDir;
+
+/* Catalog subdata case file */
+struct __attribute__ ((packed)) _HfsFile {
+ int8_t flags;
+ int8_t type; /* should be 0 */
+ int8_t FInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t file_ID;
+ uint16_t data_start_block;
+ uint32_t data_sz_byte;
+ uint32_t data_sz_block;
+ uint16_t res_start_block;
+ uint32_t res_sz_byte;
+ uint32_t res_sz_block;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ int8_t FXInfo[16]; /* used by Finder, handle as reserved */
+ uint16_t clump_size;
+ HfsExtDataRec extents_data;
+ HfsExtDataRec extents_res;
+ uint32_t reserved;
+};
+typedef struct _HfsFile HfsFile;
+
+/* Catalog subdata case directory thread */
+struct __attribute__ ((packed)) _HfsDirTh {
+ uint32_t reserved[2];
+ uint32_t parent_ID;
+ int8_t name_length;
+ char name[31];
+};
+typedef struct _HfsDirTh HfsDirTh;
+
+/* Catalog subdata case file thread */
+typedef struct _HfsDirTh HfsFileTh; /* same as directory thread */
+
+/* Catalog data */
+struct __attribute__ ((packed)) _HfsCatalog {
+ int8_t type;
+ int8_t reserved;
+ union {
+ HfsDir dir;
+ HfsFile file;
+ HfsDirTh dir_th;
+ HfsFileTh file_th;
+ } sel;
+};
+typedef struct _HfsCatalog HfsCatalog;
+
+
+
+/* ------------------------------------ */
+/* -- HFS+ DATA STRUCTURES -- */
+/* ------------------------------------ */
+
+/* documented since 2004 in tn1150 */
+struct __attribute__ ((packed)) _HfsPPerms {
+ uint32_t owner_ID;
+ uint32_t group_ID;
+ uint32_t permissions;
+ uint32_t special_devices;
+};
+typedef struct _HfsPPerms HfsPPerms;
+
+/* HFS+ extent descriptor*/
+struct __attribute__ ((packed)) _HfsPExtDescriptor {
+ uint32_t start_block;
+ uint32_t block_count;
+};
+typedef struct _HfsPExtDescriptor HfsPExtDescriptor;
+typedef HfsPExtDescriptor HfsPExtDataRec[HFSP_EXT_NB];
+
+/* HFS+ fork data structure */
+struct __attribute__ ((packed)) _HfsPForkData {
+ uint64_t logical_size;
+ uint32_t clump_size;
+ uint32_t total_blocks;
+ HfsPExtDataRec extents;
+};
+typedef struct _HfsPForkData HfsPForkData;
+
+/* HFS+ catalog node ID */
+typedef uint32_t HfsPNodeID;
+
+/* HFS+ file names */
+typedef uint16_t unichar;
+struct __attribute__ ((packed)) _HfsPUniStr255 {
+ uint16_t length;
+ unichar unicode[255]; /* 1 upto 255 */
+};
+typedef struct _HfsPUniStr255 HfsPUniStr255;
+
+/* HFS+ volume header */
+struct __attribute__ ((packed)) _HfsPVolumeHeader {
+ uint16_t signature;
+ uint16_t version;
+ uint32_t attributes;
+ uint32_t last_mounted_version;
+ uint32_t journal_info_block;
+
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ uint32_t checked_date;
+
+ uint32_t file_count;
+ uint32_t dir_count;
+
+ uint32_t block_size;
+ uint32_t total_blocks;
+ uint32_t free_blocks;
+
+ uint32_t next_allocation;
+ uint32_t res_clump_size;
+ uint32_t data_clump_size;
+ HfsPNodeID next_catalog_ID;
+
+ uint32_t write_count;
+ uint64_t encodings_bitmap;
+
+ uint8_t finder_info[32];
+
+ HfsPForkData allocation_file;
+ HfsPForkData extents_file;
+ HfsPForkData catalog_file;
+ HfsPForkData attributes_file;
+ HfsPForkData startup_file;
+};
+typedef struct _HfsPVolumeHeader HfsPVolumeHeader;
+
+/* HFS+ B-Tree Node Descriptor. Same as HFS btree. */
+struct __attribute__ ((packed)) _HfsPNodeDescriptor {
+ uint32_t next;
+ uint32_t previous;
+ int8_t type;
+ uint8_t height;
+ uint16_t rec_nb;
+ uint16_t reserved;
+};
+typedef struct _HfsPNodeDescriptor HfsPNodeDescriptor;
+
+/* Header record of a whole HFS+ B-Tree. */
+struct __attribute__ ((packed)) _HfsPHeaderRecord {
+ uint16_t depth;
+ uint32_t root_node;
+ uint32_t leaf_records;
+ uint32_t first_leaf_node;
+ uint32_t last_leaf_node;
+ uint16_t node_size;
+ uint16_t max_key_len;
+ uint32_t total_nodes;
+ uint32_t free_nodes; /* same as hfs btree until here */
+ uint16_t reserved1;
+
+ uint32_t clump_size;
+ uint8_t btree_type; /* must be 0 for HFS+ B-Tree */
+ uint8_t key_compare_type; /* hfsx => 0xCF = case folding */
+ /* 0xBC = binary compare */
+ /* otherwise, reserved */
+ uint32_t attributes;
+ uint32_t reserved3[16];
+};
+typedef struct _HfsPHeaderRecord HfsPHeaderRecord;
+
+/* Catalog key for B-Tree lookup in the HFS+ catalog file */
+struct __attribute__ ((packed)) _HfsPCatalogKey {
+ uint16_t key_length;
+ HfsPNodeID parent_ID;
+ HfsPUniStr255 node_name;
+};
+typedef struct _HfsPCatalogKey HfsPCatalogKey;
+
+/* HFS+ catalog subdata case dir */
+struct __attribute__ ((packed)) _HfsPDir {
+ uint16_t flags;
+ uint32_t valence;
+ HfsPNodeID dir_ID;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t attrib_mod_date;
+ uint32_t access_date;
+ uint32_t backup_date;
+ HfsPPerms permissions;
+ int8_t DInfo[16]; /* used by Finder, handle as reserved */
+ int8_t DXInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t text_encoding;
+ uint32_t reserved;
+};
+typedef struct _HfsPDir HfsPDir;
+
+/* HFS+ catalog subdata case file */
+struct __attribute__ ((packed)) _HfsPFile {
+ uint16_t flags;
+ uint32_t reserved1;
+ HfsPNodeID file_ID;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t attrib_mod_date;
+ uint32_t access_date;
+ uint32_t backup_date;
+ HfsPPerms permissions;
+ int8_t FInfo[16]; /* used by Finder, handle as reserved */
+ int8_t FXInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t text_encoding;
+ uint32_t reserved2;
+
+ HfsPForkData data_fork;
+ HfsPForkData res_fork;
+};
+typedef struct _HfsPFile HfsPFile;
+
+/* HFS+ catalog subdata case thread */
+struct __attribute__ ((packed)) _HfsPThread {
+ int16_t reserved;
+ HfsPNodeID parent_ID;
+ HfsPUniStr255 node_name;
+};
+typedef struct _HfsPThread HfsPDirTh;
+typedef struct _HfsPThread HfsPFileTh;
+
+/* HFS+ Catalog leaf data */
+struct __attribute__ ((packed)) _HfsPCatalog {
+ int16_t type;
+ union {
+ HfsPDir dir;
+ HfsPFile file;
+ HfsPDirTh dir_th;
+ HfsPFileTh file_th;
+ } sel;
+};
+typedef struct _HfsPCatalog HfsPCatalog;
+
+/* HFS+ extents file key */
+struct __attribute__ ((packed)) _HfsPExtentKey {
+ uint16_t key_length;
+ uint8_t type;
+ uint8_t pad;
+ HfsPNodeID file_ID;
+ uint32_t start;
+};
+typedef struct _HfsPExtentKey HfsPExtentKey;
+
+/* extent file data is HfsPExtDataRec */
+
+/* Fork data attribute file */
+struct __attribute__ ((packed)) _HfsPForkDataAttr {
+ uint32_t record_type;
+ uint32_t reserved;
+ union __attribute__ ((packed)) {
+ HfsPForkData fork;
+ HfsPExtDataRec extents;
+ } fork_res;
+};
+typedef struct _HfsPForkDataAttr HfsPForkDataAttr;
+
+
+/* ----------- Journal data structures ----------- */
+
+/* Info block : stored in a block # defined in the VH */
+struct __attribute__ ((packed)) _HfsJJournalInfoBlock {
+ uint32_t flags;
+ uint32_t device_signature[8];
+ uint64_t offset;
+ uint64_t size;
+ uint32_t reserved[32];
+};
+typedef struct _HfsJJournalInfoBlock HfsJJournalInfoBlock;
+
+struct __attribute__ ((packed)) _HfsJJournalHeader {
+ uint32_t magic;
+ uint32_t endian;
+ uint64_t start;
+ uint64_t end;
+ uint64_t size;
+ uint32_t blhdr_size;
+ uint32_t checksum;
+ uint32_t jhdr_size;
+};
+typedef struct _HfsJJournalHeader HfsJJournalHeader;
+
+struct __attribute__ ((packed)) _HfsJBlockInfo {
+ uint64_t bnum; /* sector number */
+ uint32_t bsize; /* size in bytes */
+ uint32_t next;
+};
+typedef struct _HfsJBlockInfo HfsJBlockInfo;
+
+struct __attribute__ ((packed)) _HfsJBlockListHeader {
+ uint16_t max_blocks; /* reserved */
+ uint16_t num_blocks;
+ uint32_t bytes_used;
+ uint32_t checksum;
+ uint32_t pad;
+ HfsJBlockInfo binfo[];
+};
+typedef struct _HfsJBlockListHeader HfsJBlockListHeader;
+
+
+
+/* ---------------------------------------- */
+/* -- INTERNAL DATA STRUCTURES -- */
+/* ---------------------------------------- */
+
+/* Data of an opened HFS file */
+struct _HfsPrivateFile {
+ PedSector sect_nb;
+ PedFileSystem* fs;
+ uint32_t CNID; /* disk order (BE) */
+ HfsExtDataRec first; /* disk order (BE) */
+ HfsExtDataRec cache; /* disk order (BE) */
+ uint16_t start_cache; /* CPU order */
+};
+typedef struct _HfsPrivateFile HfsPrivateFile;
+
+/* To store bad block list */
+struct _HfsPrivateLinkExtent {
+ HfsExtDescriptor extent;
+ struct _HfsPrivateLinkExtent* next;
+};
+typedef struct _HfsPrivateLinkExtent HfsPrivateLinkExtent;
+
+/* HFS Filesystem specific data */
+struct _HfsPrivateFSData {
+ uint8_t alloc_map[(1<<16) / 8];
+ HfsMasterDirectoryBlock* mdb;
+ HfsPrivateFile* extent_file;
+ HfsPrivateFile* catalog_file;
+ HfsPrivateLinkExtent* bad_blocks_xtent_list;
+ unsigned int bad_blocks_xtent_nb;
+ char bad_blocks_loaded;
+};
+typedef struct _HfsPrivateFSData HfsPrivateFSData;
+
+/* Generic btree key */
+struct __attribute__ ((packed)) _HfsPrivateGenericKey {
+ uint8_t key_length;
+ uint8_t key_content[1]; /* we use 1 as a minimum size */
+};
+typedef struct _HfsPrivateGenericKey HfsPrivateGenericKey;
+
+/* ----- HFS+ ----- */
+
+/* Data of an opened HFS file */
+struct _HfsPPrivateFile {
+ PedSector sect_nb;
+ PedFileSystem* fs;
+ HfsPNodeID CNID; /* disk order (BE) */
+ HfsPExtDataRec first; /* disk order (BE) */
+ HfsPExtDataRec cache; /* disk order (BE) */
+ uint32_t start_cache; /* CPU order */
+};
+typedef struct _HfsPPrivateFile HfsPPrivateFile;
+
+struct _HfsPPrivateExtent {
+ PedSector start_sector;
+ PedSector sector_count;
+};
+typedef struct _HfsPPrivateExtent HfsPPrivateExtent;
+
+/* To store bad block list */
+struct _HfsPPrivateLinkExtent {
+ HfsPExtDescriptor extent;
+ struct _HfsPPrivateLinkExtent* next;
+};
+typedef struct _HfsPPrivateLinkExtent HfsPPrivateLinkExtent;
+
+/* HFS+ file system specific data */
+struct _HfsPPrivateFSData {
+ PedFileSystem* wrapper; /* NULL if hfs+ is not embedded */
+ PedGeometry* plus_geom; /* Geometry of HFS+ _volume_ */
+ uint8_t* alloc_map;
+ uint8_t* dirty_alloc_map;
+ HfsPVolumeHeader* vh;
+ HfsPPrivateFile* extents_file;
+ HfsPPrivateFile* catalog_file;
+ HfsPPrivateFile* attributes_file;
+ HfsPPrivateFile* allocation_file;
+ HfsPPrivateLinkExtent* bad_blocks_xtent_list;
+ uint32_t jib_start_block;
+ uint32_t jl_start_block;
+ unsigned int bad_blocks_xtent_nb;
+ char bad_blocks_loaded;
+ char free_geom; /* 1 = plus_geom must be freed */
+};
+typedef struct _HfsPPrivateFSData HfsPPrivateFSData;
+
+/* Generic + btree key */
+struct __attribute__ ((packed)) _HfsPPrivateGenericKey {
+ uint16_t key_length;
+ uint8_t key_content[1]; /* we use 1 as a minimum size */
+};
+typedef struct _HfsPPrivateGenericKey HfsPPrivateGenericKey;
+
+/* ---- common ---- */
+
+/* node and lead record reference for a BTree search */
+struct _HfsCPrivateLeafRec {
+ unsigned int node_size; /* in sectors */
+ unsigned int node_number;
+ unsigned int record_pos;
+ unsigned int record_number;
+};
+typedef struct _HfsCPrivateLeafRec HfsCPrivateLeafRec;
+
+extern uint8_t* hfs_block;
+extern uint8_t* hfsp_block;
+extern unsigned hfs_block_count;
+extern unsigned hfsp_block_count;
+
+#endif /* _HFS_H */
diff --git a/libparted/fs/hfs/probe.c b/libparted/fs/hfs/probe.c
new file mode 100644
index 0000000..d02ca28
--- /dev/null
+++ b/libparted/fs/hfs/probe.c
@@ -0,0 +1,238 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+
+#include "probe.h"
+
+int
+hfsc_can_use_geom (PedGeometry* geom)
+{
+ PedDevice* dev;
+
+ dev = geom->dev;
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (dev != NULL);
+
+ if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Parted can't use HFS file systems on disks "
+ "with a sector size not equal to %d bytes."),
+ (int)PED_SECTOR_SIZE_DEFAULT );
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Probe an HFS volume, detecting it even if
+it is in fact a wrapper to an HFS+ volume */
+/* Used by hfsplus_probe and hfs_probe */
+PedGeometry*
+hfs_and_wrapper_probe (PedGeometry* geom)
+{
+ HfsMasterDirectoryBlock *mdb;
+ PedGeometry* geom_ret;
+ PedSector search, max;
+
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (hfsc_can_use_geom (geom));
+
+ const int sectors = ((3 * 512) + geom->dev->sector_size - 1) /
+ geom->dev->sector_size;
+ char * buf = alloca (sectors * geom->dev->sector_size);
+
+ mdb = (HfsMasterDirectoryBlock *)(buf+1024);
+
+ /* is 5 an intelligent value ? */
+ if ((geom->length < 5)
+ || (!ped_geometry_read (geom, buf, 0, sectors))
+ || (mdb->signature != PED_CPU_TO_BE16 (HFS_SIGNATURE)) )
+ return NULL;
+
+ search = ((PedSector) PED_BE16_TO_CPU (mdb->start_block)
+ + ((PedSector) PED_BE16_TO_CPU (mdb->total_blocks)
+ * (PED_BE32_TO_CPU (mdb->block_size) / geom->dev->sector_size)));
+ max = search + (PED_BE32_TO_CPU (mdb->block_size) / geom->dev->sector_size);
+ if ((search < 0)
+ || !(geom_ret = ped_geometry_new (geom->dev, geom->start, search + 2)))
+ return NULL;
+
+ for (; search < max; search++) {
+ if (!ped_geometry_set (geom_ret, geom_ret->start, search + 2)
+ || !ped_geometry_read (geom_ret, buf, search, 1))
+ break;
+ if (mdb->signature == PED_CPU_TO_BE16 (HFS_SIGNATURE))
+ return geom_ret;
+ }
+
+ ped_geometry_destroy (geom_ret);
+ return NULL;
+}
+
+PedGeometry*
+hfsplus_probe (PedGeometry* geom)
+{
+ PedGeometry* geom_ret;
+ uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
+
+ PED_ASSERT (geom != NULL);
+
+ if (!hfsc_can_use_geom (geom))
+ return NULL;
+
+ 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)
+ || (mdb->old_new.embedded.signature
+ != PED_CPU_TO_BE16 (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 ((geom->length < 5)
+ || !ped_geometry_read (geom, buf, 2, 1)
+ || (vh->signature != PED_CPU_TO_BE16 (HFSP_SIGNATURE)))
+ return NULL;
+
+ /* Correct range is indeed [ blocks*sz-2;(blocs+1)*sz-2 ( */
+ /* But previous versions of my implementation used to */
+ /* assume range is [(blocks-1)*sz-1;(blocks*sz) ( */
+ /* (blocks-1)*sz-1 has to be scanned last, because */
+ /* it can belong to a regular file */
+ max = ((PedSector) PED_BE32_TO_CPU (vh->total_blocks) + 1)
+ * ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT )
+ - 2;
+ search = max - 2 * ( PED_BE32_TO_CPU (vh->block_size)
+ / PED_SECTOR_SIZE_DEFAULT ) + 2;
+ if ((search < 0)
+ || !(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 (vh->signature == PED_CPU_TO_BE16 (HFSP_SIGNATURE))
+ return geom_ret;
+ }
+ search = ((PedSector) PED_BE32_TO_CPU (vh->total_blocks) - 1)
+ * ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT )
+ - 1;
+ if ((search < 0)
+ || !ped_geometry_set (geom_ret, geom_ret->start,
+ search + 2)
+ || !ped_geometry_read (geom_ret, buf, search, 1)
+ || vh->signature != PED_CPU_TO_BE16 (HFSP_SIGNATURE)) {
+ ped_geometry_destroy (geom_ret);
+ return NULL;
+ } else
+ return geom_ret;
+ }
+}
+
+PedGeometry*
+hfs_probe (PedGeometry* geom)
+{
+ PedGeometry* geom_base;
+ PedGeometry* geom_plus = NULL;
+
+ PED_ASSERT (geom != NULL);
+
+ if (!hfsc_can_use_geom (geom))
+ return 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;
+ }
+}
+
+PedGeometry*
+hfsx_probe (PedGeometry* geom)
+{
+ PedGeometry* geom_ret;
+ uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
+ PedSector search, max;
+ HfsPVolumeHeader *vh = (HfsPVolumeHeader *) buf;
+
+ PED_ASSERT (geom != NULL);
+
+ if (!hfsc_can_use_geom (geom))
+ return NULL;
+
+ if ((geom->length < 5)
+ || !ped_geometry_read (geom, buf, 2, 1)
+ || (vh->signature != PED_CPU_TO_BE16 (HFSX_SIGNATURE)))
+ return NULL;
+
+ /* unlike the hfs+ code, which should be kept compatible
+ with my old previous implementations, we only care here
+ about legal alternate VH positions, like TN1150 describes them */
+ max = ((PedSector) PED_BE32_TO_CPU (vh->total_blocks) + 1)
+ * ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT )
+ - 2;
+ search = max - ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT );
+ if ((search < 0)
+ || !(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 (vh->signature == PED_CPU_TO_BE16 (HFSX_SIGNATURE))
+ return geom_ret;
+ }
+
+ ped_geometry_destroy (geom_ret);
+ return NULL;
+}
diff --git a/libparted/fs/hfs/probe.h b/libparted/fs/hfs/probe.h
new file mode 100644
index 0000000..29ce880
--- /dev/null
+++ b/libparted/fs/hfs/probe.h
@@ -0,0 +1,44 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 2007, 2009-2014, 2019-2023 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _PROBE_H
+#define _PROBE_H
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include "hfs.h"
+
+int
+hfsc_can_use_geom (PedGeometry* geom);
+
+PedGeometry*
+hfs_and_wrapper_probe (PedGeometry* geom);
+
+PedGeometry*
+hfsplus_probe (PedGeometry* geom);
+
+PedGeometry*
+hfs_probe (PedGeometry* geom);
+
+PedGeometry*
+hfsx_probe (PedGeometry* geom);
+
+#endif /* _PROBE_H */