pmt: initial 3.0.2 update

This commit is contained in:
2024-12-14 11:17:56 +03:00
parent bbf76e4925
commit a6c9feb4d6
1292 changed files with 500838 additions and 2817 deletions

92
jni/parted/libparted/fs/hfs/DOC Executable file
View File

@@ -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.
---

View File

@@ -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

View File

@@ -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(+)

View File

@@ -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);
}

648
jni/parted/libparted/fs/hfs/hfs.h Executable file
View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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 */