diff --git a/tsk/fs/tsk_xfs.h b/tsk/fs/tsk_xfs.h
index 66967e78aaec3c6b9b3a0539606cd715ef24731f..734029c611525f8adbd63ebeda853082d123ab9b 100644
--- a/tsk/fs/tsk_xfs.h
+++ b/tsk/fs/tsk_xfs.h
@@ -74,6 +74,12 @@ typedef struct xfs_btree_sblock {
     uint16_t    bb_numrecs;
     uint32_t    bb_leftsib;
     uint32_t    bb_rightsib;
+    /* version 5 filesystem fields start here */
+    uint64_t    bb_blkno;
+    uint64_t    bb_lsn;
+    xfs_uuid_t  bb_uuid;
+    uint32_t    bb_owner;
+    uint32_t    bb_crc;
 } xfs_btree_sblock_t;
 
 typedef struct xfs_alloc_rec {
@@ -449,16 +455,35 @@ typedef struct xfs_dir2_data_free {
     uint16_t                length;        /* length of freespace */
 } xfs_dir2_data_free_t;
 
-#define    XFS_DIR2_DATA_FD_COUNT    3
 /*
- * Header for the data blocks.
+ * Header for the data blocks (non-v5 XFS)
  */
+#define XFS_DIR2_HDR_LEN        16
+#define XFS_DIR2_DATA_FD_COUNT  3
 typedef struct xfs_dir2_data_hdr {
     uint32_t                magic;        /* XFS_DIR2_DATA_MAGIC or */
                                           /* XFS_DIR2_BLOCK_MAGIC */
     xfs_dir2_data_free_t    bestfree[XFS_DIR2_DATA_FD_COUNT];
 } xfs_dir2_data_hdr_t;
 
+/*
+ * Header for the data blocks (v5 XFS)
+ */
+#define XFS_DIR3_HDR_LEN        64
+struct xfs_dir3_blk_hdr {
+    uint32_t                magic;
+    uint32_t                crc;
+    uint64_t                blkno;
+    uint64_t                lsn;
+    xfs_uuid_t              uuid;
+    uint64_t                owner;
+};
+struct xfs_dir3_data_hdr {
+    struct xfs_dir3_blk_hdr hdr;
+    xfs_dir2_data_free_t    best_free[XFS_DIR2_DATA_FD_COUNT];
+    /* uint32_t pad; */
+};
+
 /*
  * Active entry in a data block.
  *
@@ -766,7 +791,7 @@ static inline bool xfs_sb_version_hasprojid32bit(xfs_sb *sb)
  */
 static inline bool xfs_sb_version_hascrc(xfs_sb *sb)
 {
-    return sb->sb_versionnum == XFS_SB_VERSION_5;
+    return XFS_SB_VERSION_NUM(sb) == XFS_SB_VERSION_5;
 }
 static inline int xfs_sb_version_hasftype(xfs_sb *sb)
 {
diff --git a/tsk/fs/xfs.cpp b/tsk/fs/xfs.cpp
index d5252a9a1670429d9fd6cc6e972c93a503bf0d25..7de936a63a7f7f4b7af1b894d1dff62054c41d4c 100644
--- a/tsk/fs/xfs.cpp
+++ b/tsk/fs/xfs.cpp
@@ -76,8 +76,8 @@ TSK_FS_META_FLAG_ENUM xfs_inode_getallocflag(
         return (TSK_FS_META_FLAG_ENUM) NULL;
     }
 
-    if ((cur_inobt_block = 
-        static_cast<xfs_inobt_block_t *>(tsk_malloc(sizeof(xfs_inobt_block_t)))) == NULL)
+    len = XFS_INOBT_BLOCK_LEN(sb);
+    if ((cur_inobt_block = (xfs_inobt_block_t*) tsk_malloc(len)) == NULL)
     {
         return (TSK_FS_META_FLAG_ENUM) NULL;
     }
@@ -90,11 +90,11 @@ TSK_FS_META_FLAG_ENUM xfs_inode_getallocflag(
     // take inode agi b+tree
     cur_block_num = (TSK_DADDR_T) ag_num * (TSK_DADDR_T) sb->sb_agblocks 
         + (TSK_DADDR_T) xfsfs->agi[ag_num].agi_root;
-    len = sizeof(xfs_inobt_block_t);
+
     cnt = tsk_fs_read(fs,
         (TSK_OFF_T) sb->sb_blocksize * cur_block_num,
         (char *) cur_inobt_block,
-        sizeof(xfs_inobt_block_t));
+        len);
     if (cnt != len) {
         if (cnt >= 0) {
             tsk_error_reset();
@@ -132,7 +132,7 @@ TSK_FS_META_FLAG_ENUM xfs_inode_getallocflag(
         // read all the keys
         len = cur_inobt_block->bb_numrecs * sizeof(xfs_inobt_key_t);
         cnt = tsk_fs_read(fs, 
-            (TSK_OFF_T) sb->sb_blocksize * cur_block_num + sizeof(xfs_inobt_block_t),
+            (TSK_OFF_T) sb->sb_blocksize * cur_block_num + XFS_INOBT_BLOCK_LEN(sb),
             (char *) ikeys,
             len);
         if (cnt != len) {
@@ -152,9 +152,9 @@ TSK_FS_META_FLAG_ENUM xfs_inode_getallocflag(
         len = cur_inobt_block->bb_numrecs * sizeof(xfs_inobt_ptr_t);
         cnt = tsk_fs_read(fs,
             (TSK_OFF_T) sb->sb_blocksize * cur_block_num 
-                + (TSK_OFF_T) sizeof(xfs_inobt_block_t) 
+                + (TSK_OFF_T) XFS_INOBT_BLOCK_LEN(sb)
                 + (TSK_OFF_T) (maxrecs * sizeof(xfs_inobt_key_t)),
-                (char *) iptrs, 
+                (char *) iptrs,
                 len);
         if (cnt != len) {
             if (cnt >= 0) {
@@ -207,11 +207,11 @@ TSK_FS_META_FLAG_ENUM xfs_inode_getallocflag(
 
             if (tsk_verbose) { tsk_fprintf(stderr, "go one level down in b+tree, cur_block_num = %u at bb_level = %" PRIu64 "\n", cur_block_num, cur_inobt_block->bb_level); }
 
-            len = sizeof(xfs_inobt_block_t);
+            len = XFS_INOBT_BLOCK_LEN(sb);
             cnt = tsk_fs_read(fs,
                 (TSK_OFF_T) sb->sb_blocksize * cur_block_num,
                 (char *) cur_inobt_block,
-                sizeof(xfs_inobt_block_t));
+                len);
             if (cnt != len) {
                 if (cnt >= 0) {
                     tsk_error_reset();
@@ -253,10 +253,9 @@ TSK_FS_META_FLAG_ENUM xfs_inode_getallocflag(
     // read all the records
     len = cur_inobt_block->bb_numrecs * sizeof(xfs_inobt_rec_t);
     cnt = tsk_fs_read(fs,
-        (TSK_OFF_T) sb->sb_blocksize * cur_block_num
-            + sizeof(xfs_inobt_block_t),
-                (char *) irecs,
-                len);
+        (TSK_OFF_T) sb->sb_blocksize * cur_block_num + XFS_INOBT_BLOCK_LEN(sb),
+        (char *) irecs,
+        len);
     if (cnt != len) {
         if (cnt >= 0) {
             tsk_error_reset();
@@ -2005,9 +2004,7 @@ parse_dir_block(
     XFSFS_INFO *xfs = (XFSFS_INFO *) a_fs;
     xfs_sb_t *sb = xfs->fs;
 
-    uint8_t ftype_size = (sb->sb_features2 & XFS_SB_VERSION2_FTYPE)
-        ? sizeof(uint8_t)
-        : 0;
+    uint8_t ftype_size = xfs_sb_version_hasftype(sb) ? sizeof(uint8_t) : 0;
 
     // skip ft if that's not a data block
     if (irec->br_startoff >= XFS_DIR2_LEAF_OFFSET / a_fs->block_size 
@@ -2058,20 +2055,9 @@ parse_dir_block(
 
         xfs_dir2_data_hdr data_hdr;
         memcpy(&data_hdr, dirbuf + offset_in_block, sizeof(data_hdr));
-        offset_in_block += sizeof(data_hdr);
-
-        data_hdr.bestfree[0].offset = 
-            tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[0].offset);
-        data_hdr.bestfree[0].length =
-            tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[0].length);
-        data_hdr.bestfree[1].offset =
-            tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[1].offset);
-        data_hdr.bestfree[1].length =
-            tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[1].length);
-        data_hdr.bestfree[2].offset =
-            tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[2].offset);
-        data_hdr.bestfree[2].length =
-            tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[2].length);
+
+        offset_in_block += XFS_SB_VERSION_NUM(sb) == XFS_SB_VERSION_5 ?
+                XFS_DIR3_HDR_LEN : XFS_DIR2_HDR_LEN;
 
         xfs_dir2_data_entry_t data_entry;
 
@@ -2088,7 +2074,7 @@ parse_dir_block(
                     static_cast<xfs_dir2_data_unused *>((void*) (dirbuf + offset_in_block));
 
                 if (tsk_verbose) { tsk_fprintf(stderr, "offset_in_block = % is a free space, shifting forward by tsk_getu32(TSK_BIG_ENDIAN, &data_unused->length)) = %d \n", offset_in_block, tsk_getu32(TSK_BIG_ENDIAN, &data_unused->length)); }
-                offset_in_block += tsk_getu32(TSK_BIG_ENDIAN, &data_unused->length);
+                offset_in_block += tsk_getu16(TSK_BIG_ENDIAN, &data_unused->length);
             }
             else
             {
@@ -2483,9 +2469,7 @@ xfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
     if ((fs_name = tsk_fs_name_alloc(XFS_MAXNAMELEN, 0)) == NULL)
         return TSK_ERR;
 
-    ftype_size = (sb->sb_features2 & XFS_SB_VERSION2_FTYPE)
-        ? sizeof(uint8_t)
-        : 0;
+    ftype_size = xfs_sb_version_hasftype(sb) ? sizeof(uint8_t) : 0;
 
     if (fs_meta->content_type == TSK_FS_META_CONTENT_TYPE_XFS_LOCAL)
     {
@@ -2649,7 +2633,8 @@ xfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
 
             TSK_OFF_T offset_in_block = 0;
 
-            // read xfs_dir2_data_hdr (on a v5 filesystem this is xfs_dir3_data_hdr_t)
+            // directory block starts with xfs_dir2_data_hdr
+            // or (xfs_dir3_data_hdr_t on a v5 filesystem)
 
             ssize_t len = (size > a_fs->block_size) ? a_fs->block_size : size;
             ssize_t cnt = tsk_fs_read(a_fs, offset, dirbuf, len);
@@ -2663,22 +2648,8 @@ xfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
                 return TSK_COR;
             }
 
-            xfs_dir2_data_hdr data_hdr;
-            memcpy(&data_hdr, dirbuf + offset_in_block, sizeof(data_hdr));
-            offset_in_block += sizeof(data_hdr);
-
-            data_hdr.bestfree[0].offset =
-                tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[0].offset);
-            data_hdr.bestfree[0].length =
-                tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[0].length);
-            data_hdr.bestfree[1].offset =
-                tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[1].offset);
-            data_hdr.bestfree[1].length =
-                tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[1].length);
-            data_hdr.bestfree[2].offset =
-                tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[2].offset);
-            data_hdr.bestfree[2].length =
-                tsk_getu16(TSK_BIG_ENDIAN, &data_hdr.bestfree[2].length);
+            offset_in_block += XFS_SB_VERSION_NUM(sb) == XFS_SB_VERSION_5 ?
+                XFS_DIR3_HDR_LEN : XFS_DIR2_HDR_LEN;
 
             xfs_dir2_block_tail block_tail;
             memcpy(&block_tail, dirbuf + size - sizeof(xfs_dir2_block_tail),
@@ -2719,7 +2690,7 @@ xfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
 
                     if (tsk_verbose) { tsk_fprintf(stderr, "offset_in_block = % is a free space, shifting forward by tsk_getu32(TSK_BIG_ENDIAN, &data_unused->length)) = %d \n", offset_in_block, tsk_getu32(TSK_BIG_ENDIAN, &data_unused->length)); }
                     offset_in_block +=
-                        tsk_getu32(TSK_BIG_ENDIAN, &data_unused->length);
+                        tsk_getu16(TSK_BIG_ENDIAN, &data_unused->length);
                 }
                 else
                 {