diff --git a/tsk/fs/ext2fs.c b/tsk/fs/ext2fs.c
index f36a193d86221b4ae3b3e96db87bac50f20b1d22..cc42ff5f51c61976053dad83a9fb5bfdaa321d37 100755
--- a/tsk/fs/ext2fs.c
+++ b/tsk/fs/ext2fs.c
@@ -452,13 +452,14 @@ static uint8_t
  * @param ext2fs A ext2fs file system information structure
  * @param dino_inum Metadata address
  * @param dino_buf The buffer to store the block in (must be size of ext2fs->inode_size or larger)
+ * @param ea_buf The buffer to hold the extended attribute data
  *
  * return 1 on error and 0 on success
  * */
 
 static uint8_t
 ext2fs_dinode_load(EXT2FS_INFO * ext2fs, TSK_INUM_T dino_inum,
-    ext2fs_inode * dino_buf)
+    ext2fs_inode * dino_buf, uint8_t ** ea_buf, size_t * ea_buf_len)
 {
     EXT2_GRPNUM_T grp_num;
     TSK_OFF_T addr;
@@ -551,6 +552,16 @@ ext2fs_dinode_load(EXT2FS_INFO * ext2fs, TSK_INUM_T dino_inum,
 //DEBUG    printf("Inode Size: %d, %d, %d, %d\n", sizeof(ext2fs_inode), *ext2fs->fs->s_inode_size, ext2fs->inode_size, *ext2fs->fs->s_want_extra_isize);
 //DEBUG    debug_print_buf((char *)dino_buf, ext2fs->inode_size);
 
+    // Check if we have an extended attribute in the inode
+    if (ext2fs->inode_size > EXT2_EA_INODE_OFFSET) {
+        // The extended attribute data immediatly follows the standard inode data
+        *ea_buf = (char*)dino_buf + EXT2_EA_INODE_OFFSET;
+        *ea_buf_len = ext2fs->inode_size - EXT2_EA_INODE_OFFSET;
+    }
+    else {
+        *ea_buf = NULL;
+    }
+
     if (tsk_verbose) {
         tsk_fprintf(stderr,
             "%" PRIuINUM " m/l/s=%o/%d/%" PRIu32
@@ -575,21 +586,132 @@ ext2fs_dinode_load(EXT2FS_INFO * ext2fs, TSK_INUM_T dino_inum,
     return 0;
 }
 
+/**
+* \internal
+* Loads attribute for Ext4 inline storage method.
+* @param fs_file File to load attrs
+* @param ea_buf  Extended attribute buffer
+* @param ea_buf_len Extended attribute buffer length
+* @returns 0 on success, 1 otherwise
+*/
+static uint8_t
+ext4_load_attrs_inline(TSK_FS_FILE *fs_file, const uint8_t * ea_buf, size_t ea_buf_len)
+{
+    TSK_FS_META *fs_meta = fs_file->meta;
+    TSK_FS_ATTR *fs_attr;
+
+    // see if we have already loaded the attr
+    if ((fs_meta->attr != NULL)
+        && (fs_meta->attr_state == TSK_FS_META_ATTR_STUDIED)) {
+        return 0;
+    }
+
+    if (fs_meta->attr_state == TSK_FS_META_ATTR_ERROR) {
+        return 1;
+    }
+
+    // First load the data from the extended attr (if present)
+    const char *ea_inline_data = NULL;
+    uint32_t ea_inline_data_len = 0;
+    if ((ea_buf != NULL) && (ea_buf_len > 4 + sizeof(ext2fs_ea_entry))
+        && (tsk_getu32(fs_file->fs_info->endian, ea_buf) == EXT2_EA_MAGIC)) {
+
+        // First entry starts after the four byte header
+        size_t index = 4;
+        ext2fs_ea_entry *ea_entry = (ext2fs_ea_entry*) &(ea_buf[index]);
+
+        // The end of the list of entries is marked by two null bytes
+        while ((ea_entry->nlen != 0) || (ea_entry->nidx != 0)) {
+
+            // It looks like the continuation of inline data is stored in system.data.
+            // Make sure we have room to read the attr name 'data'.
+            if ((ea_entry->nidx == EXT2_EA_IDX_SYSTEM)
+                && (ea_entry->nlen == 4)
+                && (index + sizeof(ext2fs_ea_entry) + strlen("data") < ea_buf_len)
+                && (strncmp(&(ea_entry->name), "data", 4)) == 0) {
+
+                // This is the right attribute. Check that the length and offset are valid.
+                // The offset is from the beginning of the entries, i.e., four bytes into the buffer.
+                uint32_t offset = tsk_getu32(fs_file->fs_info->endian, ea_entry->val_off);
+                uint32_t size = tsk_getu32(fs_file->fs_info->endian, ea_entry->val_size);
+                if (4 + offset + size <= ea_buf_len) {
+                    ea_inline_data = &(ea_buf[4 + offset]);
+                    ea_inline_data_len = size;
+                    break;
+                }
+            }
+
+            // Prepare to load the next entry.
+            // The entry size is the size of the struct plus the length of the name, minus one
+            // because the struct contains the first character of the name.
+            index += sizeof(ext2fs_ea_entry) + ea_entry->nlen - 1;
+
+            // Make sure there's room for the next entry plus the 'data' name we're looking for.
+            if (index + sizeof(ext2fs_ea_entry) + strlen("data") > ea_buf_len) {
+                break;
+            }
+            ext2fs_ea_entry *ea_entry = (ext2fs_ea_entry*) &(ea_buf[index]);
+        }
+    }
+
+    // Combine the two parts of the inline data for the resident attribute. For now, make a
+    // buffer for the full file size - this may be different than the length of the data 
+    // from the inode if we have sparse data.
+    uint8_t *resident_data;
+    if ((resident_data = (uint8_t*)tsk_malloc(fs_meta->size)) == NULL) {
+        return 1;
+    }
+    memset(resident_data, 0, fs_meta->size);
+
+    // Copy the data from the inode.
+    size_t inode_data_len = (fs_meta->size < EXT2_INLINE_MAX_DATA_LEN) ? fs_meta->size : EXT2_INLINE_MAX_DATA_LEN;
+    memcpy(resident_data, fs_meta->content_ptr, inode_data_len);
+
+    // If we need more data and found an extended attribute, append that data
+    if ((fs_meta->size > EXT2_INLINE_MAX_DATA_LEN) && (ea_inline_data_len > 0)) {
+        // Don't go beyond the size of the file
+        size_t ea_data_len = (inode_data_len + ea_inline_data_len < (uint64_t)fs_meta->size) ? inode_data_len + ea_inline_data_len : fs_meta->size - inode_data_len;
+        memcpy(resident_data + inode_data_len, ea_inline_data, ea_data_len);
+    }
+
+    fs_meta->attr = tsk_fs_attrlist_alloc();
+    if ((fs_attr =
+        tsk_fs_attrlist_getnew(fs_meta->attr,
+            TSK_FS_ATTR_RES)) == NULL) {
+        free(resident_data);
+        return 1;
+    }
+
+    // Set the details in the fs_attr structure
+    if (tsk_fs_attr_set_str(fs_file, fs_attr, "DATA",
+        TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
+        (void*)resident_data,
+        fs_meta->size)) {
+        free(resident_data);
+        fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
+        return 1;
+    }
+
+    free(resident_data);
+    fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED;
+    return 0;
+}
+
 /* ext2fs_dinode_copy - copy cached disk inode into generic inode
  *
  * returns 1 on error and 0 on success
  * */
 static uint8_t
-ext2fs_dinode_copy(EXT2FS_INFO * ext2fs, TSK_FS_META * fs_meta,
-    TSK_INUM_T inum, const ext2fs_inode * dino_buf)
+ext2fs_dinode_copy(EXT2FS_INFO * ext2fs, TSK_FS_FILE * fs_file,
+    TSK_INUM_T inum, const ext2fs_inode * dino_buf, const uint8_t * ea_buf, size_t ea_buf_len)
 {
     int i;
     TSK_FS_INFO *fs = (TSK_FS_INFO *) & ext2fs->fs_info;
+    TSK_FS_META * fs_meta = fs_file->meta;
     ext2fs_sb *sb = ext2fs->fs;
     EXT2_GRPNUM_T grp_num;
     TSK_INUM_T ibase = 0;
 
-
     if (dino_buf == NULL) {
         tsk_error_reset();
         tsk_error_set_errno(TSK_ERR_FS_ARG);
@@ -728,9 +850,20 @@ ext2fs_dinode_copy(EXT2FS_INFO * ext2fs, TSK_FS_META * fs_meta,
         /* NOTE TSK_DADDR_T != uint32_t, so lets make sure we use uint32_t */
         addr_ptr = (uint32_t *) fs_meta->content_ptr;
         for (i = 0; i < EXT2FS_NDADDR + EXT2FS_NIADDR; i++) {
-            addr_ptr[i] = tsk_gets32(fs->endian, dino_buf->i_block[i]);;
+            addr_ptr[i] = tsk_gets32(fs->endian, dino_buf->i_block[i]);
         }
     }
+    else if (tsk_getu32(fs->endian, dino_buf->i_flags) & EXT2_INLINE_DATA) {
+        uint32_t *addr_ptr;
+        fs_meta->content_type = TSK_FS_META_CONTENT_TYPE_EXT4_INLINE;
+        addr_ptr = (uint32_t *)fs_meta->content_ptr;
+        for (i = 0; i < EXT2FS_NDADDR + EXT2FS_NIADDR; i++) {
+            addr_ptr[i] = tsk_gets32(fs->endian, dino_buf->i_block[i]);
+        }
+
+        // For inline data we create the default attribute now
+        ext4_load_attrs_inline(fs_file, ea_buf, ea_buf_len);
+    } 
     else {
         TSK_DADDR_T *addr_ptr;
         addr_ptr = (TSK_DADDR_T *) fs_meta->content_ptr;
@@ -887,6 +1020,8 @@ ext2fs_inode_lookup(TSK_FS_INFO * fs, TSK_FS_FILE * a_fs_file,
 {
     EXT2FS_INFO *ext2fs = (EXT2FS_INFO *) fs;
     ext2fs_inode *dino_buf = NULL;
+    uint8_t *ea_buf = NULL;
+    size_t ea_buf_len = 0;
     unsigned int size = 0;
 
     if (a_fs_file == NULL) {
@@ -919,12 +1054,12 @@ ext2fs_inode_lookup(TSK_FS_INFO * fs, TSK_FS_FILE * a_fs_file,
         return 1;
     }
 
-    if (ext2fs_dinode_load(ext2fs, inum, dino_buf)) {
+    if (ext2fs_dinode_load(ext2fs, inum, dino_buf, &ea_buf, &ea_buf_len)) {
         free(dino_buf);
         return 1;
     }
 
-    if (ext2fs_dinode_copy(ext2fs, a_fs_file->meta, inum, dino_buf)) {
+    if (ext2fs_dinode_copy(ext2fs, a_fs_file, inum, dino_buf, ea_buf, ea_buf_len)) {
         free(dino_buf);
         return 1;
     }
@@ -956,6 +1091,8 @@ ext2fs_inode_walk(TSK_FS_INFO * fs, TSK_INUM_T start_inum,
     TSK_FS_FILE *fs_file;
     unsigned int myflags;
     ext2fs_inode *dino_buf = NULL;
+    uint8_t *ea_buf = NULL;
+    size_t ea_buf_len = 0;
     unsigned int size = 0;
 
     // clean up any error messages that are lying around
@@ -1089,7 +1226,7 @@ ext2fs_inode_walk(TSK_FS_INFO * fs, TSK_INUM_T start_inum,
         if ((flags & myflags) != myflags)
             continue;
 
-        if (ext2fs_dinode_load(ext2fs, inum, dino_buf)) {
+        if (ext2fs_dinode_load(ext2fs, inum, dino_buf, &ea_buf, &ea_buf_len)) {
             tsk_fs_file_close(fs_file);
             free(dino_buf);
             return 1;
@@ -1119,7 +1256,7 @@ ext2fs_inode_walk(TSK_FS_INFO * fs, TSK_INUM_T start_inum,
          * Fill in a file system-independent inode structure and pass control
          * to the application.
          */
-        if (ext2fs_dinode_copy(ext2fs, fs_file->meta, inum, dino_buf)) {
+        if (ext2fs_dinode_copy(ext2fs, fs_file, inum, dino_buf, ea_buf, ea_buf_len)) {
             tsk_fs_meta_close(fs_file->meta);
             free(dino_buf);
             return 1;
@@ -1694,7 +1831,7 @@ ext4_load_attrs_extents(TSK_FS_FILE *fs_file)
     }
     
     length = roundup(fs_meta->size, fs_info->block_size);
-    
+
     if ((fs_attr =
          tsk_fs_attrlist_getnew(fs_meta->attr,
                                 TSK_FS_ATTR_NONRES)) == NULL) {
@@ -1755,7 +1892,7 @@ ext4_load_attrs_extents(TSK_FS_FILE *fs_file)
             ("ext2fs_load_attr: Inode reports too many extent indices");
             return 1;
         }
-        
+
         if ((fs_attr_extent =
              tsk_fs_attrlist_getnew(fs_meta->attr,
                                     TSK_FS_ATTR_NONRES)) == NULL) {
@@ -1815,6 +1952,10 @@ ext2fs_load_attrs(TSK_FS_FILE * fs_file)
     if (fs_file->meta->content_type == TSK_FS_META_CONTENT_TYPE_EXT4_EXTENTS) {
         return ext4_load_attrs_extents(fs_file);
     }
+    else if (fs_file->meta->content_type == TSK_FS_META_CONTENT_TYPE_EXT4_INLINE) {
+        // Inline attributes are loaded in dinode_copy
+        return 0;
+    }
     else {
         return tsk_fs_unix_make_data_run(fs_file);
     }
@@ -2683,6 +2824,8 @@ ext2fs_istat(TSK_FS_INFO * fs, TSK_FS_ISTAT_FLAG_ENUM istat_flags, FILE * hFile,
     EXT2FS_PRINT_ADDR print;
     const TSK_FS_ATTR *fs_attr_indir;
     ext2fs_inode *dino_buf = NULL;
+    uint8_t *ea_buf = NULL;
+    size_t ea_buf_len = 0;
     char timeBuf[128];
     unsigned int size;
     unsigned int large_inodes;
@@ -2703,7 +2846,7 @@ ext2fs_istat(TSK_FS_INFO * fs, TSK_FS_ISTAT_FLAG_ENUM istat_flags, FILE * hFile,
         return 1;
     }
 
-    if (ext2fs_dinode_load(ext2fs, inum, dino_buf)) {
+    if (ext2fs_dinode_load(ext2fs, inum, dino_buf, &ea_buf, &ea_buf_len)) {
         free(dino_buf);
         return 1;
     }
@@ -2810,6 +2953,21 @@ ext2fs_istat(TSK_FS_INFO * fs, TSK_FS_ISTAT_FLAG_ENUM istat_flags, FILE * hFile,
         if (tsk_getu32(fs->endian, dino_buf->i_flags) & EXT2_IN_EOFBLOCKS)
             tsk_fprintf(hFile, "Blocks Allocated Beyond EOF, ");
 
+        if (tsk_getu32(fs->endian, dino_buf->i_flags) & EXT2_SNAPFILE)
+            tsk_fprintf(hFile, "Snapshot, ");
+
+        if (tsk_getu32(fs->endian, dino_buf->i_flags) & EXT2_SNAPFILE_DELETED)
+            tsk_fprintf(hFile, "Deleted Snapshot, ");
+
+        if (tsk_getu32(fs->endian, dino_buf->i_flags) & EXT2_SNAPFILE_SHRUNK)
+            tsk_fprintf(hFile, "Shrunk Snapshot, ");
+
+        if (tsk_getu32(fs->endian, dino_buf->i_flags) & EXT2_INLINE_DATA)
+            tsk_fprintf(hFile, "Inline Data, ");
+
+        if (tsk_getu32(fs->endian, dino_buf->i_flags) & EXT2_PROJINHERIT)
+            tsk_fprintf(hFile, "Inherited project ID, ");
+
 
         tsk_fprintf(hFile, "\n");
     }
@@ -3135,87 +3293,89 @@ ext2fs_istat(TSK_FS_INFO * fs, TSK_FS_ISTAT_FLAG_ENUM istat_flags, FILE * hFile,
     if (numblock > 0)
         fs_meta->size = numblock * fs->block_size;
 
-    tsk_fprintf(hFile, "\nDirect Blocks:\n");
-
-    if (istat_flags & TSK_FS_ISTAT_RUNLIST) {
-        const TSK_FS_ATTR *fs_attr_default =
-            tsk_fs_file_attr_get_type(fs_file,
-                TSK_FS_ATTR_TYPE_DEFAULT, 0, 0);
-        if (fs_attr_default && (fs_attr_default->flags & TSK_FS_ATTR_NONRES)) {
-            if (tsk_fs_attr_print(fs_attr_default, hFile)) {
-                tsk_fprintf(hFile, "\nError creating run lists\n");
-                tsk_error_print(hFile);
-                tsk_error_reset();
-            }
-        }
-    }
-    else {
-        print.idx = 0;
-        print.hFile = hFile;
-
-        if (tsk_fs_file_walk(fs_file, TSK_FS_FILE_WALK_FLAG_AONLY,
-            print_addr_act, (void *)&print)) {
-            tsk_fprintf(hFile, "\nError reading file:  ");
-            tsk_error_print(hFile);
-            tsk_error_reset();
-        }
-        else if (print.idx != 0) {
-            tsk_fprintf(hFile, "\n");
-        }
-    }
+    if (fs_meta->content_type != TSK_FS_META_CONTENT_TYPE_EXT4_INLINE) {
+        tsk_fprintf(hFile, "\nDirect Blocks:\n");
 
-    if (fs_meta->content_type == TSK_FS_META_CONTENT_TYPE_EXT4_EXTENTS) {
-        const TSK_FS_ATTR *fs_attr_extent =
-            tsk_fs_file_attr_get_type(fs_file,
-            TSK_FS_ATTR_TYPE_UNIX_EXTENT, 0, 0);
-        if (fs_attr_extent) {
-            tsk_fprintf(hFile, "\nExtent Blocks:\n");
-
-            if (istat_flags & TSK_FS_ISTAT_RUNLIST) {
-                if (tsk_fs_attr_print(fs_attr_extent, hFile)) {
+        if (istat_flags & TSK_FS_ISTAT_RUNLIST) {
+            const TSK_FS_ATTR *fs_attr_default =
+                tsk_fs_file_attr_get_type(fs_file,
+                    TSK_FS_ATTR_TYPE_DEFAULT, 0, 0);
+            if (fs_attr_default && (fs_attr_default->flags & TSK_FS_ATTR_NONRES)) {
+                if (tsk_fs_attr_print(fs_attr_default, hFile)) {
                     tsk_fprintf(hFile, "\nError creating run lists\n");
                     tsk_error_print(hFile);
                     tsk_error_reset();
                 }
             }
-            else {
-                print.idx = 0;
+        }
+        else {
+            print.idx = 0;
+            print.hFile = hFile;
 
-                if (tsk_fs_attr_walk(fs_attr_extent,
-                    TSK_FS_FILE_WALK_FLAG_AONLY, print_addr_act,
-                    (void *)&print)) {
-                    tsk_fprintf(hFile,
-                        "\nError reading indirect attribute:  ");
-                    tsk_error_print(hFile);
-                    tsk_error_reset();
+            if (tsk_fs_file_walk(fs_file, TSK_FS_FILE_WALK_FLAG_AONLY,
+                print_addr_act, (void *)&print)) {
+                tsk_fprintf(hFile, "\nError reading file:  ");
+                tsk_error_print(hFile);
+                tsk_error_reset();
+            }
+            else if (print.idx != 0) {
+                tsk_fprintf(hFile, "\n");
+            }
+        }
+
+        if (fs_meta->content_type == TSK_FS_META_CONTENT_TYPE_EXT4_EXTENTS) {
+            const TSK_FS_ATTR *fs_attr_extent =
+                tsk_fs_file_attr_get_type(fs_file,
+                    TSK_FS_ATTR_TYPE_UNIX_EXTENT, 0, 0);
+            if (fs_attr_extent) {
+                tsk_fprintf(hFile, "\nExtent Blocks:\n");
+
+                if (istat_flags & TSK_FS_ISTAT_RUNLIST) {
+                    if (tsk_fs_attr_print(fs_attr_extent, hFile)) {
+                        tsk_fprintf(hFile, "\nError creating run lists\n");
+                        tsk_error_print(hFile);
+                        tsk_error_reset();
+                    }
                 }
-                else if (print.idx != 0) {
-                    tsk_fprintf(hFile, "\n");
+                else {
+                    print.idx = 0;
+
+                    if (tsk_fs_attr_walk(fs_attr_extent,
+                        TSK_FS_FILE_WALK_FLAG_AONLY, print_addr_act,
+                        (void *)&print)) {
+                        tsk_fprintf(hFile,
+                            "\nError reading indirect attribute:  ");
+                        tsk_error_print(hFile);
+                        tsk_error_reset();
+                    }
+                    else if (print.idx != 0) {
+                        tsk_fprintf(hFile, "\n");
+                    }
                 }
             }
         }
-    }
-    else {
-        fs_attr_indir = tsk_fs_file_attr_get_type(fs_file,
-            TSK_FS_ATTR_TYPE_UNIX_INDIR, 0, 0);
-        if (fs_attr_indir) {
-            tsk_fprintf(hFile, "\nIndirect Blocks:\n");
-            if (istat_flags & TSK_FS_ISTAT_RUNLIST) {
-                tsk_fs_attr_print(fs_attr_indir, hFile);
-            }
-            else {
-                print.idx = 0;
-
-                if (tsk_fs_attr_walk(fs_attr_indir,
-                    TSK_FS_FILE_WALK_FLAG_AONLY, print_addr_act,
-                    (void *)&print)) {
-                    tsk_fprintf(hFile,
-                        "\nError reading indirect attribute:  ");
-                    tsk_error_print(hFile);
-                    tsk_error_reset();
+        else {
+            fs_attr_indir = tsk_fs_file_attr_get_type(fs_file,
+                TSK_FS_ATTR_TYPE_UNIX_INDIR, 0, 0);
+            if (fs_attr_indir) {
+                tsk_fprintf(hFile, "\nIndirect Blocks:\n");
+                if (istat_flags & TSK_FS_ISTAT_RUNLIST) {
+                    tsk_fs_attr_print(fs_attr_indir, hFile);
                 }
-                else if (print.idx != 0) {
-                    tsk_fprintf(hFile, "\n");
+                else {
+                    print.idx = 0;
+
+                    if (tsk_fs_attr_walk(fs_attr_indir,
+                        TSK_FS_FILE_WALK_FLAG_AONLY, print_addr_act,
+                        (void *)&print)) {
+                        tsk_fprintf(hFile,
+                            "\nError reading indirect attribute:  ");
+                        tsk_error_print(hFile);
+                        tsk_error_reset();
+                    }
+                    else if (print.idx != 0) {
+                        tsk_fprintf(hFile, "\n");
+                    }
                 }
             }
         }
diff --git a/tsk/fs/ext2fs_dent.c b/tsk/fs/ext2fs_dent.c
index f590bd07bf88997626096fac0631f204bf4830cb..95e8b256961bdd504dcc91b34a2d4abeb2140e30 100644
--- a/tsk/fs/ext2fs_dent.c
+++ b/tsk/fs/ext2fs_dent.c
@@ -317,7 +317,13 @@ ext2fs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
         return TSK_ERR;
     }
 
-    size = roundup(fs_dir->fs_file->meta->size, a_fs->block_size);
+    if (fs_dir->fs_file->meta->content_type == TSK_FS_META_CONTENT_TYPE_EXT4_INLINE) {
+        // For inline dirs, don't try to read past the end of the data
+        size = fs_dir->fs_file->meta->size;
+    }
+    else {
+        size = roundup(fs_dir->fs_file->meta->size, a_fs->block_size);
+    }
     TSK_OFF_T offset = 0;
 
     while (size > 0) {
diff --git a/tsk/fs/tsk_ext2fs.h b/tsk/fs/tsk_ext2fs.h
index 382a9a5312f323046ca256c45484e3895e379a73..71640f5fd67ffbb68815568886a7bd8263e17adc 100644
--- a/tsk/fs/tsk_ext2fs.h
+++ b/tsk/fs/tsk_ext2fs.h
@@ -413,10 +413,16 @@ extern "C" {
 #define EXT2_IN_EXTENTS                 0x00080000      /* Inode uses extents */
 #define EXT2_IN_EA_INODE                0x00200000      /* Inode used for large EA */
 #define EXT2_IN_EOFBLOCKS               0x00400000      /* Blocks allocated beyond EOF */
+#define EXT2_SNAPFILE                   0x01000000      /* Inode is a snapshot */
+#define EXT2_SNAPFILE_DELETED           0x04000000	    /* Snapshot is being deleted */
+#define EXT2_SNAPFILE_SHRUNK            0x08000000	    /* Snapshot shrink has completed */
+#define EXT2_INLINE_DATA                0x10000000	    /* Inode has inline data */
+#define EXT2_PROJINHERIT                0x20000000	    /* Create children with the same project ID */
 #define EXT2_IN_RESERVED                0x80000000      /* reserved for ext4 lib */
 #define EXT2_IN_USER_VISIBLE            0x004BDFFF      /* User visible flags */
 #define EXT2_IN_USER_MODIFIABLE         0x004B80FF      /* User modifiable flags */
 
+#define EXT2_INLINE_MAX_DATA_LEN 60  /* Max length for inline data in inode (not counting extended attribute) */
 
 /*
  * directory entries
@@ -463,6 +469,7 @@ extern "C" {
  */
 
 #define EXT2_EA_MAGIC	0xEA020000
+#define EXT2_EA_INODE_OFFSET   160
 
     typedef struct {
         uint8_t magic[4];
@@ -480,6 +487,8 @@ extern "C" {
 #define EXT2_EA_IDX_TRUSTED                4
 #define EXT2_EA_IDX_LUSTRE                 5
 #define EXT2_EA_IDX_SECURITY               6
+#define EXT2_EA_IDX_SYSTEM                 7 // Possibly only valid for inline data
+#define EXT2_EA_IDX_SYSTEM_RICHACL         8
 
 /* Entries follow the header and are aligned to 4-byte boundaries
  * the value of the attribute is stored at the bottom of the block
diff --git a/tsk/fs/tsk_fs.h b/tsk/fs/tsk_fs.h
index 2158584563104b5158975835cc73a11ccfdf243b..d0b5d1dc59697222a59fc889a8e3de8248a17e45 100644
--- a/tsk/fs/tsk_fs.h
+++ b/tsk/fs/tsk_fs.h
@@ -437,7 +437,8 @@ extern "C" {
 
     typedef enum TSK_FS_META_CONTENT_TYPE_ENUM {
         TSK_FS_META_CONTENT_TYPE_DEFAULT = 0x0,
-        TSK_FS_META_CONTENT_TYPE_EXT4_EXTENTS = 0x1     ///< Ext4 with extents instead of individual pointers
+        TSK_FS_META_CONTENT_TYPE_EXT4_EXTENTS = 0x1,     ///< Ext4 with extents instead of individual pointers
+        TSK_FS_META_CONTENT_TYPE_EXT4_INLINE = 0x02      ///< Ext4 with inline data
     } TSK_FS_META_CONTENT_TYPE_ENUM;