From patchwork Fri Mar 14 21:57:49 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ethan Carter Edwards X-Patchwork-Id: 14017539 Received: from mout-p-102.mailbox.org (mout-p-102.mailbox.org [80.241.56.152]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 85DF41FE44A; Fri, 14 Mar 2025 21:58:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=80.241.56.152 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741989522; cv=none; b=BXSZC7KyWFb9lZre+Gl4Hjtgp+UPqHeeLqC3ZDRR6Q8wbPS79sTomOC4vlJcloQQFWbccTmWE5TxaeF2o+0gEo67BD6iSS4lX0XLAtpMFRdVXuQUprnPhb3GMf+ZPFI8r5FnUZJq1MTTAK4VkXE28S73nlgZon298IaVg5zltVg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741989522; c=relaxed/simple; bh=WA77y/TkoQeHIT/2P1Tc55iU91UoDdmatzs2t0Cz46s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fFnOCgPFbU3z+u/FSIf2pWRBBi/+BegkmQG6P/0riix/rQMTuEU8RM63AN+WVUCYdXNBjp2aO7exThvtTZENJh/OI/9KYtO7LBGMFIUzRO5sS/nNmwUbtSZrW1+rM001KpKhjRtNV9fwM0zHHFMkyYlKxbZAljbxBgOimmRbWJo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ethancedwards.com; spf=pass smtp.mailfrom=ethancedwards.com; dkim=pass (2048-bit key) header.d=ethancedwards.com header.i=@ethancedwards.com header.b=jRN00Y9b; arc=none smtp.client-ip=80.241.56.152 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=ethancedwards.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ethancedwards.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ethancedwards.com header.i=@ethancedwards.com header.b="jRN00Y9b" Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:b231:465::2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-102.mailbox.org (Postfix) with ESMTPS id 4ZDytM5dFDz9sd5; Fri, 14 Mar 2025 22:58:35 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ethancedwards.com; s=MBO0001; t=1741989515; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Jea3sbJgUxmSgM13kQyuc4qCeB7pA0D3rMuT0ZGZpP8=; b=jRN00Y9bi8ycFlG556o4bP2sY0uZBHKty00/8BYIjq+qKJziiEOLAQJcexMm992qhlefZJ STBj/yFbxegzqDkACFTbmTwe9dcsf+xs5FcLf35fROsS/CYDqBIRHwBruC+ia1Ws0TZ1Re VvqbByonl8RVT/eCmjoKhAXO6EQRmDENhAvJVF8BOQY2FJo7mbY2bQujevOg+JlgpfJUfn DEKg1X+Y2bG459pjOcbcBoAf+Eadqxgyj2Je/i0P/eIAZp8hua6OzrQYIONTSvyaPmBdZv hxBypacIaIX0fpAmC0CJe5bHsFDQd1HIybY7dyM75hRVI72+2vKGGf+XuQwDLA== From: Ethan Carter Edwards Date: Fri, 14 Mar 2025 17:57:49 -0400 Subject: [PATCH RFC 3/8] staging: apfs: init apfs_raw.h to handle on-disk structures Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250314-apfs-v1-3-ddfaa6836b5c@ethancedwards.com> References: <20250314-apfs-v1-0-ddfaa6836b5c@ethancedwards.com> In-Reply-To: <20250314-apfs-v1-0-ddfaa6836b5c@ethancedwards.com> To: Greg Kroah-Hartman , tytso@mit.edu Cc: ernesto.mnd.fernandez@gmail.com, dan.carpenter@linaro.org, sven@svenpeter.dev, ernesto@corellium.com, gargaditya08@live.com, willy@infradead.org, asahi@lists.linux.dev, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-staging@lists.linux.dev, Ethan Carter Edwards X-Developer-Signature: v=1; a=openpgp-sha256; l=45088; i=ethan@ethancedwards.com; h=from:subject:message-id; bh=WA77y/TkoQeHIT/2P1Tc55iU91UoDdmatzs2t0Cz46s=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0o0bkp2QXk4ekFKWGJEOXFoNThlVGp6e GhQcXlVeHBGOVpWbTdDcEozWW05UjRQMEY0dDlxYUN1Yzc3NE1yCnRYLzdSbnEzTmk4T3ViYi81 cStPVWhZR01TNEdXVEZGbHY4NXlta1BOV2NvN1B6cjBnUXpoNVVKWkFnREY2Y0EKVEdUelo0Wi9 ka0hCenk3c1QzdDUvckh5blBEcG11cXNIYWEvT2RZODRoUU5YMTNyWFZJNWo1SGhodmRrL3NtQg p4L3dhMy81ZGt0UlZVWDV4Z2lqSDlPcUd5bnZWZVdzV2I3dklBd0QzQWs5aAo9TzcrcwotLS0tL UVORCBQR1AgTUVTU0FHRS0tLS0tCg== X-Developer-Key: i=ethan@ethancedwards.com; a=openpgp; fpr=2E51F61839D1FA947A7300C234C04305D581DBFE X-Rspamd-Queue-Id: 4ZDytM5dFDz9sd5 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 --- 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 + * Copyright (C) 2025 Ethan Carter Edwards + * + * Definitions for all on-disk data structures. + */ + +#ifndef _APFS_RAW_H +#define _APFS_RAW_H + +#include +#include + +/* 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 */