Check that the internal flags of an inode are all valid, and consistent
with each other. Also report if any of them are unsupported, or if they
were set as the result of a crash.
Ignore the finder info flag for now, because it seems to be set in some
inodes that have no corresponding xfield. The next patch will take care
of reporting this as weird.
Signed-off-by: Ernesto A. Fernández <
ernesto.mn...@gmail.com>
---
apfsck/inode.c | 33 +++++++++++++++++++++++++++++++++
apfsck/inode.h | 29 +++++++++++++++++++++++++++++
2 files changed, 62 insertions(+)
diff --git a/apfsck/inode.c b/apfsck/inode.c
index 54a5274..b3925dd 100644
--- a/apfsck/inode.c
+++ b/apfsck/inode.c
@@ -446,6 +446,36 @@ static void parse_inode_xfields(struct apfs_xf_blob *xblob, int len,
}
/**
+ * check_inode_internal_flags - Check basic consistency of inode flags
+ * @flags: the flags
+ */
+static void check_inode_internal_flags(u64 flags)
+{
+ if ((flags & APFS_VALID_INTERNAL_INODE_FLAGS) != flags)
+ report("Inode record", "invalid flags in use.");
+
+ if ((flags & APFS_INODE_DIR_STATS_ORIGIN) &&
+ !(flags & APFS_INODE_MAINTAIN_DIR_STATS))
+ report("Inode record", "incompatible directory stats flags.");
+ if (flags & APFS_INODE_HAS_RSRC_FORK && flags & APFS_INODE_NO_RSRC_FORK)
+ report("Inode record", "incompatible resource fork flags.");
+
+ if (flags & APFS_INODE_BEING_TRUNCATED)
+ report_crash("Inode internal flags");
+
+ if (flags & APFS_INODE_PINNED_TO_MAIN ||
+ flags & APFS_INODE_PINNED_TO_TIER2 ||
+ flags & APFS_INODE_ALLOCATION_SPILLEDOVER)
+ report_unknown("Fusion drive");
+ if (flags & APFS_INODE_HAS_RSRC_FORK)
+ report_unknown("Resource fork");
+ if (flags & APFS_INODE_MAINTAIN_DIR_STATS)
+ report_unknown("Directory statistics");
+ if (flags & APFS_INODE_IS_APFS_PRIVATE)
+ report_unknown("Private implementation inode");
+}
+
+/**
* check_inode_ids - Check that an inode id is consistent with its parent id
* @ino: inode number
* @parent_ino: parent inode number
@@ -512,6 +542,9 @@ void parse_inode_record(struct apfs_inode_key *key,
check_inode_ids(inode->i_ino, le64_to_cpu(val->parent_id));
+ inode->i_flags = le64_to_cpu(val->internal_flags);
+ check_inode_internal_flags(inode->i_flags);
+
mode = le16_to_cpu(val->mode);
filetype = mode & S_IFMT;
diff --git a/apfsck/inode.h b/apfsck/inode.h
index e6c4dff..ba70b8b 100644
--- a/apfsck/inode.h
+++ b/apfsck/inode.h
@@ -23,6 +23,34 @@ struct apfs_sibling_link_key;
/* Smallest inode number available for user content */
#define APFS_MIN_USER_INO_NUM 16
+/* 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
+
+/* Masks for internal flags */
+#define APFS_VALID_INTERNAL_INODE_FLAGS 0x0001ffdf
+#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)
+
/* File mode flags */
#define S_IFMT 00170000
#define S_IFSOCK 0140000
@@ -166,6 +194,7 @@ struct inode {
u64 i_size; /* Inode size */
u64 i_alloced_size; /* Inode size, including unused */
u64 i_sparse_bytes; /* Number of sparse bytes */
+ u64 i_flags; /* Internal flags */
u32 i_rdev; /* Device ID */
char *i_name; /* Name of primary link */
--
2.11.0