[PATCH RFC 3/8] staging: apfs: init apfs_raw.h to handle on-disk structures

Ethan Carter Edwards
2025-03-14T21:58:39Z

This file handles and stores information regarding on disk structures.
It includes some magic numbers and bits of information.

Signed-off-by: Ethan Carter Edwards <ethan@ethancedwards.com>
---
drivers/staging/apfs/apfs_raw.h | 1567 +++++++++++++++++++++++++++++++++++++++
1 file changed, 1567 insertions(+)

diff --git a/drivers/staging/apfs/apfs_raw.h b/drivers/staging/apfs/apfs_raw.h
new file mode 100644
index 0000000000000000000000000000000000000000..c131bb07ff249bfb8ac37e28d1256a4bd9ed94c3
--- /dev/null
+++ b/drivers/staging/apfs/apfs_raw.h
@@ -0,0 +1,1567 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2019 Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
+ * Copyright (C) 2025 Ethan Carter Edwards <ethan@ethancedwards.com>
+ *
+ * Definitions for all on-disk data structures.
+ */
+
+#ifndef _APFS_RAW_H
+#define _APFS_RAW_H
+
+#include <linux/types.h>
+#include <linux/uuid.h>
+
+/* Object identifiers constants */
+#define APFS_OID_NX_SUPERBLOCK 1
+#define APFS_OID_INVALID 0ULL
+#define APFS_OID_RESERVED_COUNT 1024
+
+/* Object type masks */
+#define APFS_OBJECT_TYPE_MASK 0x0000ffff
+#define APFS_OBJECT_TYPE_FLAGS_MASK 0xffff0000
+#define APFS_OBJ_STORAGETYPE_MASK 0xc0000000
+#define APFS_OBJECT_TYPE_FLAGS_DEFINED_MASK 0xf8000000
+
+/* Object types */
+#define APFS_OBJECT_TYPE_NX_SUPERBLOCK 0x00000001
+#define APFS_OBJECT_TYPE_BTREE 0x00000002
+#define APFS_OBJECT_TYPE_BTREE_NODE 0x00000003
+#define APFS_OBJECT_TYPE_SPACEMAN 0x00000005
+#define APFS_OBJECT_TYPE_SPACEMAN_CAB 0x00000006
+#define APFS_OBJECT_TYPE_SPACEMAN_CIB 0x00000007
+#define APFS_OBJECT_TYPE_SPACEMAN_BITMAP 0x00000008
+#define APFS_OBJECT_TYPE_SPACEMAN_FREE_QUEUE 0x00000009
+#define APFS_OBJECT_TYPE_EXTENT_LIST_TREE 0x0000000a
+#define APFS_OBJECT_TYPE_OMAP 0x0000000b
+#define APFS_OBJECT_TYPE_CHECKPOINT_MAP 0x0000000c
+#define APFS_OBJECT_TYPE_FS 0x0000000d
+#define APFS_OBJECT_TYPE_FSTREE 0x0000000e
+#define APFS_OBJECT_TYPE_BLOCKREFTREE 0x0000000f
+#define APFS_OBJECT_TYPE_SNAPMETATREE 0x00000010
+#define APFS_OBJECT_TYPE_NX_REAPER 0x00000011
+#define APFS_OBJECT_TYPE_NX_REAP_LIST 0x00000012
+#define APFS_OBJECT_TYPE_OMAP_SNAPSHOT 0x00000013
+#define APFS_OBJECT_TYPE_EFI_JUMPSTART 0x00000014
+#define APFS_OBJECT_TYPE_FUSION_MIDDLE_TREE 0x00000015
+#define APFS_OBJECT_TYPE_NX_FUSION_WBC 0x00000016
+#define APFS_OBJECT_TYPE_NX_FUSION_WBC_LIST 0x00000017
+#define APFS_OBJECT_TYPE_ER_STATE 0x00000018
+#define APFS_OBJECT_TYPE_GBITMAP 0x00000019
+#define APFS_OBJECT_TYPE_GBITMAP_TREE 0x0000001a
+#define APFS_OBJECT_TYPE_GBITMAP_BLOCK 0x0000001b
+#define APFS_OBJECT_TYPE_ER_RECOVERY_BLOCK 0x0000001c
+#define APFS_OBJECT_TYPE_SNAP_META_EXT 0x0000001d
+#define APFS_OBJECT_TYPE_INTEGRITY_META 0x0000001e
+#define APFS_OBJECT_TYPE_FEXT_TREE 0x0000001f
+#define APFS_OBJECT_TYPE_RESERVED_20 0x00000020
+#define APFS_OBJECT_TYPE_INVALID 0x00000000
+#define APFS_OBJECT_TYPE_TEST 0x000000ff
+
+/* Object type flags */
+#define APFS_OBJ_VIRTUAL 0x00000000
+#define APFS_OBJ_EPHEMERAL 0x80000000
+#define APFS_OBJ_PHYSICAL 0x40000000
+#define APFS_OBJ_NOHEADER 0x20000000
+#define APFS_OBJ_ENCRYPTED 0x10000000
+#define APFS_OBJ_NONPERSISTENT 0x08000000
+
+#define APFS_MAX_CKSUM_SIZE 8
+
+/*
+ * On-disk representation of an APFS object
+ */
+struct apfs_obj_phys {
+/*00*/ __le64 o_cksum; /* Fletcher checksum */
+ __le64 o_oid; /* Object-id */
+/*10*/ __le64 o_xid; /* Transaction ID */
+ __le32 o_type; /* Object type */
+ __le32 o_subtype; /* Object subtype */
+} __packed;
+
+/* Flags for the object map structure */
+#define APFS_OMAP_MANUALLY_MANAGED 0x00000001
+#define APFS_OMAP_ENCRYPTING 0x00000002
+#define APFS_OMAP_DECRYPTING 0x00000004
+#define APFS_OMAP_KEYROLLING 0x00000008
+#define APFS_OMAP_CRYPTO_GENERATION 0x00000010
+#define APFS_OMAP_FLAGS_VALID_MASK (APFS_OMAP_MANUALLY_MANAGED \
+ | APFS_OMAP_ENCRYPTING \
+ | APFS_OMAP_DECRYPTING \
+ | APFS_OMAP_KEYROLLING \
+ | APFS_OMAP_CRYPTO_GENERATION)
+
+/*
+ * On-disk representation of an object map
+ */
+struct apfs_omap_phys {
+/*00*/ struct apfs_obj_phys om_o;
+/*20*/ __le32 om_flags;
+ __le32 om_snap_count;
+ __le32 om_tree_type;
+ __le32 om_snapshot_tree_type;
+/*30*/ __le64 om_tree_oid;
+ __le64 om_snapshot_tree_oid;
+/*40*/ __le64 om_most_recent_snap;
+ __le64 om_pending_revert_min;
+ __le64 om_pending_revert_max;
+} __packed;
+
+/* Object map value flags */
+#define APFS_OMAP_VAL_DELETED 0x00000001
+#define APFS_OMAP_VAL_SAVED 0x00000002
+#define APFS_OMAP_VAL_ENCRYPTED 0x00000004
+#define APFS_OMAP_VAL_NOHEADER 0x00000008
+#define APFS_OMAP_VAL_CRYPTO_GENERATION 0x00000010
+#define APFS_OMAP_VAL_FLAGS_VALID_MASK (APFS_OMAP_VAL_DELETED \
+ | APFS_OMAP_VAL_SAVED \
+ | APFS_OMAP_VAL_ENCRYPTED \
+ | APFS_OMAP_VAL_NOHEADER \
+ | APFS_OMAP_VAL_CRYPTO_GENERATION)
+
+/*
+ * Structure of a value in an object map B-tree
+ */
+struct apfs_omap_val {
+ __le32 ov_flags;
+ __le32 ov_size;
+ __le64 ov_paddr;
+} __packed;
+
+/*
+ * Structure of a value in an omap's snapshot tree
+ */
+struct apfs_omap_snapshot {
+ __le32 oms_flags;
+ __le32 oms_pad;
+ __le64 oms_oid;
+} __packed;
+
+/* B-tree node flags */
+#define APFS_BTNODE_ROOT 0x0001
+#define APFS_BTNODE_LEAF 0x0002
+#define APFS_BTNODE_FIXED_KV_SIZE 0x0004
+#define APFS_BTNODE_CHECK_KOFF_INVAL 0x8000
+#define APFS_BTNODE_MASK 0x0007 /* Valid on-disk flags */
+
+/* B-tree location constants */
+#define APFS_BTOFF_INVALID 0xffff
+
+/*
+ * Structure storing a location inside a B-tree node
+ */
+struct apfs_nloc {
+ __le16 off;
+ __le16 len;
+} __packed;
+
+/*
+ * Structure storing the location of a key/value pair within a B-tree node
+ */
+struct apfs_kvloc {
+ struct apfs_nloc k;
+ struct apfs_nloc v;
+} __packed;
+
+/*
+ * Structure storing the location of a key/value pair within a B-tree node
+ * having fixed-size key and value (flag APFS_BTNODE_FIXED_KV_SIZE is present)
+ */
+struct apfs_kvoff {
+ __le16 k;
+ __le16 v;
+} __packed;
+
+/*
+ * On-disk representation of a B-tree node
+ */
+struct apfs_btree_node_phys {
+/*00*/ struct apfs_obj_phys btn_o;
+/*20*/ __le16 btn_flags;
+ __le16 btn_level;
+ __le32 btn_nkeys;
+/*28*/ struct apfs_nloc btn_table_space;
+ struct apfs_nloc btn_free_space;
+ struct apfs_nloc btn_key_free_list;
+ struct apfs_nloc btn_val_free_list;
+/*38*/ __le64 btn_data[];
+} __packed;
+
+/* B-tree info flags */
+#define APFS_BTREE_UINT64_KEYS 0x00000001
+#define APFS_BTREE_SEQUENTIAL_INSERT 0x00000002
+#define APFS_BTREE_ALLOW_GHOSTS 0x00000004
+#define APFS_BTREE_EPHEMERAL 0x00000008
+#define APFS_BTREE_PHYSICAL 0x00000010
+#define APFS_BTREE_NONPERSISTENT 0x00000020
+#define APFS_BTREE_KV_NONALIGNED 0x00000040
+#define APFS_BTREE_FLAGS_VALID_MASK (APFS_BTREE_UINT64_KEYS \
+ | APFS_BTREE_SEQUENTIAL_INSERT \
+ | APFS_BTREE_ALLOW_GHOSTS \
+ | APFS_BTREE_EPHEMERAL \
+ | APFS_BTREE_PHYSICAL \
+ | APFS_BTREE_NONPERSISTENT \
+ | APFS_BTREE_KV_NONALIGNED)
+
+/*
+ * Structure used to store information about a B-tree that won't change
+ * over time
+ */
+struct apfs_btree_info_fixed {
+ __le32 bt_flags;
+ __le32 bt_node_size;
+ __le32 bt_key_size;
+ __le32 bt_val_size;
+} __packed;
+
+/*
+ * Structure used to store information about a B-tree (located at the end of
+ * a B-tree root node block)
+ */
+struct apfs_btree_info {
+ struct apfs_btree_info_fixed bt_fixed;
+ __le32 bt_longest_key; /* Longest key ever stored */
+ __le32 bt_longest_val; /* Longest value ever stored */
+ __le64 bt_key_count;
+ __le64 bt_node_count;
+} __packed;
+
+/*
+ * Structure of the value of a directory entry. This is the data in
+ * the catalog nodes for record type APFS_TYPE_DIR_REC.
+ */
+struct apfs_drec_val {
+ __le64 file_id;
+ __le64 date_added;
+ __le16 flags;
+ u8 xfields[];
+} __packed;
+
+/* Physical extent records */
+#define APFS_PEXT_LEN_MASK 0x0fffffffffffffffULL
+#define APFS_PEXT_KIND_MASK 0xf000000000000000ULL
+#define APFS_PEXT_KIND_SHIFT 60
+
+/* The kind of a physical extent record */
+enum {
+ APFS_KIND_ANY = 0,
+ APFS_KIND_NEW = 1,
+ APFS_KIND_UPDATE = 2,
+ APFS_KIND_DEAD = 3,
+ APFS_KIND_UPDATE_REFCNT = 4,
+
+ APFS_KIND_INVALID = 255 /* This is weird, won't fit in 4 bits */
+};
+
+#define APFS_OWNING_OBJ_ID_INVALID (~0ULL)
+#define APFS_OWNING_OBJ_ID_UNKNOWN (~1ULL)
+
+/*
+ * Structure of a physical extent record
+ */
+struct apfs_phys_ext_val {
+ __le64 len_and_kind;
+ __le64 owning_obj_id;
+ __le32 refcnt;
+} __packed;
+
+/* File extent records */
+#define APFS_FILE_EXTENT_LEN_MASK 0x00ffffffffffffffULL
+#define APFS_FILE_EXTENT_FLAG_MASK 0xff00000000000000ULL
+#define APFS_FILE_EXTENT_FLAG_SHIFT 56
+#define APFS_FILE_EXTENT_CRYPTO_FLAG 0x01 /* Made-up name */
+#define APFS_FILE_EXTENT_PREALLOCATED 0x02 /* Made-up name */
+#define APFS_VALID_FILE_EXTENT_FLAGS (APFS_FILE_EXTENT_CRYPTO_FLAG \
+ | APFS_FILE_EXTENT_PREALLOCATED)
+
+/*
+ * Put a bound on maximum file size so that a growing truncation will always
+ * produce a single hole extent, even if 64k block sizes were in use. Larger
+ * file sizes could be supported with multiple extents of course, but it takes
+ * some work and I don't see the point.
+ */
+#define APFS_MAX_FILE_SIZE 0x00ffffffffff0000ULL
+
+/*
+ * Structure of a file extent record
+ */
+struct apfs_file_extent_val {
+ __le64 len_and_flags;
+ __le64 phys_block_num;
+ __le64 crypto_id;
+} __packed;
+
+/*
+ * Structure of a data stream record
+ */
+struct apfs_dstream_id_val {
+ __le32 refcnt;
+} __packed;
+
+#define APFS_CP_MAX_WRAPPEDKEYSIZE 128
+
+/*
+ * Structure used to store the encryption state for PFKs
+ */
+struct apfs_wrapped_crypto_state {
+ __le16 major_version;
+ __le16 minor_version;
+ __le32 cpflags;
+ __le32 persistent_class;
+ __le32 key_os_version;
+ __le16 key_revision;
+ __le16 key_len;
+ u8 persistent_key[];
+} __packed;
+
+/*
+ * Structure of a crypto state record
+ */
+struct apfs_crypto_state_val {
+ __le32 refcnt;
+ struct apfs_wrapped_crypto_state state;
+} __packed;
+
+/* Inode numbers for special inodes */
+#define APFS_INVALID_INO_NUM 0
+
+#define APFS_ROOT_DIR_PARENT 1 /* Root directory parent */
+#define APFS_ROOT_DIR_INO_NUM 2 /* Root directory */
+#define APFS_PRIV_DIR_INO_NUM 3 /* Private directory */
+#define APFS_SNAP_DIR_INO_NUM 6 /* Snapshots metadata */
+#define APFS_PURGEABLE_DIR_INO_NUM 7 /* Parent of purgeable files */
+
+/* Smallest inode number available for user content */
+#define APFS_MIN_USER_INO_NUM 16
+
+#define APFS_UNIFIED_ID_SPACE_MARK 0x0800000000000000
+
+/* Inode internal flags */
+#define APFS_INODE_IS_APFS_PRIVATE 0x00000001
+#define APFS_INODE_MAINTAIN_DIR_STATS 0x00000002
+#define APFS_INODE_DIR_STATS_ORIGIN 0x00000004
+#define APFS_INODE_PROT_CLASS_EXPLICIT 0x00000008
+#define APFS_INODE_WAS_CLONED 0x00000010
+#define APFS_INODE_FLAG_UNUSED 0x00000020
+#define APFS_INODE_HAS_SECURITY_EA 0x00000040
+#define APFS_INODE_BEING_TRUNCATED 0x00000080
+#define APFS_INODE_HAS_FINDER_INFO 0x00000100
+#define APFS_INODE_IS_SPARSE 0x00000200
+#define APFS_INODE_WAS_EVER_CLONED 0x00000400
+#define APFS_INODE_ACTIVE_FILE_TRIMMED 0x00000800
+#define APFS_INODE_PINNED_TO_MAIN 0x00001000
+#define APFS_INODE_PINNED_TO_TIER2 0x00002000
+#define APFS_INODE_HAS_RSRC_FORK 0x00004000
+#define APFS_INODE_NO_RSRC_FORK 0x00008000
+#define APFS_INODE_ALLOCATION_SPILLEDOVER 0x00010000
+#define APFS_INODE_FAST_PROMOTE 0x00020000
+#define APFS_INODE_HAS_UNCOMPRESSED_SIZE 0x00040000
+#define APFS_INODE_IS_PURGEABLE 0x00080000
+#define APFS_INODE_WANTS_TO_BE_PURGEABLE 0x00100000
+#define APFS_INODE_IS_SYNC_ROOT 0x00200000
+#define APFS_INODE_SNAPSHOT_COW_EXEMPTION 0x00400000
+/* This flag is not documented */
+#define APFS_INODE_HAS_PURGEABLE_FLAGS 0x02000000
+
+/* Masks for internal flags */
+#define APFS_VALID_INTERNAL_INODE_FLAGS (APFS_INODE_IS_APFS_PRIVATE \
+ | APFS_INODE_MAINTAIN_DIR_STATS \
+ | APFS_INODE_DIR_STATS_ORIGIN \
+ | APFS_INODE_PROT_CLASS_EXPLICIT \
+ | APFS_INODE_WAS_CLONED \
+ | APFS_INODE_HAS_SECURITY_EA \
+ | APFS_INODE_BEING_TRUNCATED \
+ | APFS_INODE_HAS_FINDER_INFO \
+ | APFS_INODE_IS_SPARSE \
+ | APFS_INODE_WAS_EVER_CLONED \
+ | APFS_INODE_ACTIVE_FILE_TRIMMED \
+ | APFS_INODE_PINNED_TO_MAIN \
+ | APFS_INODE_PINNED_TO_TIER2 \
+ | APFS_INODE_HAS_RSRC_FORK \
+ | APFS_INODE_NO_RSRC_FORK \
+ | APFS_INODE_ALLOCATION_SPILLEDOVER \
+ | APFS_INODE_FAST_PROMOTE \
+ | APFS_INODE_HAS_UNCOMPRESSED_SIZE \
+ | APFS_INODE_IS_PURGEABLE \
+ | APFS_INODE_WANTS_TO_BE_PURGEABLE \
+ | APFS_INODE_IS_SYNC_ROOT \
+ | APFS_INODE_SNAPSHOT_COW_EXEMPTION \
+ | APFS_INODE_HAS_PURGEABLE_FLAGS)
+#define APFS_INODE_INHERITED_INTERNAL_FLAGS (APFS_INODE_MAINTAIN_DIR_STATS)
+#define APFS_INDOE_CLONED_INTERNAL_FLAGS (APFS_INODE_HAS_RSRC_FORK \
+ | APFS_INODE_NO_RSRC_FORK \
+ | APFS_INODE_HAS_FINDER_INFO)
+#define APFS_INODE_PINNED_MASK (APFS_INODE_PINNED_TO_MAIN \
+ | APFS_INODE_PINNED_TO_TIER2)
+
+/* BSD flags */
+#define APFS_INOBSD_NODUMP 0x00000001
+#define APFS_INOBSD_IMMUTABLE 0x00000002
+#define APFS_INOBSD_APPEND 0x00000004
+#define APFS_INOBSD_COMPRESSED 0x00000020
+
+/*
+ * Structure of an inode as stored as a B-tree value
+ */
+struct apfs_inode_val {
+/*00*/ __le64 parent_id;
+ __le64 private_id;
+/*10*/ __le64 create_time;
+ __le64 mod_time;
+ __le64 change_time;
+ __le64 access_time;
+/*30*/ __le64 internal_flags;
+ union {
+ __le32 nchildren;
+ __le32 nlink;
+ };
+ __le32 default_protection_class;
+/*40*/ __le32 write_generation_counter;
+ __le32 bsd_flags;
+ __le32 owner;
+ __le32 group;
+/*50*/ __le16 mode;
+ __le16 pad1;
+ __le64 uncompressed_size;
+/*5C*/ u8 xfields[];
+} __packed;
+
+/* Extended field types for dentries */
+#define APFS_DREC_EXT_TYPE_SIBLING_ID 1
+
+/* Extended field types for inodes */
+#define APFS_INO_EXT_TYPE_SNAP_XID 1
+#define APFS_INO_EXT_TYPE_DELTA_TREE_OID 2
+#define APFS_INO_EXT_TYPE_DOCUMENT_ID 3
+#define APFS_INO_EXT_TYPE_NAME 4
+#define APFS_INO_EXT_TYPE_PREV_FSIZE 5
+#define APFS_INO_EXT_TYPE_RESERVED_6 6
+#define APFS_INO_EXT_TYPE_FINDER_INFO 7
+#define APFS_INO_EXT_TYPE_DSTREAM 8
+#define APFS_INO_EXT_TYPE_RESERVED_9 9
+#define APFS_INO_EXT_TYPE_DIR_STATS_KEY 10
+#define APFS_INO_EXT_TYPE_FS_UUID 11
+#define APFS_INO_EXT_TYPE_RESERVED_12 12
+#define APFS_INO_EXT_TYPE_SPARSE_BYTES 13
+#define APFS_INO_EXT_TYPE_RDEV 14
+#define APFS_INO_EXT_TYPE_PURGEABLE_FLAGS 15
+#define APFS_INO_EXT_TYPE_ORIG_SYNC_ROOT_ID 16
+
+/* Extended field flags */
+#define APFS_XF_DATA_DEPENDENT 0x01
+#define APFS_XF_DO_NOT_COPY 0x02
+#define APFS_XF_RESERVED_4 0x04
+#define APFS_XF_CHILDREN_INHERIT 0x08
+#define APFS_XF_USER_FIELD 0x10
+#define APFS_XF_SYSTEM_FIELD 0x20
+#define APFS_XF_RESERVED_40 0x40
+#define APFS_XF_RESERVED_80 0x80
+
+/* Constants for extended fields */
+#define APFS_MIN_DOC_ID 3 /* Smallest not reserved document id */
+
+/*
+ * Structure used to store the number and size of an xfield collection. The
+ * official reference seems to be wrong about @xf_used_data: it's the size of
+ * the xfield values alone, without the metadata.
+ */
+struct apfs_xf_blob {
+ __le16 xf_num_exts;
+ __le16 xf_used_data;
+ u8 xf_data[];
+} __packed;
+
+/*
+ * Structure used to describe an extended field
+ */
+struct apfs_x_field {
+ u8 x_type;
+ u8 x_flags;
+ __le16 x_size;
+} __packed;
+
+/*
+ * Structure used to store information about a data stream
+ */
+struct apfs_dstream {
+ __le64 size;
+ __le64 alloced_size;
+ __le64 default_crypto_id;
+ __le64 total_bytes_written;
+ __le64 total_bytes_read;
+} __packed;
+
+/*
+ * Structure used to store directory information
+ */
+struct apfs_dir_stats_val {
+ __le64 num_children;
+ __le64 total_size;
+ __le64 chained_key;
+ __le64 gen_count;
+} __packed;
+
+/*
+ * Structure of the value for a sibling link record. These are used to
+ * list the hard links for a given inode.
+ */
+struct apfs_sibling_val {
+ __le64 parent_id;
+ __le16 name_len;
+ u8 name[];
+} __packed;
+
+/*
+ * Structure of the value for a sibling map record. No idea what these are for.
+ */
+struct apfs_sibling_map_val {
+ __le64 file_id;
+} __packed;
+
+/*
+ * Structure of a key in an object map B-tree
+ */
+struct apfs_omap_key {
+ __le64 ok_oid;
+ __le64 ok_xid;
+} __packed;
+
+/*
+ * Structure of a key in a free-space queue b-tree
+ */
+struct apfs_spaceman_free_queue_key {
+ __le64 sfqk_xid;
+ __le64 sfqk_paddr;
+} __packed;
+
+/* Catalog records types */
+enum {
+ APFS_TYPE_ANY = 0,
+ APFS_TYPE_SNAP_METADATA = 1,
+ APFS_TYPE_EXTENT = 2,
+ APFS_TYPE_INODE = 3,
+ APFS_TYPE_XATTR = 4,
+ APFS_TYPE_SIBLING_LINK = 5,
+ APFS_TYPE_DSTREAM_ID = 6,
+ APFS_TYPE_CRYPTO_STATE = 7,
+ APFS_TYPE_FILE_EXTENT = 8,
+ APFS_TYPE_DIR_REC = 9,
+ APFS_TYPE_DIR_STATS = 10,
+ APFS_TYPE_SNAP_NAME = 11,
+ APFS_TYPE_SIBLING_MAP = 12,
+ APFS_TYPE_MAX_VALID = 12,
+ APFS_TYPE_MAX = 15,
+ APFS_TYPE_INVALID = 15,
+};
+
+/* Bit masks for the 'obj_id_and_type' field of a key header */
+#define APFS_OBJ_ID_MASK 0x0fffffffffffffffULL
+#define APFS_OBJ_TYPE_MASK 0xf000000000000000ULL
+#define APFS_OBJ_TYPE_SHIFT 60
+
+/* Key header for filesystem-object keys */
+struct apfs_key_header {
+ __le64 obj_id_and_type;
+} __packed;
+
+/*
+ * Structure of the key for a physical extent record
+ */
+struct apfs_phys_ext_key {
+ struct apfs_key_header hdr;
+} __packed;
+
+/*
+ * Structure of the key for an inode record
+ */
+struct apfs_inode_key {
+ struct apfs_key_header hdr;
+} __packed;
+
+/*
+ * Structure of the key for a file extent record
+ */
+struct apfs_file_extent_key {
+ struct apfs_key_header hdr;
+ __le64 logical_addr;
+} __packed;
+
+/*
+ * Structure of the key for a data stream record
+ */
+struct apfs_dstream_id_key {
+ struct apfs_key_header hdr;
+} __packed;
+
+/*
+ * Structure of the key for a crypto state record
+ */
+struct apfs_crypto_state_key {
+ struct apfs_key_header hdr;
+} __packed;
+
+/* Bit masks for the 'name_len_and_hash' field of a directory entry */
+#define APFS_DREC_LEN_MASK 0x000003ff
+#define APFS_DREC_HASH_MASK 0xfffffc00
+#define APFS_DREC_HASH_SHIFT 10
+
+/* We could support bigger filenames, but I don't know if Linux allows it */
+#define APFS_NAME_LEN NAME_MAX
+
+/* Bit masks for the 'type' field of a directory entry */
+enum {
+ APFS_DREC_TYPE_MASK = 0x000f,
+ APFS_DREC_RESERVED_10 = 0x0010,
+
+ /* These flags are not documented */
+ APFS_DREC_PURGEABLE_2 = 0x0200,
+ APFS_DREC_PURGEABLE_8 = 0x0800,
+};
+
+#define APFS_DREC_PURGEABLE (APFS_DREC_PURGEABLE_2 | APFS_DREC_PURGEABLE_8)
+
+/*
+ * Structure of the key for a directory entry - no hash, used on normalization
+ * sensitive volumes
+ */
+struct apfs_drec_key {
+ struct apfs_key_header hdr;
+ __le16 name_len;
+ u8 name[];
+} __packed;
+
+/*
+ * Structure of the key for a directory entry, including a precomputed
+ * hash of its name
+ */
+struct apfs_drec_hashed_key {
+ struct apfs_key_header hdr;
+ __le32 name_len_and_hash;
+ u8 name[];
+} __packed;
+
+/*
+ * Structure of the key for an extended attributes record
+ */
+struct apfs_xattr_key {
+ struct apfs_key_header hdr;
+ __le16 name_len;
+ u8 name[];
+} __packed;
+
+/*
+ * Structure of the key for a snapshot metadata record
+ */
+struct apfs_snap_metadata_key {
+ struct apfs_key_header hdr;
+} __packed;
+
+/* The snapshot name headers always have this placeholder object id */
+#define APFS_SNAP_NAME_OBJ_ID (~0ULL & APFS_OBJ_ID_MASK)
+
+/*
+ * Structure of the key for a snapshot name record
+ */
+struct apfs_snap_name_key {
+ struct apfs_key_header hdr;
+ __le16 name_len;
+ u8 name[];
+} __packed;
+
+/*
+ * Structure of the key for a sibling link record
+ */
+struct apfs_sibling_link_key {
+ struct apfs_key_header hdr;
+ __le64 sibling_id;
+} __packed;
+
+/*
+ * Structure of the key for a siblink map record
+ */
+struct apfs_sibling_map_key {
+ struct apfs_key_header hdr;
+} __packed;
+
+/*
+ * On-disk allocation info for a chunk of blocks
+ */
+struct apfs_chunk_info {
+ __le64 ci_xid;
+ __le64 ci_addr;
+ __le32 ci_block_count;
+ __le32 ci_free_count;
+ __le64 ci_bitmap_addr;
+} __packed;
+
+/* Constants for the chunk info block */
+#define APFS_CI_COUNT_MASK 0x000FFFFF
+#define APFS_CI_COUNT_RESERVED_MASK 0xFFF00000
+
+/*
+ * Structure of a block with an array of chunk allocation info structures
+ */
+struct apfs_chunk_info_block {
+ struct apfs_obj_phys cib_o;
+ __le32 cib_index;
+ __le32 cib_chunk_info_count;
+ struct apfs_chunk_info cib_chunk_info[];
+} __packed;
+
+/*
+ * Structure of a block with an array of addresses to chunk information blocks
+ */
+struct apfs_cib_addr_block {
+ struct apfs_obj_phys cab_o;
+ __le32 cab_index;
+ __le32 cab_cib_count;
+ __le64 cab_cib_addr[];
+} __packed;
+
+/*
+ * On-disk structure for a free queue
+ */
+struct apfs_spaceman_free_queue {
+ __le64 sfq_count;
+ __le64 sfq_tree_oid;
+ __le64 sfq_oldest_xid;
+ __le16 sfq_tree_node_limit;
+ __le16 sfq_pad16;
+ __le32 sfq_pad32;
+ __le64 sfq_reserved;
+} __packed;
+
+/* Indexes for a free queue array */
+enum {
+ APFS_SFQ_IP = 0,
+ APFS_SFQ_MAIN = 1,
+ APFS_SFQ_TIER2 = 2,
+ APFS_SFQ_COUNT = 3
+};
+
+/*
+ * On-disk structure for device allocation information
+ */
+struct apfs_spaceman_device {
+ __le64 sm_block_count;
+ __le64 sm_chunk_count;
+ __le32 sm_cib_count;
+ __le32 sm_cab_count;
+ __le64 sm_free_count;
+ __le32 sm_addr_offset;
+ __le32 sm_reserved;
+ __le64 sm_reserved2;
+} __packed;
+
+/* Indexes for a device array */
+enum {
+ APFS_SD_MAIN = 0,
+ APFS_SD_TIER2 = 1,
+ APFS_SD_COUNT = 2
+};
+
+/*
+ * On-disk structure to describe allocation zone boundaries
+ */
+struct apfs_spaceman_allocation_zone_boundaries {
+ __le64 saz_zone_start;
+ __le64 saz_zone_end;
+} __packed;
+
+/* Allocation zone constants */
+#define APFS_SM_ALLOCZONE_INVALID_END_BOUNDARY 0
+#define APFS_SM_ALLOCZONE_NUM_PREVIOUS_BOUNDARIES 7
+
+struct apfs_spaceman_allocation_zone_info_phys {
+ struct apfs_spaceman_allocation_zone_boundaries saz_current_boundaries;
+ struct apfs_spaceman_allocation_zone_boundaries
+ saz_previous_boundaries[APFS_SM_ALLOCZONE_NUM_PREVIOUS_BOUNDARIES];
+
+ __le16 saz_zone_id;
+ __le16 saz_previous_boundary_index;
+ __le32 saz_reserved;
+} __packed;
+
+/* Datazone constants */
+#define APFS_SM_DATAZONE_ALLOCZONE_COUNT 8
+
+struct apfs_spaceman_datazone_info_phys {
+ struct apfs_spaceman_allocation_zone_info_phys
+ sdz_allocation_zones[APFS_SD_COUNT][APFS_SM_DATAZONE_ALLOCZONE_COUNT];
+} __packed;
+
+/* Internal-pool bitmap constants */
+#define APFS_SPACEMAN_IP_BM_TX_MULTIPLIER 16
+#define APFS_SPACEMAN_IP_BM_INDEX_INVALID 0xFFFF
+#define APFS_SPACEMAN_IP_BM_BLOCK_COUNT_MAX 0xFFFE
+
+/* Space manager flags */
+#define APFS_SM_FLAG_VERSIONED 0x00000001
+#define APFS_SM_FLAGS_VALID_MASK APFS_SM_FLAG_VERSIONED
+
+/*
+ * On-disk structure for the space manager
+ */
+struct apfs_spaceman_phys {
+ struct apfs_obj_phys sm_o;
+ __le32 sm_block_size;
+ __le32 sm_blocks_per_chunk;
+ __le32 sm_chunks_per_cib;
+ __le32 sm_cibs_per_cab;
+ struct apfs_spaceman_device sm_dev[APFS_SD_COUNT];
+ __le32 sm_flags;
+ __le32 sm_ip_bm_tx_multiplier;
+ __le64 sm_ip_block_count;
+ __le32 sm_ip_bm_size_in_blocks;
+ __le32 sm_ip_bm_block_count;
+ __le64 sm_ip_bm_base;
+ __le64 sm_ip_base;
+ __le64 sm_fs_reserve_block_count;
+ __le64 sm_fs_reserve_alloc_count;
+ struct apfs_spaceman_free_queue sm_fq[APFS_SFQ_COUNT];
+ __le16 sm_ip_bm_free_head;
+ __le16 sm_ip_bm_free_tail;
+ __le32 sm_ip_bm_xid_offset;
+ __le32 sm_ip_bitmap_offset;
+ __le32 sm_ip_bm_free_next_offset;
+ __le32 sm_version;
+ __le32 sm_struct_size;
+ struct apfs_spaceman_datazone_info_phys sm_datazone;
+} __packed;
+
+/*
+ * Structure used to store a range of physical blocks
+ */
+struct apfs_prange {
+ __le64 pr_start_paddr;
+ __le64 pr_block_count;
+} __packed;
+
+/* Reaper flags */
+#define APFS_NR_BHM_FLAG 0x00000001
+#define APFS_NR_CONTINUE 0x00000002
+#define APFS_NR_FLAGS_VALID_MASK (APFS_NR_BHM_FLAG | APFS_NR_CONTINUE)
+
+/*
+ * On-disk reaper structure
+ */
+struct apfs_nx_reaper_phys {
+ struct apfs_obj_phys nr_o;
+ __le64 nr_next_reap_id;
+ __le64 nr_completed_id;
+ __le64 nr_head;
+ __le64 nr_tail;
+ __le32 nr_flags;
+ __le32 nr_rlcount;
+ __le32 nr_type;
+ __le32 nr_size;
+ __le64 nr_fs_oid;
+ __le64 nr_oid;
+ __le64 nr_xid;
+ __le32 nr_nrle_flags;
+ __le32 nr_state_buffer_size;
+ u8 nr_state_buffer[];
+} __packed;
+
+struct apfs_nx_reap_list_entry {
+ __le32 nrle_next;
+ __le32 nrle_flags;
+ __le32 nrle_type;
+ __le32 nrle_size;
+ __le64 nrle_fs_oid;
+ __le64 nrle_oid;
+ __le64 nrle_xid;
+} __packed;
+
+struct apfs_nx_reap_list_phys {
+ struct apfs_obj_phys nrl_o;
+ __le64 nrl_next;
+ __le32 nrl_flags;
+ __le32 nrl_max;
+ __le32 nrl_count;
+ __le32 nrl_first;
+ __le32 nrl_last;
+ __le32 nrl_free;
+ struct apfs_nx_reap_list_entry nrl_entries[];
+} __packed;
+
+/* EFI constants */
+#define APFS_NX_EFI_JUMPSTART_MAGIC 0x5244534A
+#define APFS_NX_EFI_JUMPSTART_VERSION 1
+
+/*
+ * Information about the embedded EFI driver
+ */
+struct apfs_nx_efi_jumpstart {
+ struct apfs_obj_phys nej_o;
+ __le32 nej_magic;
+ __le32 nej_version;
+ __le32 nej_efi_file_len;
+ __le32 nej_num_extents;
+ __le64 nej_reserved[16];
+ struct apfs_prange nej_rec_extents[];
+} __packed;
+
+/* Main container */
+
+/* Container constants */
+#define APFS_NX_MAGIC 0x4253584E
+#define APFS_NX_BLOCK_NUM 0
+#define APFS_NX_MAX_FILE_SYSTEMS 100
+
+#define APFS_NX_EPH_INFO_COUNT 4
+#define APFS_NX_EPH_MIN_BLOCK_COUNT 8
+#define APFS_NX_MAX_FILE_SYSTEM_EPH_STRUCTS 4
+#define APFS_NX_TX_MIN_CHECKPOINT_COUNT 4
+#define APFS_NX_EPH_INFO_VERSION_1 1
+
+/* Container flags */
+#define APFS_NX_RESERVED_1 0x00000001LL
+#define APFS_NX_RESERVED_2 0x00000002LL
+#define APFS_NX_CRYPTO_SW 0x00000004LL
+#define APFS_NX_FLAGS_VALID_MASK (APFS_NX_RESERVED_1 \
+ | APFS_NX_RESERVED_2 \
+ | APFS_NX_CRYPTO_SW)
+
+/* Optional container feature flags */
+#define APFS_NX_FEATURE_DEFRAG 0x0000000000000001ULL
+#define APFS_NX_FEATURE_LCFD 0x0000000000000002ULL
+#define APFS_NX_SUPPORTED_FEATURES_MASK (APFS_NX_FEATURE_DEFRAG | \
+ APFS_NX_FEATURE_LCFD)
+
+/* Read-only compatible container feature flags */
+#define APFS_NX_SUPPORTED_ROCOMPAT_MASK (0x0ULL)
+
+/* Incompatible container feature flags */
+#define APFS_NX_INCOMPAT_VERSION1 0x0000000000000001ULL
+#define APFS_NX_INCOMPAT_VERSION2 0x0000000000000002ULL
+#define APFS_NX_INCOMPAT_FUSION 0x0000000000000100ULL
+#define APFS_NX_SUPPORTED_INCOMPAT_MASK (APFS_NX_INCOMPAT_VERSION2 \
+ | APFS_NX_INCOMPAT_FUSION)
+
+/* Block and container sizes */
+#define APFS_NX_MINIMUM_BLOCK_SIZE 4096
+#define APFS_NX_DEFAULT_BLOCK_SIZE 4096
+#define APFS_NX_MAXIMUM_BLOCK_SIZE 65536
+#define APFS_NX_MINIMUM_CONTAINER_SIZE 1048576
+
+/* Indexes into a container superblock's array of counters */
+enum {
+ APFS_NX_CNTR_OBJ_CKSUM_SET = 0,
+ APFS_NX_CNTR_OBJ_CKSUM_FAIL = 1,
+
+ APFS_NX_NUM_COUNTERS = 32
+};
+
+/*
+ * On-disk representation of the container superblock
+ */
+struct apfs_nx_superblock {
+/*00*/ struct apfs_obj_phys nx_o;
+/*20*/ __le32 nx_magic;
+ __le32 nx_block_size;
+ __le64 nx_block_count;
+
+/*30*/ __le64 nx_features;
+ __le64 nx_readonly_compatible_features;
+ __le64 nx_incompatible_features;
+
+/*48*/ char nx_uuid[UUID_SIZE];
+
+/*58*/ __le64 nx_next_oid;
+ __le64 nx_next_xid;
+
+/*68*/ __le32 nx_xp_desc_blocks;
+ __le32 nx_xp_data_blocks;
+/*70*/ __le64 nx_xp_desc_base;
+ __le64 nx_xp_data_base;
+ __le32 nx_xp_desc_next;
+ __le32 nx_xp_data_next;
+/*88*/ __le32 nx_xp_desc_index;
+ __le32 nx_xp_desc_len;
+ __le32 nx_xp_data_index;
+ __le32 nx_xp_data_len;
+
+/*98*/ __le64 nx_spaceman_oid;
+ __le64 nx_omap_oid;
+ __le64 nx_reaper_oid;
+
+/*B0*/ __le32 nx_test_type;
+
+ __le32 nx_max_file_systems;
+/*B8*/ __le64 nx_fs_oid[APFS_NX_MAX_FILE_SYSTEMS];
+/*3D8*/ __le64 nx_counters[APFS_NX_NUM_COUNTERS];
+/*4D8*/ struct apfs_prange nx_blocked_out_prange;
+ __le64 nx_evict_mapping_tree_oid;
+/*4F0*/ __le64 nx_flags;
+ __le64 nx_efi_jumpstart;
+/*500*/ char nx_fusion_uuid[UUID_SIZE];
+ struct apfs_prange nx_keylocker;
+/*520*/ __le64 nx_ephemeral_info[APFS_NX_EPH_INFO_COUNT];
+
+/*540*/ __le64 nx_test_oid;
+
+ __le64 nx_fusion_mt_oid;
+/*550*/ __le64 nx_fusion_wbc_oid;
+ struct apfs_prange nx_fusion_wbc;
+
+ __le64 nx_newest_mounted_version;
+
+/*570*/ struct apfs_prange nx_mkb_locker;
+} __packed;
+
+/*
+ * A mapping from an ephemeral object id to its physical address
+ */
+struct apfs_checkpoint_mapping {
+ __le32 cpm_type;
+ __le32 cpm_subtype;
+ __le32 cpm_size;
+ __le32 cpm_pad;
+ __le64 cpm_fs_oid;
+ __le64 cpm_oid;
+ __le64 cpm_paddr;
+} __packed;
+
+/* Checkpoint flags */
+#define APFS_CHECKPOINT_MAP_LAST 0x00000001
+
+/*
+ * A checkpoint-mapping block
+ */
+struct apfs_checkpoint_map_phys {
+ struct apfs_obj_phys cpm_o;
+ __le32 cpm_flags;
+ __le32 cpm_count;
+ struct apfs_checkpoint_mapping cpm_map[];
+} __packed;
+
+/* Volume */
+
+/* Volume constants */
+#define APFS_MAGIC 0x42535041
+
+#define APFS_MAX_HIST 8
+#define APFS_VOLNAME_LEN 256
+
+/* Volume flags */
+#define APFS_FS_UNENCRYPTED 0x00000001LL
+#define APFS_FS_EFFACEABLE 0x00000002LL
+#define APFS_FS_RESERVED_4 0x00000004LL
+#define APFS_FS_ONEKEY 0x00000008LL
+#define APFS_FS_SPILLEDOVER 0x00000010LL
+#define APFS_FS_RUN_SPILLOVER_CLEANER 0x00000020LL
+#define APFS_FS_ALWAYS_CHECK_EXTENTREF 0x00000040LL
+#define APFS_FS_PREVIOUSLY_SEALED 0x00000080LL /* Made-up name */
+#define APFS_FS_PFK 0x00000100LL /* Made-up name */
+#define APFS_FS_UNKNOWN_200 0x00000200LL
+#define APFS_FS_FLAGS_VALID_MASK (APFS_FS_UNENCRYPTED \
+ | APFS_FS_EFFACEABLE \
+ | APFS_FS_RESERVED_4 \
+ | APFS_FS_ONEKEY \
+ | APFS_FS_SPILLEDOVER \
+ | APFS_FS_RUN_SPILLOVER_CLEANER \
+ | APFS_FS_ALWAYS_CHECK_EXTENTREF \
+ | APFS_FS_PREVIOUSLY_SEALED \
+ | APFS_FS_PFK \
+ | APFS_FS_UNKNOWN_200)
+
+#define APFS_FS_CRYPTOFLAGS (APFS_FS_UNENCRYPTED \
+ | APFS_FS_EFFACEABLE \
+ | APFS_FS_ONEKEY)
+
+/* Volume roles */
+#define APFS_VOLUME_ENUM_SHIFT 6
+#define APFS_VOL_ROLE_NONE 0x0000
+#define APFS_VOL_ROLE_SYSTEM 0x0001
+#define APFS_VOL_ROLE_USER 0x0002
+#define APFS_VOL_ROLE_RECOVERY 0x0004
+#define APFS_VOL_ROLE_VM 0x0008
+#define APFS_VOL_ROLE_PREBOOT 0x0010
+#define APFS_VOL_ROLE_INSTALLER 0x0020
+#define APFS_VOL_ROLE_DATA (1 << APFS_VOLUME_ENUM_SHIFT)
+#define APFS_VOL_ROLE_BASEBAND (2 << APFS_VOLUME_ENUM_SHIFT)
+#define APFS_VOL_ROLE_UPDATE (3 << APFS_VOLUME_ENUM_SHIFT)
+#define APFS_VOL_ROLE_XART (4 << APFS_VOLUME_ENUM_SHIFT)
+#define APFS_VOL_ROLE_HARDWARE (5 << APFS_VOLUME_ENUM_SHIFT)
+#define APFS_VOL_ROLE_BACKUP (6 << APFS_VOLUME_ENUM_SHIFT)
+#define APFS_VOL_ROLE_RESERVED_7 (7 << APFS_VOLUME_ENUM_SHIFT)
+#define APFS_VOL_ROLE_RESERVED_8 (8 << APFS_VOLUME_ENUM_SHIFT)
+#define APFS_VOL_ROLE_ENTERPRISE (9 << APFS_VOLUME_ENUM_SHIFT)
+#define APFS_VOL_ROLE_RESERVED_10 (10 << APFS_VOLUME_ENUM_SHIFT)
+#define APFS_VOL_ROLE_PRELOGIN (11 << APFS_VOLUME_ENUM_SHIFT)
+#define APFS_VOL_ROLES_VALID_MASK (APFS_VOL_ROLE_SYSTEM \
+ | APFS_VOL_ROLE_USER \
+ | APFS_VOL_ROLE_RECOVERY \
+ | APFS_VOL_ROLE_VM \
+ | APFS_VOL_ROLE_PREBOOT \
+ | APFS_VOL_ROLE_INSTALLER \
+ | APFS_VOL_ROLE_DATA \
+ | APFS_VOL_ROLE_BASEBAND \
+ | APFS_VOL_ROLE_UPDATE \
+ | APFS_VOL_ROLE_XART \
+ | APFS_VOL_ROLE_HARDWARE \
+ | APFS_VOL_ROLE_BACKUP \
+ | APFS_VOL_ROLE_RESERVED_7 \
+ | APFS_VOL_ROLE_RESERVED_8 \
+ | APFS_VOL_ROLE_ENTERPRISE \
+ | APFS_VOL_ROLE_RESERVED_10 \
+ | APFS_VOL_ROLE_PRELOGIN)
+
+/* Optional volume feature flags */
+#define APFS_FEATURE_DEFRAG_PRERELEASE 0x00000001LL
+#define APFS_FEATURE_HARDLINK_MAP_RECORDS 0x00000002LL
+#define APFS_FEATURE_DEFRAG 0x00000004LL
+#define APFS_FEATURE_STRICTATIME 0x00000008LL
+#define APFS_FEATURE_VOLGRP_SYSTEM_INO_SPACE 0x00000010LL
+
+#define APFS_SUPPORTED_FEATURES_MASK (APFS_FEATURE_DEFRAG \
+ | APFS_FEATURE_DEFRAG_PRERELEASE \
+ | APFS_FEATURE_HARDLINK_MAP_RECORDS \
+ | APFS_FEATURE_STRICTATIME \
+ | APFS_FEATURE_VOLGRP_SYSTEM_INO_SPACE)
+
+/* Read-only compatible volume feature flags */
+#define APFS_SUPPORTED_ROCOMPAT_MASK (0x0ULL)
+
+/* Incompatible volume feature flags */
+#define APFS_INCOMPAT_CASE_INSENSITIVE 0x00000001LL
+#define APFS_INCOMPAT_DATALESS_SNAPS 0x00000002LL
+#define APFS_INCOMPAT_ENC_ROLLED 0x00000004LL
+#define APFS_INCOMPAT_NORMALIZATION_INSENSITIVE 0x00000008LL
+#define APFS_INCOMPAT_INCOMPLETE_RESTORE 0x00000010LL
+#define APFS_INCOMPAT_SEALED_VOLUME 0x00000020LL
+#define APFS_INCOMPAT_PFK 0x00000040LL /* Made-up name */
+#define APFS_INCOMPAT_EXTENT_PREALLOC_FLAG 0x00000080LL /* Made-up name */
+#define APFS_INCOMPAT_SECONDARY_FSROOT 0x00000100LL /* Made-up name */
+
+#define APFS_SUPPORTED_INCOMPAT_MASK (APFS_INCOMPAT_CASE_INSENSITIVE \
+ | APFS_INCOMPAT_DATALESS_SNAPS \
+ | APFS_INCOMPAT_ENC_ROLLED \
+ | APFS_INCOMPAT_NORMALIZATION_INSENSITIVE \
+ | APFS_INCOMPAT_INCOMPLETE_RESTORE \
+ | APFS_INCOMPAT_SEALED_VOLUME \
+ | APFS_INCOMPAT_PFK \
+ | APFS_INCOMPAT_EXTENT_PREALLOC_FLAG \
+ | APFS_INCOMPAT_SECONDARY_FSROOT)
+
+#define APFS_MODIFIED_NAMELEN 32
+
+/*
+ * Structure containing information about a program that modified the volume
+ */
+struct apfs_modified_by {
+ u8 id[APFS_MODIFIED_NAMELEN];
+ __le64 timestamp;
+ __le64 last_xid;
+} __packed;
+
+/* Version constants for wrapped meta crypto state */
+#define APFS_WMCS_MAJOR_VERSION 5
+#define APFS_WMCS_MINOR_VERSION 0
+
+/* Protection classes */
+#define APFS_PROTECTION_CLASS_DIR_NONE 0 /* Inherits the directory's default */
+#define APFS_PROTECTION_CLASS_A 1
+#define APFS_PROTECTION_CLASS_B 2
+#define APFS_PROTECTION_CLASS_C 3
+#define APFS_PROTECTION_CLASS_D 4 /* No protection */
+#define APFS_PROTECTION_CLASS_F 6 /* No protection, nonpersistent key */
+
+/* Encryption identifiers */
+#define APFS_CRYPTO_SW_ID 4
+#define APFS_CRYPTO_RESERVED_5 5
+#define APFS_UNASSIGNED_CRYPTO_ID (~0ULL)
+
+/* Doc id index flags. I'm making up the names for now. */
+#define APFS_DOC_ID_HAS_PREV_TREE 0x00000001
+#define APFS_DOC_ID_UNKNOWN_02 0x00000002
+#define APFS_DOC_ID_UNKNOWN_04 0x00000004
+#define APFS_DOC_ID_UNKNOWN_08 0x00000008
+#define APFS_DOC_ID_UNKNOWN_10 0x00000010
+#define APFS_DOC_ID_VALID_FLAGS (APFS_DOC_ID_HAS_PREV_TREE \
+ | APFS_DOC_ID_UNKNOWN_02 \
+ | APFS_DOC_ID_UNKNOWN_04 \
+ | APFS_DOC_ID_UNKNOWN_08 \
+ | APFS_DOC_ID_UNKNOWN_10)
+
+/*
+ * Structure used to store the encryption state
+ */
+struct apfs_wrapped_meta_crypto_state {
+ __le16 major_version;
+ __le16 minor_version;
+ __le32 cpflags;
+ __le32 persistent_class;
+ __le32 key_os_version;
+ __le16 key_revision;
+ __le16 unused;
+} __packed;
+
+/*
+ * On-disk representation of a volume superblock
+ */
+struct apfs_superblock {
+/*00*/ struct apfs_obj_phys apfs_o;
+
+/*20*/ __le32 apfs_magic;
+ __le32 apfs_fs_index;
+
+/*28*/ __le64 apfs_features;
+ __le64 apfs_readonly_compatible_features;
+ __le64 apfs_incompatible_features;
+
+/*40*/ __le64 apfs_unmount_time;
+
+ __le64 apfs_fs_reserve_block_count;
+ __le64 apfs_fs_quota_block_count;
+ __le64 apfs_fs_alloc_count;
+
+/*60*/ struct apfs_wrapped_meta_crypto_state apfs_meta_crypto;
+
+/*74*/ __le32 apfs_root_tree_type;
+ __le32 apfs_extentref_tree_type;
+ __le32 apfs_snap_meta_tree_type;
+
+/*80*/ __le64 apfs_omap_oid;
+ __le64 apfs_root_tree_oid;
+ __le64 apfs_extentref_tree_oid;
+ __le64 apfs_snap_meta_tree_oid;
+
+/*A0*/ __le64 apfs_revert_to_xid;
+ __le64 apfs_revert_to_sblock_oid;
+
+/*B0*/ __le64 apfs_next_obj_id;
+
+/*B8*/ __le64 apfs_num_files;
+ __le64 apfs_num_directories;
+ __le64 apfs_num_symlinks;
+ __le64 apfs_num_other_fsobjects;
+ __le64 apfs_num_snapshots;
+
+/*E0*/ __le64 apfs_total_blocks_alloced;
+ __le64 apfs_total_blocks_freed;
+
+/*F0*/ char apfs_vol_uuid[UUID_SIZE];
+/*100*/ __le64 apfs_last_mod_time;
+
+ __le64 apfs_fs_flags;
+
+/*110*/ struct apfs_modified_by apfs_formatted_by;
+/*140*/ struct apfs_modified_by apfs_modified_by[APFS_MAX_HIST];
+
+/*2C0*/ u8 apfs_volname[APFS_VOLNAME_LEN];
+/*3C0*/ __le32 apfs_next_doc_id;
+
+ __le16 apfs_role;
+ __le16 reserved;
+
+/*3C8*/ __le64 apfs_root_to_xid;
+ __le64 apfs_er_state_oid;
+
+ __le64 apfs_cloneinfo_id_epoch;
+ __le64 apfs_cloneinfo_xid;
+
+ __le64 apfs_snap_meta_ext_oid;
+
+/*3F0*/ char apfs_volume_group_id[UUID_SIZE];
+
+/*400*/ __le64 apfs_integrity_meta_oid;
+
+ __le64 apfs_fext_tree_oid;
+/*410*/ __le32 apfs_fext_tree_type;
+
+ __le32 reserved_type;
+ __le64 reserved_oid;
+
+/*420*/ __le64 apfs_doc_id_index_xid;
+ __le32 apfs_doc_id_index_flags;
+ __le32 apfs_doc_id_tree_type;
+/*430*/ __le64 apfs_doc_id_tree_oid; /* Made-up name */
+ __le64 apfs_prev_doc_id_tree_oid;
+ __le64 apfs_doc_id_fixup_cursor;
+ __le64 apfs_sec_root_tree_oid;
+/*450*/ __le32 apfs_sec_root_tree_type;
+} __packed;
+
+/* Extended attributes constants */
+#define APFS_XATTR_MAX_EMBEDDED_SIZE 3804
+
+/* Extended attributes names */
+#define APFS_XATTR_NAME_SYMLINK "com.apple.fs.symlink"
+#define APFS_XATTR_NAME_COMPRESSED "com.apple.decmpfs"
+#define APFS_XATTR_NAME_RSRC_FORK "com.apple.ResourceFork"
+#define APFS_XATTR_NAME_SECURITY "com.apple.system.Security"
+#define APFS_XATTR_NAME_FINDER_INFO "com.apple.FinderInfo"
+
+/* Extended attributes flags */
+enum {
+ APFS_XATTR_DATA_STREAM = 0x00000001,
+ APFS_XATTR_DATA_EMBEDDED = 0x00000002,
+ APFS_XATTR_FILE_SYSTEM_OWNED = 0x00000004,
+ APFS_XATTR_RESERVED_8 = 0x00000008,
+ APFS_XATTR_UNKNOWN_10 = 0x00000010,
+};
+
+#define APFS_XATTR_VALID_FLAGS 0x0000001f
+
+/*
+ * Structure of the value of an extended attributes record
+ */
+struct apfs_xattr_val {
+ __le16 flags;
+ __le16 xdata_len;
+ u8 xdata[];
+} __packed;
+
+/*
+ * Structure used to store the data of an extended attributes record
+ */
+struct apfs_xattr_dstream {
+ __le64 xattr_obj_id;
+ struct apfs_dstream dstream;
+} __packed;
+
+/*
+ * Integrity metadata for a sealed volume
+ */
+struct apfs_integrity_meta_phys {
+ struct apfs_obj_phys im_o;
+
+ __le32 im_version;
+ __le32 im_flags;
+ __le32 im_hash_type;
+ __le32 im_root_hash_offset;
+ __le64 im_broken_xid;
+ __le64 im_reserved[9];
+} __packed;
+
+/*
+ * Version numbers for the integrity metadata structure
+ */
+enum {
+ APFS_INTEGRITY_META_VERSION_INVALID = 0,
+ APFS_INTEGRITY_META_VERSION_1 = 1,
+ APFS_INTEGRITY_META_VERSION_2 = 2,
+ APFS_INTEGRITY_META_VERSION_HIGHEST = APFS_INTEGRITY_META_VERSION_2
+};
+
+/* Flags used by integrity metadata */
+#define APFS_SEAL_BROKEN (1U << 0)
+
+/*
+ * Constants used to identify hash algorithms
+ */
+enum {
+ APFS_HASH_INVALID = 0,
+ APFS_HASH_SHA256 = 0x1,
+ APFS_HASH_SHA512_256 = 0x2,
+ APFS_HASH_SHA384 = 0x3,
+ APFS_HASH_SHA512 = 0x4,
+
+ APFS_HASH_MIN = APFS_HASH_SHA256,
+ APFS_HASH_MAX = APFS_HASH_SHA512,
+ APFS_HASH_DEFAULT = APFS_HASH_SHA256,
+};
+
+#define APFS_HASH_CCSHA256_SIZE 32
+#define APFS_HASH_CCSHA512_256_SIZE 32
+#define APFS_HASH_CCSHA384_SIZE 48
+#define APFS_HASH_CCSHA512_SIZE 64
+
+#define APFS_HASH_MAX_SIZE 64
+
+/*
+ * Structure of a key in a fext tree
+ */
+struct apfs_fext_tree_key {
+ __le64 private_id;
+ __le64 logical_addr;
+} __packed;
+
+/*
+ * Structure of a value in a fext tree
+ */
+struct apfs_fext_tree_val {
+ __le64 len_and_flags;
+ __le64 phys_block_num;
+} __packed;
+
+/*
+ * Structure of the key for a file info record
+ */
+struct apfs_file_info_key {
+ struct apfs_key_header hdr;
+ __le64 info_and_lba;
+} __packed;
+
+#define APFS_FILE_INFO_LBA_MASK 0x00ffffffffffffffULL
+#define APFS_FILE_INFO_TYPE_MASK 0xff00000000000000ULL
+#define APFS_FILE_INFO_TYPE_SHIFT 56
+
+/*
+ * A hash of file data
+ */
+struct apfs_file_data_hash_val {
+ __le16 hashed_len;
+ u8 hash_size;
+ u8 hash[];
+} __packed;
+
+#define APFS_FILE_INFO_DATA_HASH 1
+
+/*
+ * Structure of the value for a file info record
+ */
+struct apfs_file_info_val {
+ union {
+ struct apfs_file_data_hash_val dhash;
+ };
+} __packed;
+
+#define APFS_BTREE_NODE_HASH_SIZE_MAX 64
+
+/*
+ * Structure of the value of an index record for a hashed catalog tree
+ */
+struct apfs_btn_index_node_val {
+ __le64 binv_child_oid;
+ /*
+ * The reference seems to be wrong about the hash size, at least for
+ * SHA-256. TODO: check what happens with other hash functions.
+ */
+ u8 binv_child_hash[APFS_HASH_CCSHA256_SIZE];
+} __packed;
+
+/*
+ * Compressed file header
+ */
+struct apfs_compress_hdr {
+ __le32 signature;
+ __le32 algo;
+ __le64 size;
+} __packed;
+
+#define APFS_COMPRESS_ZLIB_ATTR 3
+#define APFS_COMPRESS_ZLIB_RSRC 4
+#define APFS_COMPRESS_LZVN_ATTR 7
+#define APFS_COMPRESS_LZVN_RSRC 8
+#define APFS_COMPRESS_PLAIN_ATTR 9
+#define APFS_COMPRESS_PLAIN_RSRC 10
+#define APFS_COMPRESS_LZFSE_ATTR 11
+#define APFS_COMPRESS_LZFSE_RSRC 12
+#define APFS_COMPRESS_LZBITMAP_ATTR 13
+#define APFS_COMPRESS_LZBITMAP_RSRC 14
+
+struct apfs_compress_rsrc_hdr {
+ __be32 data_offs;
+ __be32 mgmt_offs;
+ __be32 data_size;
+ __be32 mgmt_size;
+} __packed;
+
+#define APFS_COMPRESS_BLOCK 0x10000
+
+struct apfs_compress_rsrc_data {
+ __le32 unknown;
+ __le32 num;
+ struct apfs_compress_rsrc_block {
+ __le32 offs;
+ __le32 size;
+ } __packed block[];
+} __packed;
+
+#define APFS_FUSION_TIER2_DEVICE_BYTE_ADDR 0x4000000000000000ULL
+
+/*
+ * TODO: this is a placeholder, create some snapshots with the official
+ * implementation to find the actual limit.
+ */
+#define APFS_SNAP_MAX_NAMELEN 255
+
+/*
+ * Structure of the value of a snapshot metadata record
+ */
+struct apfs_snap_metadata_val {
+ __le64 extentref_tree_oid;
+ __le64 sblock_oid;
+ __le64 create_time;
+ __le64 change_time;
+ __le64 inum;
+ __le32 extentref_tree_type;
+ __le32 flags;
+ __le16 name_len;
+ u8 name[];
+} __packed;
+
+/* Snapshot metadata record flags */
+enum {
+ APFS_SNAP_META_PENDING_DATALESS = 0x00000001,
+ APFS_SNAP_MERGE_IN_PROGRESS = 0x00000002,
+};
+
+/*
+ * Structure of the value of a snapshot name record
+ */
+struct apfs_snap_name_val {
+ __le64 snap_xid;
+} __packed;
+
+/*
+ * Structure of the extended snapshot metadata
+ */
+struct apfs_snap_meta_ext {
+ struct apfs_obj_phys sme_o;
+
+ __le32 sme_version;
+ __le32 sme_flags;
+ __le64 sme_snap_xid;
+ char sme_uuid[UUID_SIZE];
+ __le64 sme_token;
+} __packed;
+
+#define APFS_OBJECT_TYPE_KEYBAG 0x6b657973 /* Spells 'syek' */
+
+#define APFS_VOL_KEYBAG_ENTRY_MAX_SIZE 512
+#define APFS_FV_PERSONAL_RECOVERY_KEY_UUID "EBC6C064-0000-11AA-AA11-00306543ECAC"
+
+/* Keybag entry types */
+enum {
+ KB_TAG_UNKNOWN = 0,
+ KB_TAG_RESERVED_1 = 1,
+
+ KB_TAG_VOLUME_KEY = 2,
+ KB_TAG_VOLUME_UNLOCK_RECORDS = 3,
+ KB_TAG_VOLUME_PASSPHRASE_HINT = 4,
+
+ KB_TAG_WRAPPING_M_KEY = 5,
+ KB_TAG_VOLUME_M_KEY = 6,
+
+ KB_TAG_RESERVED_F8 = 0xF8
+};
+
+/*
+ * Structure of a single entry in the keybag
+ */
+struct apfs_keybag_entry {
+ char ke_uuid[UUID_SIZE];
+ __le16 ke_tag;
+ __le16 ke_keylen;
+ __le32 padding;
+ u8 ke_keydata[];
+} __packed;
+
+#define APFS_KEYBAG_VERSION 2
+
+/*
+ * Structure of the locker in the keybag
+ */
+struct apfs_kb_locker {
+ __le16 kl_version;
+ __le16 kl_nkeys;
+ __le32 kl_nbytes;
+ __le64 padding;
+ struct apfs_keybag_entry kl_entries[];
+} __packed;
+
+#endif /* _APFS_RAW_H */

--
2.48.1