From 974b8eeb2b532b40d6e6c642895ca03df0db8234 Mon Sep 17 00:00:00 2001
From: isciurus <isciurus@gmail.com>
Date: Thu, 22 Aug 2019 13:48:02 -0700
Subject: [PATCH] Parsing XFS_DINODE_FMT_BTREE directories for v5 (tested on
 RHEL)

---
 tsk/fs/tsk_xfs.h | 45 +++++++++++++++++++++++++++++++++++++++++++++
 tsk/fs/xfs.c     |  3 ++-
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/tsk/fs/tsk_xfs.h b/tsk/fs/tsk_xfs.h
index 40dec266c..ca4ec2474 100644
--- a/tsk/fs/tsk_xfs.h
+++ b/tsk/fs/tsk_xfs.h
@@ -265,8 +265,53 @@ typedef struct xfs_btree_lblock {
     uint16_t   bb_numrecs;
     uint64_t   bb_leftsib;
     uint64_t   bb_rightsib;
+    /* version 5 filesystem fields start here */
+    uint64_t   bb_blkno;
+    uint64_t   bb_lsn;
+    xfs_uuid_t bb_uuid;
+    uint64_t   bb_owner;
+    uint32_t   bb_crc;
+    uint32_t   bb_pad;
 } xfs_btree_lblock_t;
 
+/* size of a long form block:
+*    uint32_t    bb_magic;
+*    uint16_t    bb_level;
+*    uint16_t    bb_numrecs;
+*    uint64_t    bb_leftsib;
+*    uint64_t    bb_rightsib;
+*/
+#define XFS_BTREE_LBLOCK_LEN \
+    (sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) + \
+     sizeof(uint64_t) + sizeof(uint64_t))
+
+/* sizes of CRC enabled long form blocks:
+*    uint32_t    bb_magic;
+*    uint16_t    bb_level;
+*    uint16_t    bb_numrecs;
+*    uint64_t    bb_leftsib;
+*    uint64_t    bb_rightsib;
++
+*    uint64_t    bb_blkno;
+*    uint64_t    bb_lsn;
+*    xfs_uuid_t  bb_uuid;
+*    uint64_t    bb_owner;
+*    uint32_t    bb_crc;
+*    uint32_t    bb_pad;
+*/
+#define XFS_BTREE_LBLOCK_CRC_LEN \
+    (sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) + \
+     sizeof(uint64_t) + sizeof(uint64_t) + \
+     sizeof(uint64_t) + sizeof(uint64_t) + sizeof(xfs_uuid_t) + \
+     sizeof(uint64_t) + sizeof(uint32_t) + sizeof(uint32_t))
+
+/*
+ * Long form block header size depends on a superblock flag
+ */
+#define XFS_LBLOCK_LEN(sb) \
+    (xfs_sb_version_hascrc(sb) ? \
+         XFS_BTREE_LBLOCK_CRC_LEN : XFS_BTREE_LBLOCK_LEN)
+
 typedef struct xfs_bmbt_key {
     xfs_dfiloff_t    br_startoff;
 } xfs_bmbt_key_t, xfs_bmdr_key_t;
diff --git a/tsk/fs/xfs.c b/tsk/fs/xfs.c
index b9f562caa..d14398ae6 100644
--- a/tsk/fs/xfs.c
+++ b/tsk/fs/xfs.c
@@ -2268,6 +2268,7 @@ visit_btree_node(
 {
     char *myname = "xfs_dir_open_meta";
     XFSFS_INFO *xfs = (XFSFS_INFO *) a_fs;
+    xfs_sb_t *sb = xfs->fs;
 
     // xfs_bmdr_block and xfs_bmbt_block_t share those two fields
     uint16_t bb_numrecs = 0;
@@ -2314,7 +2315,7 @@ visit_btree_node(
             return TSK_ERR;
         }
 
-        len = header_offset = sizeof(xfs_bmbt_block_t);
+        len = header_offset = XFS_LBLOCK_LEN(sb);
         cnt = tsk_fs_read(&xfs->fs_info,
             cur_node_offset,
             (char *) cur_bmbt_block,
-- 
GitLab