diff --git a/notes.md b/notes.md new file mode 100644 index 0000000..e7a98c5 --- /dev/null +++ b/notes.md @@ -0,0 +1,157 @@ +# §3 Objects + + ## Object Types + + - [x] OBJECT_TYPE_ER_RECOVERY_BLOCK + - [x] OBJECT_TYPE_SNAP_META_EXT + - [x] OBJECT_TYPE_INTEGRITY_META + - [x] OBJECT_TYPE_FEXT_TREE + - [x] OBJECT_TYPE_RESERVED_20 + - [x] OBJECT_TYPE_MEDIA_KEYBAG + +# §5 Container + + ## `nx_superblock_t` + + - [x] nx_newest_mounted_version + - [x] nx_mkb_locker + +# §6 Object Maps + + ## Object Map Flags + + - [x] OMAP_VALID_FLAGS + +# §7 Volumes + + ## `apfs_superblock_t` + + - [x] apfs_cloneinfo_id_epoch + - [x] apfs_cloneinfo_xid + - [x] apfs_snap_meta_ext_oid + - [x] apfs_volume_group_id + - [x] apfs_integrity_meta_oid + - [x] apfs_fext_tree_oid + - [x] apfs_fext_tree_type + - [x] reserved_type + - [x] reserved_oid + + ## Volume Flags + + - [x] APFS_FS_RESERVED_80 + - [x] APFS_FS_RESERVED_100 + + ## Volume Roles + + - [x] APFS_VOL_ROLE_UPDATE + - [x] APFS_VOL_ROLE_XART + - [x] APFS_VOL_ROLE_HARDWARE + - [x] APFS_VOL_ROLE_BACKUP + - [x] APFS_VOL_ROLE_RESERVED_7 + - [x] APFS_VOL_ROLE_RESERVED_8 + - [x] APFS_VOL_ROLE_ENTERPRISE + - [x] APFS_VOL_ROLE_RESERVED_10 + - [x] APFS_VOL_ROLE_PRELOGIN + + ## Optional Volume Feature Flags + + - [x] APFS_FEATURE_STRICTATIME + - [x] APFS_FEATURE_VOLGRP_SYSTEM_INO_SPACE + + ## Incompatible Volume Feature Flags + + - [x] APFS_INCOMPAT_INCOMPLETE_RESTORE + - [x] APFS_INCOMPAT_SEALED_VOLUME + +# §8 File-System Objects + + ## `j_key_t` + + - [x] SYSTEM_OBJ_ID_MARK + + ## `j_inode_val_t` + + - [x] uncompressed_size + +# §9 File-System Constants + + ## `j_obj_types` + + - [x] APFS_TYPE_FILE_INFO + + ## `j_inode_flags` + + - [x] INODE_FAST_PROMOTE + - [x] INODE_HAS_UNCOMPRESSED_SIZE + - [x] INODE_IS_PURGEABLE + - [x] INODE_WANTS_TO_BE_PURGEABLE + - [x] INODE_IS_SYNC_ROOT + - [x] INODE_SNAPSHOT_COW_EXEMPTION + + ## Inode Numbers + + - [x] PURGEABLE_DIR_INO_NUM + - [x] UNIFIED_ID_SPACE_MARK + + ## Extended Attributes Constants + + - [x] FIRMLINK_EA_NAME + - [x] APFS_COW_EXEMPT_COUNT_NAME + +# §11 Extended Fields + + ## Extended-Field Types + + - [x] INO_EXT_TYPE_PURGEABLE_FLAGS + - [x] INO_EXT_TYPE_ORIG_SYNC_ROOT_ID + +# §13 Snapshot Metadata + + ## `snap_meta_ext_obj_phys_t` + + - [x] *New datatype* `snap_meta_ext_obj_phys_t` + + ## `snap_meta_ext_t` + + - [x] *New datatype* `snap_meta_ext_t` + +# §14 B-Trees + + ## `btn_index_node_val_t` + + - [x] *New datatype* `btn_index_node_val_t` + + ## B-Tree Flags + + - [x] BTREE_HASHED + - [x] BTREE_NOHEADER + + ## B-Tree Node Flags + + - [x] BTNODE_HASHED + - [x] BTNODE_NOHEADER + +# §15 Encryption + + ## Protection Classes + + - [x] PROTECTION_CLASS_M + + ## Encryption Identifiers + + - [x] APFS_UNASSIGNED_CRYPTO_ID + + ## Keybag Tags + + - [x] KB_TAG_WRAPPING_M_KEY + - [x] KB_TAG_VOLUME_M_KEY + +# §16 Sealed Volumes + +- [x] *New chapter* Sealed Volumes + +# §17 Space Manager + + ## `spaceman_free_queue_entry_t` + + - [x] *New datatype* `spaceman_free_queue_entry_t` diff --git a/src/apfs/string/btree.c b/src/apfs/string/btree.c index e7b2b77..21d656e 100644 --- a/src/apfs/string/btree.c +++ b/src/apfs/string/btree.c @@ -28,20 +28,22 @@ char* get_btn_flags_string(btree_node_phys_t* btn) { char* default_string = "(none)"; size_t default_string_len = strlen(default_string); - uint8_t NUM_FLAGS = 4; - + uint8_t NUM_FLAGS = 6; uint16_t flag_constants[] = { BTNODE_ROOT, BTNODE_LEAF, BTNODE_FIXED_KV_SIZE, + BTNODE_HASHED, + BTNODE_NOHEADER, BTNODE_CHECK_KOFF_INVAL, }; - char* flag_strings[] = { "Root node", "Leaf node", "Fixed size for keys and values", - "In transient state --- should never appear on disk" + "Contains child node hashes", + "Doesn't have an object header", + "In transient state (key offsets are invalid) --- should never appear on disk" }; size_t max_mem_required = 0; @@ -102,7 +104,7 @@ char* get_bt_info_flags_string(btree_info_t* bt_info) { char* default_string = " - No flags are set\n"; size_t default_string_len = strlen(default_string); - uint8_t NUM_FLAGS = 7; + uint8_t NUM_FLAGS = 9; uint16_t flag_constants[] = { BTREE_UINT64_KEYS, @@ -112,6 +114,8 @@ char* get_bt_info_flags_string(btree_info_t* bt_info) { BTREE_PHYSICAL, BTREE_NONPERSISTENT, BTREE_KV_NONALIGNED, + BTREE_HASHED, + BTREE_NOHEADER, }; char* flag_strings[] = { @@ -122,6 +126,8 @@ char* get_bt_info_flags_string(btree_info_t* bt_info) { "Child nodes are referred to using Physical OIDs", "This B-tree does not persist across unmounts", "8-byte alignment of keys and values is not required", + "Non-leaf nodes store a hash of their child nodes", + "Nodes don't have object headers", }; size_t max_mem_required = 0; diff --git a/src/apfs/string/fs.c b/src/apfs/string/fs.c index 62ab3de..2d9165a 100644 --- a/src/apfs/string/fs.c +++ b/src/apfs/string/fs.c @@ -28,18 +28,22 @@ char* get_apfs_features_string(apfs_superblock_t* apsb) { char* default_string = "- No volume feature flags are set.\n"; size_t default_string_len = strlen(default_string); - const int NUM_FLAGS = 3; + const int NUM_FLAGS = 5; uint64_t flag_constants[] = { APFS_FEATURE_DEFRAG_PRERELEASE, APFS_FEATURE_HARDLINK_MAP_RECORDS, APFS_FEATURE_DEFRAG, + APFS_FEATURE_STRICTATIME, + APFS_FEATURE_VOLGRP_SYSTEM_INO_SPACE, }; char* flag_strings[] = { "Reserved --- To avoid data corruption, this flag must not be set; this flag enabled a prerelease version of the defragmentation system in macOS 10.13 versions. Itʼs ignored by macOS 10.13.6 and later.", "This volume has hardlink map records.", "Defragmentation is supported.", + "File access times are updated every time a file is read.", + "This volume supports mounting a system and data volume as a single user-visible volume.", }; // Allocate sufficient memory for the result string @@ -168,13 +172,16 @@ char* get_apfs_incompatible_features_string(apfs_superblock_t* apsb) { char* default_string = "- No backward-incompatible volume feature flags are set.\n"; size_t default_string_len = strlen(default_string); - const int NUM_FLAGS = 4; + const int NUM_FLAGS = 7; uint64_t flag_constants[] = { 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_RESERVED_40, }; char* flag_strings[] = { @@ -182,6 +189,9 @@ char* get_apfs_incompatible_features_string(apfs_superblock_t* apsb) { "At least one snapshot with no data exists for this volume.", "This volume's encryption has changed keys at least once.", "Filenames on this volume are normalization insensitive.", + "This volume is being restored, or a restore operation to this volume was uncleanly aborted.", + "This volume is sealed (cannot be modified).", + "Reserved flag (0x40).", }; // Allocate sufficient memory for the result string @@ -243,7 +253,7 @@ char* get_apfs_fs_flags_string(apfs_superblock_t* apsb) { char* default_string = "- No flags are set.\n"; size_t default_string_len = strlen(default_string); - const int NUM_FLAGS = 7; + const int NUM_FLAGS = 9; uint64_t flag_constants[] = { APFS_FS_UNENCRYPTED, @@ -253,6 +263,8 @@ char* get_apfs_fs_flags_string(apfs_superblock_t* apsb) { APFS_FS_SPILLEDOVER, APFS_FS_RUN_SPILLOVER_CLEANER, APFS_FS_ALWAYS_CHECK_EXTENTREF, + APFS_FS_RESERVED_80, + APFS_FS_RESERVED_100, }; char* flag_strings[] = { @@ -263,6 +275,8 @@ char* get_apfs_fs_flags_string(apfs_superblock_t* apsb) { "Volume has run out of allocated space on SSD, so has spilled over to other drives.", "Volume has spilled over and spillover cleaner must be run.", "When deciding whether to overwrite a file extent, always consult the extent reference tree.", + "Reserved flag (0x80).", + "Reserved flag (0x100).", }; // Allocate sufficient memory for the result string @@ -310,8 +324,8 @@ char* get_apfs_fs_flags_string(apfs_superblock_t* apsb) { } /** - * Get a human-readable string that lists the role flags that are - * set on a given APFS volume superblock. + * Get a human-readable string describing the role of a given APFS volume + * superblock. * * apsb: A pointer to the APFS volume superblock in question. * @@ -321,13 +335,11 @@ char* get_apfs_fs_flags_string(apfs_superblock_t* apsb) { */ char* get_apfs_role_string(apfs_superblock_t* apsb) { // String to use if no flags are set - char* default_string = "- This volume has no defined roles\n"; - size_t default_string_len = strlen(default_string); + char* default_string = "(unknown role) (role field value %#llx)"; - const int NUM_FLAGS = 9; - - // `APFS_ROLE_NONE` (0x0) is intentionally ommitted from this array. - uint64_t flag_constants[] = { + const int NUM_ROLES = 18; + uint64_t role_constants[] = { + APFS_VOL_ROLE_NONE, APFS_VOL_ROLE_SYSTEM, APFS_VOL_ROLE_USER, APFS_VOL_ROLE_RECOVERY, @@ -336,29 +348,44 @@ char* get_apfs_role_string(apfs_superblock_t* apsb) { APFS_VOL_ROLE_INSTALLER, APFS_VOL_ROLE_DATA, APFS_VOL_ROLE_BASEBAND, - APFS_VOL_ROLE_RESERVED_200, + 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, }; - - char* flag_strings[] = { - "Root volume (contains a root directory for the system)", - "Home volume (contains users' home directories)", - "Recovery volume (contains a recovery system)", - "Swap volume (used as swap space for virtual memory)", - "Preboot volume (contains files needed to boot from an encrypted volumes)", - "Installer volume (used by the OS installer)", - "Data volume (contains mutable data)", - "Baseband volume (sed by the radio firmware)", - "Reserved flag (0x200)", + char* role_strings[] = { + "(no role)", + "System (contains a root directory for the system)", + "User (contains users' home directories)", + "Recovery (contains a recovery system)", + "Virtual memory (used as swap space for virtual memory)", + "Preboot (contains files needed to boot from an encrypted volumes)", + "Installer (used by the OS installer)", + "Data (contains mutable data)", + "Baseband (used by the radio firmware)", + "Update (used by the software update mechanism)", + "xART (used to manage OS access to secure user data", + "Hardware (used for firmware data)", + "Backup (used by Time Machine to store backups)", + "Reserved role 7 (Sidecar?) (role field value 0x1c0)", + "Reserved role 8 (role field value 0x200)", + "Enterprise (used to store enterprise-managed data)", + "Reserved role 10 (role field value 0x280)", + "Pre-login (used to store system data used before login)", }; // Allocate sufficient memory for the result string - size_t max_mem_required = 0; - for (int i = 0; i < NUM_FLAGS; i++) { - max_mem_required += strlen(flag_strings[i]) + 3; - // `+ 3` accounts for prepending "- " and appending "\n" to each string - } - if (max_mem_required < default_string_len) { - max_mem_required = default_string_len; + size_t max_mem_required = strlen(default_string) + 1; // `+1` accounts for format specifier "%#llx" becoming up to 6 characters + for (int i = 0; i < NUM_ROLES; i++) { + size_t role_string_length = strlen(role_strings[i]); + if (max_mem_required < role_string_length) { + max_mem_required = role_string_length; + } } max_mem_required++; // Make room for terminating NULL byte @@ -368,28 +395,22 @@ char* get_apfs_role_string(apfs_superblock_t* apsb) { exit(-1); } - char* cursor = result_string; + // Make `result_string` an empty string so that we can easily test the + // case that no role matches. + *result_string = '\0'; - // Go through possible flags, adding corresponding string to result if - // that flag is set. - for (int i = 0; i < NUM_FLAGS; i++) { - if (apsb->apfs_role & flag_constants[i]) { - *cursor++ = '-'; - *cursor++ = ' '; - memcpy(cursor, flag_strings[i], strlen(flag_strings[i])); - cursor += strlen(flag_strings[i]); - *cursor++ = '\n'; + for (int i = 0; i < NUM_ROLES; i++) { + if (apsb->apfs_role == role_constants[i]) { + memcpy(result_string, role_strings[i], strlen(role_strings[i]) + 1); + break; } } - if (cursor == result_string) { - // No strings were added, so it must be that no flags are set. - memcpy(cursor, default_string, default_string_len); - cursor += default_string_len; + // If no role matches, use the default string. + if (strlen(result_string) == 0) { + snprintf(result_string, max_mem_required, default_string, apsb->apfs_role); } - *cursor = '\0'; - // Free up excess allocated memory. result_string = realloc(result_string, strlen(result_string) + 1); return result_string; @@ -406,7 +427,7 @@ void print_apfs_superblock(apfs_superblock_t* apsb) { printf("\n"); char magic_string[] = { - (char)apsb->apfs_magic, + (char)(apsb->apfs_magic), (char)(apsb->apfs_magic >> 8), (char)(apsb->apfs_magic >> 16), (char)(apsb->apfs_magic >> 24), @@ -417,9 +438,14 @@ void print_apfs_superblock(apfs_superblock_t* apsb) { printf("\n"); printf("Volume name: ### %s ###\n", apsb->apfs_volname); + + char* tmp_string = get_apfs_role_string(apsb); + printf("Role: %s", tmp_string); + free(tmp_string); + printf("\n"); - char* tmp_string = get_apfs_fs_flags_string(apsb); + tmp_string = get_apfs_fs_flags_string(apsb); printf("Flags:\n%s", tmp_string); free(tmp_string); @@ -434,10 +460,6 @@ void print_apfs_superblock(apfs_superblock_t* apsb) { tmp_string = get_apfs_incompatible_features_string(apsb); printf("Backward-incompatible features:\n%s", tmp_string); free(tmp_string); - - tmp_string = get_apfs_role_string(apsb); - printf("Roles:\n%s", tmp_string); - free(tmp_string); printf("\n"); @@ -532,5 +554,12 @@ void print_apfs_superblock(apfs_superblock_t* apsb) { * - apfs_modified_by * - apfs_root_to_xid * - apfs_er_state_oid + * - apfs_cloneinfo_id_epoch + * - apfs_cloneinfo_xid + * - apfs_snap_meta_ext_oid + * - apfs_volume_group_id + * - apfs_integrity_meta_oid + * - apfs_fext_tree_oid + * - apfs_fext_tree_type */ } diff --git a/src/apfs/string/j.c b/src/apfs/string/j.c index 083f21b..b3a1037 100644 --- a/src/apfs/string/j.c +++ b/src/apfs/string/j.c @@ -95,7 +95,7 @@ char* get_j_inode_internal_flags_string(uint64_t internal_flags) { char* default_string = "- No internal flags are set.\n"; size_t default_string_len = strlen(default_string); - const int NUM_FLAGS = 17; + const int NUM_FLAGS = 23; uint64_t flag_constants[] = { INODE_IS_APFS_PRIVATE, @@ -115,6 +115,12 @@ char* get_j_inode_internal_flags_string(uint64_t internal_flags) { INODE_HAS_RSRC_FORK, INODE_NO_RSRC_FORK, INODE_ALLOCATION_SPILLEDOVER, + INODE_FAST_PROMOTE, + INODE_HAS_UNCOMPRESSED_SIZE, + INODE_IS_PURGEABLE, + INODE_WANTS_TO_BE_PURGEABLE, + INODE_IS_SYNC_ROOT, + INODE_SNAPSHOT_COW_EXEMPTION, }; char* flag_strings[] = { @@ -135,6 +141,12 @@ char* get_j_inode_internal_flags_string(uint64_t internal_flags) { "Has a resource fork", "Has no resource fork", "Fusion drive: file content spilled over from preferred storage tier/device", + "Scheduled for promotion from slow storage to fast storage", + "Uncompressed size is stored in the inode", + "Will be deleted at the next purge", + "Should become purgeable when its link count drops to 1", + "Is the root of a sync hierarchy for `fileproviderd`", + "Exempt from copy-on-write behavior if the data is part of a snapshot", }; // Allocate sufficient memory for the result string @@ -261,6 +273,21 @@ void print_j_inode_val(j_inode_val_t* val, bool has_xfields) { printf("Private ID: 0x%llx\n", val->private_id); printf("\n"); + char* tmp_string = NULL; + if (val->internal_flags & INODE_HAS_UNCOMPRESSED_SIZE) { + if (asprintf(tmp_string, "%llu bytes", val->uncompressed_size) < 0) { + fprintf(stderr, "ABORT: %s:%d: call to asprintf() couldn't allocate sufficient memory", __func__, __LINE__); + exit(-1); + } + } else { + if (asprintf(tmp_string, "(unknown)") < 0) { + fprintf(stderr, "ABORT: %s:%d: call to asprintf() couldn't allocate sufficient memory", __func__, __LINE__); + exit(-1); + } + } + printf("Uncompressed size: %s\n", tmp_string); + free(tmp_string); + time_t timestamp = val->create_time / 1000000000; printf("Creation time: %s", ctime(×tamp)); timestamp = val->mod_time / 1000000000; @@ -279,7 +306,7 @@ void print_j_inode_val(j_inode_val_t* val, bool has_xfields) { printf("Mode: %s\n", j_inode_mode_to_string(val->mode)); printf("\n"); - char* tmp_string = get_j_inode_internal_flags_string(val->internal_flags); + tmp_string = get_j_inode_internal_flags_string(val->internal_flags); printf("Internal flags:\n%s", tmp_string); printf("\n"); free(tmp_string); @@ -289,12 +316,9 @@ void print_j_inode_val(j_inode_val_t* val, bool has_xfields) { printf("\n"); free(tmp_string); - printf("No. extended fields: "); - if (!has_xfields) { - printf("0\n"); - return; - } - printf("%u\n", ((xf_blob_t*)(val->xfields))->xf_num_exts); + printf("Number of extended fields: %u\n", + has_xfields ? ((xf_blob_t*)(val->xfields))->xf_num_exts : 0 + ); // TODO: Print actual details of extended fields/attributes } diff --git a/src/apfs/string/nx.c b/src/apfs/string/nx.c index a5610ef..f21ac43 100644 --- a/src/apfs/string/nx.c +++ b/src/apfs/string/nx.c @@ -304,10 +304,35 @@ char* get_nx_flags_string(nx_superblock_t* nxsb) { void print_nx_superblock(nx_superblock_t* nxsb) { print_obj_phys(nxsb); // `nxsb` is equivalent to `&(nxsb->nx_o)`. - printf("Keybag location: starts at %#llx, spans %#llx blocks\n", nxsb->nx_keylocker.pr_start_paddr, nxsb->nx_keylocker.pr_block_count); + printf("Keybag location: "); + if (nxsb->nx_keylocker.pr_block_count == 0) { + printf("none (spans 0 blocks)\n"); + } else { + printf( + "first block %#llx, spans %llu (%#llx) blocks (last block %#llx)\n", + nxsb->nx_keylocker.pr_start_paddr, + nxsb->nx_keylocker.pr_block_count, + nxsb->nx_keylocker.pr_block_count, + nxsb->nx_keylocker.pr_start_paddr + nxsb->nx_keylocker.pr_block_count - 1 + ); + } + + printf("Media keybag location: "); + if (nxsb->nx_mkb_locker.pr_block_count == 0) { + printf("none (spans 0 blocks)\n"); + } else { + printf( + "first block %#llx, spans %llu (%#llx) blocks (last block %#llx)\n", + nxsb->nx_mkb_locker.pr_start_paddr, + nxsb->nx_mkb_locker.pr_block_count, + nxsb->nx_mkb_locker.pr_block_count, + nxsb->nx_mkb_locker.pr_start_paddr + nxsb->nx_mkb_locker.pr_block_count - 1 + ); + } + char magic_string[] = { - (char)nxsb->nx_magic, + (char)(nxsb->nx_magic), (char)(nxsb->nx_magic >> 8), (char)(nxsb->nx_magic >> 16), (char)(nxsb->nx_magic >> 24), @@ -315,8 +340,22 @@ void print_nx_superblock(nx_superblock_t* nxsb) { }; printf("Magic string: %s\n", magic_string); + printf( + "Latest version of Apple APFS software that mounted this container: " + "%llu.%llu.%llu.%llu.%llu\n", + + nxsb->nx_newest_mounted_version >> 40, + (nxsb->nx_newest_mounted_version >> 30) & ~(~0ULL << 10), + (nxsb->nx_newest_mounted_version >> 20) & ~(~0ULL << 10), + (nxsb->nx_newest_mounted_version >> 10) & ~(~0ULL << 10), + (nxsb->nx_newest_mounted_version) & ~(~0ULL << 10) + ); + printf("Block size: %u bytes\n", nxsb->nx_block_size); - printf("Block count: %llu\n", nxsb->nx_block_count); + printf("Block count: %llu (last block %#llx)\n", + nxsb->nx_block_count, + nxsb->nx_block_count - 1 + ); char* features_string = get_nx_features_string(nxsb); printf("Supported features:\n%s", features_string); diff --git a/src/apfs/string/object.c b/src/apfs/string/object.c index ff74908..4c7fbe6 100644 --- a/src/apfs/string/object.c +++ b/src/apfs/string/object.c @@ -126,7 +126,7 @@ char* get_o_type_string(uint32_t o_type) { // This string is a legal `sprintf()` format string. char* default_string = "Unknown type (0x%08x) --- perhaps this type was introduced in a later version of APFS than that published on 2019-02-27."; - size_t NUM_FLAGS = 22; + size_t NUM_FLAGS = 26; uint32_t flag_constants[] = { OBJECT_TYPE_NX_SUPERBLOCK, OBJECT_TYPE_BTREE, @@ -146,6 +146,10 @@ char* get_o_type_string(uint32_t o_type) { OBJECT_TYPE_ER_STATE, OBJECT_TYPE_GBITMAP, OBJECT_TYPE_GBITMAP_BLOCK, + OBJECT_TYPE_ER_RECOVERY_BLOCK, + OBJECT_TYPE_SNAP_META_EXT, + OBJECT_TYPE_INTEGRITY_META, + OBJECT_TYPE_RESERVED_20, OBJECT_TYPE_INVALID, OBJECT_TYPE_TEST, OBJECT_TYPE_CONTAINER_KEYBAG, @@ -170,7 +174,11 @@ char* get_o_type_string(uint32_t o_type) { "Encryption-rolling state", "General-purpose bitmap", "General purpose bitmap block", - "(none/invalid)", + "Encryption-rolling recovery block", + "Additional snapshot metadata", + "Integrity metadata", + "Reserved type/subtype (0x20)", + "(invalid type / no subtype)", "A type reserved for testing (should never appear on disk --- if it does, file a bug against the APFS implementation that created this object)", "Container keybag", "Volume keybag", @@ -243,8 +251,7 @@ char* get_o_subtype_string(uint32_t o_subtype) { // This string is a legal `sprintf()` format string. char* default_string = "Unknown subtype (0x%08x) --- perhaps this subtype was introduced in a later version of APFS than that published on 2019-02-27."; - size_t NUM_FLAGS = 8; - + size_t NUM_FLAGS = 9; uint32_t flag_constants[] = { OBJECT_TYPE_SPACEMAN_FREE_QUEUE, OBJECT_TYPE_EXTENT_LIST_TREE, @@ -254,9 +261,8 @@ char* get_o_subtype_string(uint32_t o_subtype) { OBJECT_TYPE_OMAP_SNAPSHOT, OBJECT_TYPE_FUSION_MIDDLE_TREE, OBJECT_TYPE_GBITMAP_TREE, - + OBJECT_TYPE_FEXT_TREE, }; - char* flag_strings[] = { "Space manager free-space queue", "Extents-list tree", @@ -266,6 +272,7 @@ char* get_o_subtype_string(uint32_t o_subtype) { "Object map snapshots tree", "Fusion inter-drive block-mapping tree", "B-tree of general-purpose bitmaps", + "B-tree of file extents", }; // Allocate sufficient memory to store the longest flag string. diff --git a/src/apfs/struct/btree.h b/src/apfs/struct/btree.h index d4e3b8e..ab8896e 100644 --- a/src/apfs/struct/btree.h +++ b/src/apfs/struct/btree.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §14 "B-Trees" + * §14 B-Trees */ #include @@ -49,6 +49,15 @@ typedef struct { uint64_t bt_node_count; } btree_info_t; +/** `btn_index_node_val_t` **/ + +#define BTREE_NODE_HASH_SIZE_MAX 64 + +typedef struct { + oid_t binv_child_oid; + uint8_t binv_child_hash[BTREE_NODE_HASH_SIZE_MAX]; +} btn_index_node_val_t; + /** `kvloc_t` **/ typedef struct { @@ -72,6 +81,8 @@ typedef struct { #define BTREE_PHYSICAL 0x00000010 #define BTREE_NONPERSISTENT 0x00000020 #define BTREE_KV_NONALIGNED 0x00000040 +#define BTREE_HASHED 0x00000080 +#define BTREE_NOHEADER 0x00000100 /** B-Tree Table of Contents Constants **/ @@ -82,7 +93,11 @@ typedef struct { #define BTNODE_ROOT 0x0001 #define BTNODE_LEAF 0x0002 + #define BTNODE_FIXED_KV_SIZE 0x0004 +#define BTNODE_HASHED 0x0008 +#define BTNODE_NOHEADER 0x0010 + #define BTNODE_CHECK_KOFF_INVAL 0x8000 /** B-Tree Node Constants **/ diff --git a/src/apfs/struct/crypto.h b/src/apfs/struct/crypto.h index 3b88fde..44af01c 100644 --- a/src/apfs/struct/crypto.h +++ b/src/apfs/struct/crypto.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §15 "Encryption" + * §15 Encryption */ #include @@ -53,19 +53,22 @@ typedef struct { /** Protection Classes **/ -#define PROTECTION_CLASS_DIR_NONE 0 -#define PROTECTION_CLASS_A 1 -#define PROTECTION_CLASS_B 2 -#define PROTECTION_CLASS_C 3 -#define PROTECTION_CLASS_D 4 -#define PROTECTION_CLASS_F 6 +#define PROTECTION_CLASS_DIR_NONE 0 +#define PROTECTION_CLASS_A 1 +#define PROTECTION_CLASS_B 2 +#define PROTECTION_CLASS_C 3 +#define PROTECTION_CLASS_D 4 +#define PROTECTION_CLASS_F 6 +#define PROTECTION_CLASS_M 14 #define CP_EFFECTIVE_CLASSMASK 0x0000001f /** Encryption Identifiers **/ -#define CRYPTO_SW_ID 4 -#define CRYPTO_RESERVED_5 5 +#define CRYPTO_SW_ID 4 +#define CRYPTO_RESERVED_5 5 + +#define APFS_UNASSIGNED_CRYPTO_ID (~0ULL) /** `keybag_entry_t` --- forward declared for `kb_locker_t` **/ @@ -108,6 +111,9 @@ enum { 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, }; diff --git a/src/apfs/struct/cryptorolling.h b/src/apfs/struct/cryptorolling.h index 7d0f3a4..de22789 100644 --- a/src/apfs/struct/cryptorolling.h +++ b/src/apfs/struct/cryptorolling.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §18 "Encryption Rolling" + * §18 Encryption Rolling */ #include diff --git a/src/apfs/struct/cryptotypes.h b/src/apfs/struct/cryptotypes.h index 069fbee..c1db1cc 100644 --- a/src/apfs/struct/cryptotypes.h +++ b/src/apfs/struct/cryptotypes.h @@ -3,9 +3,11 @@ /** * Definitions of types used for encryption-related structures, as defined in - * §15.6 "Encryption Types" --- These types are defined in their own - * header file rather than being included in `crypto.h`, else there would be - * a dependency cycle (`j.h` ==> `crypto.h` ==> `j.h`). + * §15.6 Encryption Types. + * + * These types are defined in their own header file rather than being included + * in `crypto.h`, else there would be a dependency cycle + * (`j.h` ==> `crypto.h` ==> `j.h`). */ #include diff --git a/src/apfs/struct/dstream.h b/src/apfs/struct/dstream.h index d4e9428..587fbca 100644 --- a/src/apfs/struct/dstream.h +++ b/src/apfs/struct/dstream.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §10 "Data Streams" + * §10 Data Streams */ #include diff --git a/src/apfs/struct/fs.h b/src/apfs/struct/fs.h index 6ef8ae4..f464506 100644 --- a/src/apfs/struct/fs.h +++ b/src/apfs/struct/fs.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §7 "Volumes" + * §7 Volumes */ #include @@ -80,10 +80,30 @@ typedef struct { uint32_t apfs_next_doc_id; uint16_t apfs_role; - uint16_t apfs_reserved; + uint16_t reserved; xid_t apfs_root_to_xid; oid_t apfs_er_state_oid; + +// Fields introduced in revision 2020-05-15 + + // Fields supported on macOS 10.13.3+ + uint64_t apfs_cloneinfo_id_epoch; + uint64_t apfs_cloneinfo_xid; + + // Fields supported on macOS 10.15+ + oid_t apfs_snap_meta_ext_oid; + uuid_t apfs_volume_group_id; + +// Fields introduced in revision 2020-06-22 + + // Fields supported on macOS 11+ + oid_t apfs_integrity_meta_oid; + oid_t apfs_fext_tree_oid; + uint32_t apfs_fext_tree_type; + + uint32_t reserved_type; + oid_t reserved_oid; } apfs_superblock_t; /** Volume Flags **/ @@ -95,8 +115,10 @@ typedef struct { #define APFS_FS_SPILLEDOVER 0x00000010LL #define APFS_FS_RUN_SPILLOVER_CLEANER 0x00000020LL #define APFS_FS_ALWAYS_CHECK_EXTENTREF 0x00000040LL +#define APFS_FS_RESERVED_80 0x00000080LL +#define APFS_FS_RESERVED_100 0x00000100LL -#define APFS_FS_FALGS_VALID_MASK ( \ +#define APFS_FS_FLAGS_VALID_MASK ( \ APFS_FS_UNENCRYPTED \ | APFS_FS_RESERVED_2 \ | APFS_FS_RESERVED_4 \ @@ -104,11 +126,12 @@ typedef struct { | APFS_FS_SPILLEDOVER \ | APFS_FS_RUN_SPILLOVER_CLEANER \ | APFS_FS_ALWAYS_CHECK_EXTENTREF \ + | APFS_FS_RESERVED_80 \ + | APFS_FS_RESERVED_100 \ ) #define APFS_FS_CRYPTOFLAGS ( \ APFS_FS_UNENCRYPTED \ - | APFS_FS_RESERVED_2 \ | APFS_FS_ONEKEY \ ) @@ -120,24 +143,39 @@ typedef struct { #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 0x0040 -#define APFS_VOL_ROLE_BASEBAND 0x0080 -#define APFS_VOL_ROLE_RESERVED_200 0x0200 +#define APFS_VOLUME_ENUM_SHIFT 6 -/** Optional Volume Feature Flags **/ +#define APFS_VOL_ROLE_DATA ( 1 << APFS_VOLUME_ENUM_SHIFT) // = 0x0040 --- formerly defined explicitly as `0x0040` +#define APFS_VOL_ROLE_BASEBAND ( 2 << APFS_VOLUME_ENUM_SHIFT) // = 0x0080 --- formerly defined explicitly as `0x0080` -#define APFS_FEATURE_DEFRAG_PRERELEASE 0x00000001LL -#define APFS_FEATURE_HARDLINK_MAP_RECORDS 0x00000002LL -#define APFS_FEATURE_DEFRAG 0x00000004LL +// Roles supported since revision 2020-05-15 --- macOS 10.15+, iOS 13+ +#define APFS_VOL_ROLE_UPDATE ( 3 << APFS_VOLUME_ENUM_SHIFT) // = 0x00c0 +#define APFS_VOL_ROLE_XART ( 4 << APFS_VOLUME_ENUM_SHIFT) // = 0x0100 +#define APFS_VOL_ROLE_HARDWARE ( 5 << APFS_VOLUME_ENUM_SHIFT) // = 0x0140 +#define APFS_VOL_ROLE_BACKUP ( 6 << APFS_VOLUME_ENUM_SHIFT) // = 0x0180 +#define APFS_VOL_ROLE_RESERVED_7 ( 7 << APFS_VOLUME_ENUM_SHIFT) // = 0x01c0 --- spec also uses the name `APFS_VOL_ROLE_SIDECAR`, but that could be an error +#define APFS_VOL_ROLE_RESERVED_8 ( 8 << APFS_VOLUME_ENUM_SHIFT) // = 0x0200 --- formerly named `APFS_VOL_ROLE_RESERVED_200` +#define APFS_VOL_ROLE_ENTERPRISE ( 9 << APFS_VOLUME_ENUM_SHIFT) // = 0x0240 +#define APFS_VOL_ROLE_RESERVED_10 (10 << APFS_VOLUME_ENUM_SHIFT) // = 0x0280 +#define APFS_VOL_ROLE_PRELOGIN (11 << APFS_VOLUME_ENUM_SHIFT) // = 0x02c0 + +/** Optional Volume Feature Flags **/ -#define APFS_SUPPORTED_FEATURES_MASK ( \ - APFS_FEATURE_DEFRAG \ - | APFS_FEATURE_DEFRAG_PRERELEASE \ - | APFS_FEATURE_HARDLINK_MAP_RECORDS \ +#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 Comaptible Volume Feature Flags **/ @@ -146,16 +184,22 @@ typedef struct { /** Incompatible Volume Feature Flags **/ -#define APFS_INCOMPAT_CASE_INSENSITIVE 0x000000001LL -#define APFS_INCOMPAT_DATALESS_SNAPS 0x000000002LL -#define APFS_INCOMPAT_ENC_ROLLED 0x000000004LL -#define APFS_INCOMPAT_NORMALIZATION_INSENSITIVE 0x000000008LL +#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_RESERVED_40 0x00000040LL #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_RESERVED_40 \ ) #endif // APFS_STRUCT_FS_H diff --git a/src/apfs/struct/fusion.h b/src/apfs/struct/fusion.h index 34cebcd..2b77540 100644 --- a/src/apfs/struct/fusion.h +++ b/src/apfs/struct/fusion.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §19 "Fusion" + * §19 Fusion */ #include diff --git a/src/apfs/struct/general.h b/src/apfs/struct/general.h index 497b9d6..8d91c0c 100644 --- a/src/apfs/struct/general.h +++ b/src/apfs/struct/general.h @@ -3,7 +3,7 @@ /** * Structures and related item as defined in - * §2 "General-Purpose Types" + * §2 General-Purpose Types */ #include diff --git a/src/apfs/struct/j.h b/src/apfs/struct/j.h index 943568a..33c591c 100644 --- a/src/apfs/struct/j.h +++ b/src/apfs/struct/j.h @@ -3,11 +3,11 @@ /** * Structures and related items as defined in - * §8 "File-System Objects" + * §8 File-System Objects */ #include -#include "const.h" // mode_t +#include "jconst.h" // mode_t #include "cryptotypes.h" // cp_key_class_t /** `j_key_t` **/ @@ -16,9 +16,11 @@ typedef struct { uint64_t obj_id_and_type; } __attribute__((packed)) j_key_t; -#define OBJ_ID_MASK 0x0fffffffffffffffULL -#define OBJ_TYPE_MASK 0xf000000000000000ULL -#define OBJ_TYPE_SHIFT 60 +#define OBJ_ID_MASK 0x0fffffffffffffffULL +#define OBJ_TYPE_MASK 0xf000000000000000ULL +#define OBJ_TYPE_SHIFT 60 + +#define SYSTEM_OBJ_ID_MARK 0x0fffffff00000000ULL /** `j_inode_key_t` **/ @@ -54,7 +56,7 @@ typedef struct { gid_t group; mode_t mode; uint16_t pad1; - uint64_t pad2; + uint64_t uncompressed_size; // formerly `pad2` uint8_t xfields[]; } __attribute__((packed)) j_inode_val_t; @@ -66,7 +68,7 @@ typedef struct { uint8_t name[0]; } __attribute__((packed)) j_drec_key_t; -/* +/** * NOTE: The spec says that if a file-system record is of type * `APFS_TYPE_DIR_REC`, then the record's key is an instance of `j_drec_key_t`. * However, the type `j_drec_hashed_key_t` (seen below) is defined in the spec diff --git a/src/apfs/struct/const.h b/src/apfs/struct/jconst.h similarity index 74% rename from src/apfs/struct/const.h rename to src/apfs/struct/jconst.h index b43ea57..7db6e8f 100644 --- a/src/apfs/struct/const.h +++ b/src/apfs/struct/jconst.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §9 "File-System Constants" + * §9 File-System Constants */ #include @@ -25,8 +25,9 @@ typedef enum { APFS_TYPE_DIR_STATS = 10, APFS_TYPE_SNAP_NAME = 11, APFS_TYPE_SIBLING_MAP = 12, + APFS_TYPE_FILE_INFO = 13, - APFS_TYPE_MAX_VALID = 12, + APFS_TYPE_MAX_VALID = 13, APFS_TYPE_MAX = 15, APFS_TYPE_INVALID = 15, @@ -64,17 +65,27 @@ typedef enum { INODE_HAS_RSRC_FORK = 0x00004000, INODE_NO_RSRC_FORK = 0x00008000, INODE_ALLOCATION_SPILLEDOVER = 0x00010000, - - INODE_INHERITED_INTERNAL_FLAGS = INODE_MAINTAIN_DIR_STATS, + INODE_FAST_PROMOTE = 0x00020000, + INODE_HAS_UNCOMPRESSED_SIZE = 0x00040000, + INODE_IS_PURGEABLE = 0x00080000, + INODE_WANTS_TO_BE_PURGEABLE = 0x00100000, + INODE_IS_SYNC_ROOT = 0x00200000, + INODE_SNAPSHOT_COW_EXEMPTION = 0x00400000, + + INODE_INHERITED_INTERNAL_FLAGS = ( \ + INODE_MAINTAIN_DIR_STATS \ + | INODE_SNAPSHOT_COW_EXEMPTION \ + ), INODE_CLONED_INTERNAL_FLAGS = ( \ INODE_HAS_RSRC_FORK \ | INODE_NO_RSRC_FORK \ | INODE_HAS_FINDER_INFO \ + | INODE_SNAPSHOT_COW_EXEMPTION \ ), } j_inode_flags; -#define APFS_VALID_INTERNAL_INODE_FLAGS ( \ +#define APFS_VALID_INTERNAL_INODE_FLAGS ( \ INODE_IS_APFS_PRIVATE \ | INODE_MAINTAIN_DIR_STATS \ | INODE_DIR_STATS_ORIGIN \ @@ -91,9 +102,18 @@ typedef enum { | INODE_HAS_RSRC_FORK \ | INODE_NO_RSRC_FORK \ | INODE_ALLOCATION_SPILLEDOVER \ + | INODE_FAST_PROMOTE \ + | INODE_HAS_UNCOMPRESSED_SIZE \ + | INODE_IS_PURGEABLE \ + | INODE_WANTS_TO_BE_PURGEABLE \ + | INODE_IS_SYNC_ROOT \ + | INODE_SNAPSHOT_COW_EXEMPTION \ ) -#define APFS_INODE_PINNED_MASK (INODE_PINNED_TO_MAIN | INODE_PINNED_TO_TIER2) +#define APFS_INODE_PINNED_MASK ( \ + INODE_PINNED_TO_MAIN \ + | INODE_PINNED_TO_TIER2 \ +) /** `j_xattr_flags` **/ @@ -113,18 +133,23 @@ typedef enum { /** Inode Numbers **/ -#define INVALID_INO_NUM 0 -#define ROOT_DIR_PARENT 1 -#define ROOT_DIR_INO_NUM 2 -#define PRIV_DIR_INO_NUM 3 -#define SNAP_DIR_INO_NUM 6 +#define INVALID_INO_NUM 0 +#define ROOT_DIR_PARENT 1 +#define ROOT_DIR_INO_NUM 2 +#define PRIV_DIR_INO_NUM 3 +#define SNAP_DIR_INO_NUM 6 +#define PURGEABLE_DIR_INO_NUM 7 + +#define MIN_USER_INO_NUM 16 -#define MIN_USER_INO_NUM 16 +#define UNIFIED_ID_SPACE_MARK 0x0800000000000000ULL /** Extended Attributes Constants **/ #define XATTR_MAX_EMBEDDED_SIZE 3804 // = 3 Ki + 732 #define SYMLINK_EA_NAME "com.apple.fs.symlink" +#define FIRMLINK_EA_NAME "com.apple.fs.firmlink" +#define APFS_COW_EXEMPT_COUNT_NAME "com.apple.fs.cow-exempt-file-count" /** File-System Object Constants **/ diff --git a/src/apfs/struct/jumpstart.h b/src/apfs/struct/jumpstart.h index 42bbc1a..ee4ef85 100644 --- a/src/apfs/struct/jumpstart.h +++ b/src/apfs/struct/jumpstart.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §4 "EFI Jumpstart" + * §4 EFI Jumpstart */ #include diff --git a/src/apfs/struct/nx.h b/src/apfs/struct/nx.h index b27f993..22d16c5 100644 --- a/src/apfs/struct/nx.h +++ b/src/apfs/struct/nx.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §5 "Container" + * §5 Container */ #include @@ -78,6 +78,10 @@ typedef struct { oid_t nx_fusion_mt_oid; oid_t nx_fusion_wbc_oid; prange_t nx_fusion_wbc; + + uint64_t nx_newest_mounted_version; + + prange_t nx_mkb_locker; } nx_superblock_t; /** Container Flags **/ diff --git a/src/apfs/struct/object.h b/src/apfs/struct/object.h index 1a3fb31..75f0aa3 100644 --- a/src/apfs/struct/object.h +++ b/src/apfs/struct/object.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §3 "Objects" + * §3 Objects */ #include @@ -75,11 +75,18 @@ typedef struct { #define OBJECT_TYPE_GBITMAP_TREE 0x0000001a #define OBJECT_TYPE_GBITMAP_BLOCK 0x0000001b +#define OBJECT_TYPE_ER_RECOVERY_BLOCK 0x0000001c +#define OBJECT_TYPE_SNAP_META_EXT 0x0000001d +#define OBJECT_TYPE_INTEGRITY_META 0x0000001e +#define OBJECT_TYPE_FEXT_TREE 0x0000001f +#define OBJECT_TYPE_RESERVED_20 0x00000020 + #define OBJECT_TYPE_INVALID 0x00000000 #define OBJECT_TYPE_TEST 0x000000ff #define OBJECT_TYPE_CONTAINER_KEYBAG 'keys' #define OBJECT_TYPE_VOLUME_KEYBAG 'recs' +#define OBJECT_TYPE_MEDIA_KEYBAG 'mkey' /** Object Type Flags **/ diff --git a/src/apfs/struct/omap.h b/src/apfs/struct/omap.h index 5c69c33..53c124f 100644 --- a/src/apfs/struct/omap.h +++ b/src/apfs/struct/omap.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §6 "Object Maps" + * §6 Object Maps */ #include @@ -69,6 +69,8 @@ typedef struct { #define OMAP_KEYROLLING 0x00000008 #define OMAP_CRYPTO_GENERATION 0x00000010 +#define OMAP_VALID_FLAGS 0x0000001f + /** Object Map Constants **/ #define OMAP_MAX_SNAP_COUNT UINT32_MAX diff --git a/src/apfs/struct/reaper.h b/src/apfs/struct/reaper.h index a37d892..43ce62f 100644 --- a/src/apfs/struct/reaper.h +++ b/src/apfs/struct/reaper.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §17 "Reaper" + * §17 Reaper */ #include diff --git a/src/apfs/struct/sealed.h b/src/apfs/struct/sealed.h new file mode 100644 index 0000000..79119ea --- /dev/null +++ b/src/apfs/struct/sealed.h @@ -0,0 +1,111 @@ +#ifndef APFS_STRUCT_SEALED_H +#define APFS_STRUCT_SEALED_H + +/** + * Structures and related items as defined in + * §16 Sealed Volumes + */ + +#include +#include "object.h" +#include "j.h" + +/** `apfs_hash_type_t` --- forward declared for `integrity_meta_phys_t` **/ + +typedef 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, +} apfs_hash_type_t; + +#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 + +/** `integrity_meta_phys_t` **/ + +typedef struct { + obj_phys_t im_o; + uint32_t im_version; + + // Fields supported by `im_version` >= 1 + uint32_t im_flags; + apfs_hash_type_t im_hash_type; + uint32_t im_root_hash_offset; + xid_t im_broken_xid; + + // Fields supported by `im_version` >= 2 + uint64_t im_reserved[9]; +} __attribute__((packed)) integrity_meta_phys_t; + +/** Integrity Metadata Version Constants **/ + +enum { + INTEGRITY_META_VERSION_INVALID = 0, + INTEGRITY_META_VERSION_1 = 1, + INTEGRITY_META_VERSION_2 = 2, + INTEGRITY_META_VERSION_HIGHEST = INTEGRITY_META_VERSION_2, +}; + +/** Integrity Metadata Flags **/ + +#define APFS_SEAL_BROKEN (1U << 0) + +/** `fext_tree_key_t` **/ + +typedef struct { + uint64_t private_id; + uint64_t logical_addr; +} __attribute__((packed)) fext_tree_key_t; + +/** `fext_tree_val_t` **/ + +typedef struct { + uint64_t len_and_flags; + uint64_t phys_block_num; +} __attribute__((packed)) fext_tree_val_t; + +/** `j_file_info_key_t` **/ + +typedef struct { + j_key_t hdr; + uint64_t info_and_lba; +} __attribute__((packed)) j_file_info_key_t; + +#define J_FILE_INFO_LBA_MASK 0x00ffffffffffffffULL +#define J_FILE_INFO_TYPE_MASK 0xff00000000000000ULL +#define J_FILE_INFO_TYPE_SHIFT 56 + +/** `j_file_data_hash_val_t` --- forward declared for `j_file_info_val_t` **/ + +typedef struct { + uint16_t hashed_len; + uint8_t hash_size; + uint8_t hash[0]; +} __attribute__((packed)) j_file_data_hash_val_t; + +/** `j_file_info_val_t` **/ + +typedef struct { + union { + j_file_data_hash_val_t dhash; + }; +} __attribute__((packed)) j_file_info_val_t; + +/** `j_obj_file_info_type` **/ + +typedef enum { + APFS_FILE_INFO_DATA_HASH = 1, +} j_obj_file_info_type; + +#endif // APFS_STRUCT_SEALED_H diff --git a/src/apfs/struct/sibling.h b/src/apfs/struct/sibling.h index 1b93676..f7e3225 100644 --- a/src/apfs/struct/sibling.h +++ b/src/apfs/struct/sibling.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §12 "Siblings" + * §12 Siblings */ #include diff --git a/src/apfs/struct/snap.h b/src/apfs/struct/snap.h index 2d31336..3d40c24 100644 --- a/src/apfs/struct/snap.h +++ b/src/apfs/struct/snap.h @@ -3,10 +3,11 @@ /** * Structures and related items as defined in - * §13 "Snapshot Metadata" + * §13 Snapshot Metadata */ #include +#include "general.h" // uuid_t #include "j.h" // j_key_t #include "object.h" // oid_t, xid_t @@ -50,4 +51,23 @@ typedef enum { SNAP_META_PENDING_DATALESS = 0x00000001, } snap_meta_flags; +/** `snap_meta_ext_t` --- forward declared for `snap_meta_ext_obj_phys_t` **/ + +typedef struct { + uint32_t sme_version; + + uint32_t sme_flags; + xid_t sme_snap_xid; + uuid_t sme_uuid; + + uint64_t sme_token; +} __attribute__((packed)) snap_meta_ext_t; + +/** `snap_meta_ext_obj_phys_t` **/ + +typedef struct { + obj_phys_t smeop_o; + snap_meta_ext_t smeop_sme; +} __attribute__((packed)) snap_meta_ext_obj_phys_t; + #endif // APFS_STRUCT_SNAP_H diff --git a/src/apfs/struct/spaceman.h b/src/apfs/struct/spaceman.h index fe663df..7d7b1bc 100644 --- a/src/apfs/struct/spaceman.h +++ b/src/apfs/struct/spaceman.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §16 "Space Manager" + * §17 Space Manager */ #include @@ -38,13 +38,24 @@ typedef struct { paddr_t cab_cib_addr[]; } cib_addr_block_t; -/** `spaceman_free_queue_key_t` **/ +/** `spaceman_free_queue_key_t` --- forward declared for `spaceman_free_queue_entry_t` **/ typedef struct { xid_t sfqk_xid; paddr_t sfqk_paddr; } spaceman_free_queue_key_t; +/** `spaceman_free_queue_val_t` --- forward declared for `spaceman_free_queue_entry_t` **/ + +typedef uint64_t spaceman_free_queue_val_t; + +/** `spaceman_free_queue_entry_t` **/ + +typedef struct { + spaceman_free_queue_key_t sfqe_key; + spaceman_free_queue_val_t sfqe_count; +} spaceman_free_queue_entry_t; + /** `spaceman_free_queue_t` **/ typedef struct { diff --git a/src/apfs/struct/xf.h b/src/apfs/struct/xf.h index fb6e906..666a70f 100644 --- a/src/apfs/struct/xf.h +++ b/src/apfs/struct/xf.h @@ -3,7 +3,7 @@ /** * Structures and related items as defined in - * §11 "Extended Fields" + * §11 Extended Fields */ #include @@ -20,7 +20,7 @@ typedef struct { uint16_t x_size; } x_field_t; -/// Extended-Field Types /// +/** Extended-Field Types **/ #define DREC_EXT_TYPE_SIBLING_ID 1 @@ -38,9 +38,10 @@ typedef struct { #define INO_EXT_TYPE_RESERVED_12 12 #define INO_EXT_TYPE_SPARSE_BYTES 13 #define INO_EXT_TYPE_RDEV 14 +#define INO_EXT_TYPE_PURGEABLE_FLAGS 15 +#define INO_EXT_TYPE_ORIG_SYNC_ROOT_ID 16 - -/// Extended-Field Flags /// +/** Extended-Field Flags **/ #define XF_DATA_DEPENDENT 0x0001 #define XF_DO_NOT_COPY 0x0002 diff --git a/src/commands/explore-fs-tree.c b/src/commands/explore-fs-tree.c index 0a8e3e2..69df15a 100644 --- a/src/commands/explore-fs-tree.c +++ b/src/commands/explore-fs-tree.c @@ -7,7 +7,7 @@ #include "../apfs/io.h" #include "../apfs/struct/general.h" #include "../apfs/struct/j.h" -#include "../apfs/struct/const.h" +#include "../apfs/struct/jconst.h" #include "../apfs/struct/dstream.h" #include "../apfs/struct/sibling.h" #include "../apfs/struct/snap.h"