Whamcloud - gitweb
debugfs: decode and dump xattrs on inode stat
authorAndreas Dilger <andreas.dilger@intel.com>
Fri, 13 Apr 2012 18:55:45 +0000 (12:55 -0600)
committerAndreas Dilger <adilger@whamcloud.com>
Thu, 15 Dec 2022 22:29:58 +0000 (15:29 -0700)
Decode and print Access Control Lists in debugfs stat/ea_list.

Print the Lustre "fid", "lma", and "link" xattr contents,
if present, with "debugfs stat" to simplify debugging.
Add "layout_version" and "range" values when printing a
trusted.fid xattr.

Increase the size of xattrs hex-dumped from 40 to 120.  But as
Lustre encrypted inodes may contain illegal characters in their
names, it is also needed to escape non-printable characters in
linkEA.

Change-Id: I3ee35ddb02582ab66d4e25ff76fae35935b54508
Reviewed-on: https://review.whamcloud.com/43384
Reviewed-by: Li Dongyang <dongyangli@ddn.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
22 files changed:
debugfs/Makefile.in
debugfs/debugfs.8.in
debugfs/debugfs.h
debugfs/xattrs.c
lib/ext2fs/ext2fs.h
lib/ext2fs/ext4_acl.h
lib/ext2fs/ext_attr.c
lib/ext2fs/lfsck.h
misc/fuse2fs.c
tests/d_print_acl/expect [new file with mode: 0644]
tests/d_print_acl/script [new file with mode: 0644]
tests/d_trusted_fid/expect [new file with mode: 0644]
tests/d_trusted_fid/image.gz [new file with mode: 0644]
tests/d_trusted_fid/name [new file with mode: 0644]
tests/d_trusted_fid/script [new file with mode: 0644]
tests/d_trusted_link/expect [new file with mode: 0644]
tests/d_trusted_link/image.gz [new file with mode: 0644]
tests/d_trusted_link/name [new file with mode: 0644]
tests/d_trusted_link/script [new file with mode: 0644]
tests/d_xattr_edits/expect
tests/m_rootdir_acl/expect
tests/test_post

index ed4ea8d..dd2acd7 100644 (file)
@@ -51,6 +51,7 @@ STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBSS) \
 # clean up this mess, we should be able to drop it
 LOCAL_CFLAGS = -I$(srcdir)/../e2fsck -DDEBUGFS
 DEPEND_CFLAGS = -I$(srcdir)
+@LFSCK_CMT@LUSTRE_INC=-I @LUSTRE@/lustre/include -I @LUSTRE@/include -I @LUSTRE@/libcfs/include -Wall
 
 .c.o:
        $(E) "  CC $<"
index 6cd1d84..6b35aae 100644 (file)
@@ -301,19 +301,29 @@ corruption in the file system.)
 .B dump_unused
 Dump unused blocks which contain non-null bytes.
 .TP
-.BI ea_get " [-f outfile]|[-xVC] [-r] filespec attr_name"
+.BI "ea_get [-f " outfile "]|[-xVC] [-r]" " filespec attr_name"
 Retrieve the value of the extended attribute
 .I attr_name
 in the file
 .I filespec
-and write it either to stdout or to \fIoutfile\fR.
+and write it either to stdout or to \fIoutfile\fR if
+.B -f
+is specified.  If
+.B -C
+is used the xattr is printed with C-format escapes, and if
+.B -x
+is used the xattr is printed in hex format, while the
+.B -V
+option prints in raw format without quotes.  The
+.B -r
+option prints the xattr name in raw format.
 .TP
 .BI ea_list " filespec
 List the extended attributes associated with the file
 .I filespec
 to standard output.
 .TP
-.BI ea_set " [-f infile] [-r] filespec attr_name attr_value
+.BI "ea_set [-f " infile "] [-r] " "filespec attr_name attr_value"
 Set the value of the extended attribute
 .I attr_name
 in the file
index 39bc024..db58aba 100644 (file)
@@ -27,6 +27,7 @@ extern quota_ctx_t current_qctx;
 extern ext2_ino_t      root, cwd;
 extern int ss_sci_idx;
 extern ss_request_table debug_cmds, extent_cmds;
+extern const char *debug_prog_name;
 
 extern void reset_getopt(void);
 extern FILE *open_pager(void);
index bd11450..6c266fb 100644 (file)
@@ -17,6 +17,8 @@ extern char *optarg;
 #include "support/cstring.h"
 
 #include "debugfs.h"
+#include "ext2fs/ext4_acl.h"
+#include "ext2fs/lfsck.h"
 
 #define PRINT_XATTR_HEX                0x01
 #define PRINT_XATTR_RAW                0x02
@@ -24,6 +26,8 @@ extern char *optarg;
 #define PRINT_XATTR_STATFMT    0x08
 #define PRINT_XATTR_NOQUOTES   0x10
 
+extern const char *debug_prog_name;
+
 /* Dump extended attributes */
 static void print_xattr_hex(FILE *f, const char *str, int len)
 {
@@ -74,19 +78,293 @@ static void print_xattr(FILE *f, char *name, char *value, size_t value_len,
            (strcmp(name, "system.data") == 0))
                value_len = 0;
        if (value_len != 0 &&
-           (!(print_flags & PRINT_XATTR_STATFMT) || (value_len < 40))) {
+           (!(print_flags & PRINT_XATTR_STATFMT) || (value_len < 120))) {
                fprintf(f, " = ");
                print_xattr_string(f, value, value_len, print_flags);
        }
        fputc('\n', f);
 }
 
-static int dump_attr(char *name, char *value, size_t value_len, void *data)
+static int print_acl(FILE *f, char *name, void *value, size_t value_len)
+{
+       const ext4_acl_header *ext_acl = (const ext4_acl_header *)value;
+       const char *cp;
+
+       if (!value ||
+           (value_len < sizeof(ext4_acl_header)) ||
+           (ext_acl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION)))
+               return -EINVAL;
+
+       cp = (const char *)value + sizeof(ext4_acl_header);
+       value_len -= sizeof(ext4_acl_header);
+
+       fprintf(f, "%s:\n", name);
+
+       while (value_len > 0) {
+               const ext4_acl_entry *disk_entry = (const ext4_acl_entry *)cp;
+               posix_acl_xattr_entry entry;
+               entry.e_tag = ext2fs_le16_to_cpu(disk_entry->e_tag);
+               entry.e_perm = ext2fs_le16_to_cpu(disk_entry->e_perm);
+
+               switch(entry.e_tag) {
+                       case ACL_USER_OBJ:
+                       case ACL_USER:
+                               fprintf(f, "    user:");
+                               if (entry.e_tag == ACL_USER)
+                                       fprintf(f, "%u",
+                                       ext2fs_le32_to_cpu(disk_entry->e_id));
+                               break;
+
+                       case ACL_GROUP_OBJ:
+                       case ACL_GROUP:
+                               fprintf(f, "    group:");
+                               if (entry.e_tag == ACL_GROUP)
+                                       fprintf(f, "%u",
+                                       ext2fs_le32_to_cpu(disk_entry->e_id));
+                               break;
+
+                       case ACL_MASK:
+                               fprintf(f, "    mask:");
+                               break;
+
+                       case ACL_OTHER:
+                               fprintf(f, "    other:");
+                               break;
+
+                       default:
+                               fprintf(stderr,
+                                       "%s: error: invalid tag %x in ACL\n",
+                                       debug_prog_name, entry.e_tag);
+                               return -EINVAL;
+               }
+               fprintf(f, ":");
+               fprintf(f, (entry.e_perm & ACL_READ) ? "r" : "-");
+               fprintf(f, (entry.e_perm & ACL_WRITE) ? "w" : "-");
+               fprintf(f, (entry.e_perm & ACL_EXECUTE) ? "x" : "-");
+               fprintf(f, "\n");
+
+               if (entry.e_tag == ACL_USER || entry.e_tag == ACL_GROUP) {
+                       cp += sizeof(ext4_acl_entry);
+                       value_len -= sizeof(ext4_acl_entry);
+               } else {
+                       cp += sizeof(ext4_acl_entry_short);
+                       value_len -= sizeof(ext4_acl_entry_short);
+               }
+       }
+
+       return 0;
+}
+
+static int print_fidstr(FILE *f, char *name, void *value, size_t value_len)
+{
+       struct filter_fid_old *ff = value;
+       int stripe;
+
+       /* Since Lustre 2.4 only the parent FID is stored in filter_fid,
+        * and the self fid is stored in the LMA and is printed below. */
+       if (value_len < sizeof(ff->ff_parent)) {
+               fprintf(stderr, "%s: error: xattr '%s' too small (%zu bytes)\n",
+                       debug_prog_name, name, value_len);
+               return -EINVAL;
+       }
+       fid_le_to_cpu(&ff->ff_parent, &ff->ff_parent);
+       stripe = fid_ver(&ff->ff_parent); /* stripe index is stored in f_ver */
+       ff->ff_parent.f_ver = 0;
+
+       fprintf(f, "fid: ");
+       /* Old larger filter_fid should only ever be used with seq = 0.
+        * FID-on-OST should use LMA for FID_SEQ_NORMAL OST objects. */
+       if (value_len == sizeof(*ff))
+               fprintf(f, "objid=%llu seq=%llu ",
+                       ext2fs_le64_to_cpu(ff->ff_objid),
+                       ext2fs_le64_to_cpu(ff->ff_seq));
+
+       fprintf(f, "parent="DFID" stripe=%u", PFID(&ff->ff_parent), stripe);
+       if (value_len >= sizeof(struct filter_fid_210)) {
+               struct filter_fid_210 *ff_new = value;
+
+               fprintf(f, " stripe_size=%u stripe_count=%u",
+                       ext2fs_le32_to_cpu(ff_new->ff_stripe_size),
+                       ext2fs_le32_to_cpu(ff_new->ff_stripe_count));
+               if (ff_new->ff_pfl_id != 0)
+                       fprintf(f, " component_id=%u component_start=%llu "
+                               "component_end=%llu",
+                               ext2fs_le32_to_cpu(ff_new->ff_pfl_id),
+                               ext2fs_le64_to_cpu(ff_new->ff_pfl_start),
+                               ext2fs_le64_to_cpu(ff_new->ff_pfl_end));
+       }
+
+       if (value_len >= sizeof(struct filter_fid)) {
+               struct filter_fid *ff_new = value;
+
+               fprintf(f, " layout_version=%u range=%u",
+                       ext2fs_le32_to_cpu(ff_new->ff_layout_version),
+                       ext2fs_le32_to_cpu(ff_new->ff_range));
+       }
+
+       fprintf(f, "\n");
+
+       return 0;
+}
+
+static int print_lmastr(FILE *f, char *name, void *value, size_t value_len)
+{
+       struct lustre_mdt_attrs *lma = value;
+       struct lustre_ost_attrs *loa = value;
+
+       if (value_len < offsetof(typeof(*lma), lma_self_fid) +
+                       sizeof(lma->lma_self_fid)) {
+               fprintf(stderr, "%s: error: xattr '%s' too small (%zu bytes)\n",
+                       debug_prog_name, name, value_len);
+               return -EINVAL;
+       }
+       fid_le_to_cpu(&lma->lma_self_fid, &lma->lma_self_fid);
+       fprintf(f, "lma: fid="DFID" compat=%x incompat=%x\n",
+               PFID(&lma->lma_self_fid), ext2fs_le32_to_cpu(lma->lma_compat),
+               ext2fs_le32_to_cpu(lma->lma_incompat));
+       if (value_len >= offsetof(typeof(*loa), loa_pfl_end) +
+                 sizeof(loa->loa_pfl_end)) {
+               int idx;
+               int cnt;
+
+               fid_le_to_cpu(&loa->loa_parent_fid, &loa->loa_parent_fid);
+               idx = loa->loa_parent_fid.f_ver & PFID_STRIPE_COUNT_MASK;
+               cnt = loa->loa_parent_fid.f_ver >> PFID_STRIPE_IDX_BITS;
+               loa->loa_parent_fid.f_ver = 0;
+
+               fprintf(f, "  fid: parent="DFID" stripe=%u stripe_size=%u "
+                       "stripe_count=%u", PFID(&loa->loa_parent_fid), idx,
+                       ext2fs_le32_to_cpu(loa->loa_stripe_size), cnt);
+               if (loa->loa_pfl_id != 0)
+                       fprintf(f, " component_id=%u component_start=%llu "
+                               "component_end=%llu",
+                               ext2fs_le32_to_cpu(loa->loa_pfl_id),
+                               ext2fs_le64_to_cpu(loa->loa_pfl_start),
+                               ext2fs_le64_to_cpu(loa->loa_pfl_end));
+               fprintf(f, "\n");
+       }
+
+       return 0;
+}
+
+static void print_name(FILE *f, const char *cp, int len)
+{
+       unsigned char ch;
+
+       while (len--) {
+               ch = *cp++;
+               if (!isprint(ch) || ch == '\\') {
+                       if (f)
+                               fprintf(f, "\\x%02x", ch);
+               } else {
+                       if (f)
+                               fputc(ch, f);
+               }
+       }
+}
+
+static int print_linkea(FILE *f, char *name, void *value, size_t value_len)
 {
+       struct link_ea_header *leh = value;
+       struct link_ea_entry *lee;
+       int i;
+
+       if (value_len < sizeof(*leh) ||
+           value_len < ext2fs_le64_to_cpu(leh->leh_len)) {
+               fprintf(stderr, "%s: error: xattr '%s' too small (%zu bytes)\n",
+                       debug_prog_name, name, value_len);
+               return -EINVAL;
+       }
+
+       if (ext2fs_le32_to_cpu(leh->leh_magic) != LINK_EA_MAGIC) {
+               fprintf(stderr, "%s: error: xattr '%s' bad magic '%#x'\n",
+                       debug_prog_name, name,
+                       ext2fs_le32_to_cpu(leh->leh_magic));
+               return -EINVAL;
+       }
+
+       lee = leh->leh_entry;
+       value_len -= sizeof(*leh);
+
+       for (i = 0; i < ext2fs_le32_to_cpu(leh->leh_reccount) &&
+                   value_len > 2; i++) {
+               int reclen = lee->lee_reclen[0] << 8 | lee->lee_reclen[1];
+               struct lu_fid pfid;
+
+               if (value_len < sizeof(*lee) || value_len < reclen) {
+                       fprintf(stderr,
+                               "%s: error: xattr '%s' entry %d too small "
+                               "(%zu bytes)\n",
+                               debug_prog_name, name, i, value_len);
+                       return -EINVAL;
+               }
+
+               memcpy(&pfid, &lee->lee_parent_fid, sizeof(pfid));
+               fid_be_to_cpu(&pfid, &pfid);
+               fprintf(f, "%s idx=%u parent="DFID" name='",
+                       i == 0 ? "linkea:" : "         ", i, PFID(&pfid));
+               print_name(f, lee->lee_name, reclen - (int)sizeof(*lee));
+               fprintf(f, "'\n");
+
+               lee = (struct link_ea_entry *)((char *)lee + reclen);
+               value_len -= reclen;
+       }
+
+       return 0;
+}
+
+struct dump_attr_pretty {
+       const char *dap_name;
+       int (*dap_print)(FILE *f, char *name, void *value, size_t value_len);
+} dumpers[] = {
+       {
+               .dap_name = "system.posix_acl_access",
+               .dap_print = print_acl,
+       },
+       {
+               .dap_name = "system.posix_acl_default",
+               .dap_print = print_acl,
+       },
+       {
+               .dap_name = "trusted.fid",
+               .dap_print = print_fidstr,
+       },
+       {
+               .dap_name = "trusted.lma",
+               .dap_print = print_lmastr,
+       },
+       {
+               .dap_name = "trusted.link",
+               .dap_print = print_linkea,
+       },
+       {
+               .dap_name = NULL,
+       }
+};
+
+static int dump_attr(char *name, char *value, size_t value_len,
+                    ext2_ino_t inode_num, void *data)
+{
+       struct dump_attr_pretty *dap;
        FILE *out = data;
+       int rc = 0;
 
        fprintf(out, "  ");
-       print_xattr(out, name, value, value_len, PRINT_XATTR_STATFMT);
+       if (EXT2_HAS_INCOMPAT_FEATURE(current_fs->super,
+                                     EXT4_FEATURE_INCOMPAT_EA_INODE) &&
+                                     inode_num != 0) {
+               fprintf(out, "inode <%u> ", inode_num);
+       }
+
+       for (dap = dumpers; dap->dap_name != NULL; dap++) {
+               if (strcmp(name, dap->dap_name) == 0) {
+                       rc = dap->dap_print(out, name, value, value_len);
+                       break;
+               }
+       }
+       if (dap->dap_name == NULL || rc)
+               print_xattr(out, name, value, value_len, PRINT_XATTR_STATFMT);
+
        return 0;
 }
 
index af09a65..53fc1b1 100644 (file)
@@ -1320,7 +1320,8 @@ errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle);
 errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle);
 errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
                                int (*func)(char *name, char *value,
-                                           size_t value_len, void *data),
+                                           size_t value_len,
+                                           ext2_ino_t inode_num, void *data),
                                void *data);
 errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
                           void **value, size_t *value_len);
index 8d4d974..8343086 100644 (file)
@@ -4,6 +4,12 @@
 
 #define EXT4_ACL_VERSION        0x0001
 
+/* 23.2.2 acl_perm_t values */
+
+#define ACL_READ               (0x04)
+#define ACL_WRITE              (0x02)
+#define ACL_EXECUTE            (0x01)
+
 /* 23.2.5 acl_tag_t values */
 
 #define ACL_UNDEFINED_TAG      (0x00)
index b33b33b..c718ef3 100644 (file)
@@ -379,6 +379,7 @@ static struct ea_name_index ea_names[] = {
        {2, "system.posix_acl_access"},
        {8, "system.richacl"},
        {6, "security."},
+       {5, "lustre."},
        {4, "trusted."},
        {7, "system."},
        {1, "user."},
@@ -1132,7 +1133,8 @@ out:
 
 errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
                                int (*func)(char *name, char *value,
-                                           size_t value_len, void *data),
+                                           size_t value_len,
+                                           ext2_ino_t inode_num, void *data),
                                void *data)
 {
        struct ext2_xattr *x;
@@ -1141,7 +1143,7 @@ errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
 
        EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
        for (x = h->attrs; x < h->attrs + h->count; x++) {
-               ret = func(x->name, x->value, x->value_len, data);
+               ret = func(x->name, x->value, x->value_len, x->ea_ino, data);
                if (ret & XATTR_CHANGED)
                        dirty = 1;
                if (ret & XATTR_ABORT)
index 6a49042..5f182bc 100644 (file)
@@ -34,6 +34,89 @@ static inline void fid_be_to_cpu(struct lu_fid *dst, struct lu_fid *src)
        dst->f_oid = ext2fs_be32_to_cpu(src->f_oid);
        dst->f_ver = ext2fs_be32_to_cpu(src->f_ver);
 }
+
+static inline void fid_le_to_cpu(struct lu_fid *dst, struct lu_fid *src)
+{
+       dst->f_seq = ext2fs_le64_to_cpu(src->f_seq);
+       dst->f_oid = ext2fs_le32_to_cpu(src->f_oid);
+       dst->f_ver = ext2fs_le32_to_cpu(src->f_ver);
+}
+#endif /* HAVE_LUSTRE_LUSTRE_IDL_H */
+
+#define LUSTRE_XATTR_MDT_LOV   "lov"
+#define LUSTRE_XATTR_MDT_LMA   "lma"
+#define LUSTRE_XATTR_MDT_LINK  "link"
+#define LUSTRE_XATTR_OST_FID   "fid"
+
+#ifndef LMA_OLD_SIZE
+#ifndef LMA_INCOMPAT_SUPP
+struct lustre_mdt_attrs {
+       __u32           lma_compat;
+       __u32           lma_incompat;
+       struct lu_fid   lma_self_fid;
+};
+struct lustre_ost_attrs {
+       struct lustre_mdt_attrs loa_lma;
+       struct lu_fid           loa_parent_fid;
+       __u32                   loa_stripe_size;
+       __u32                   loa_pfl_id;
+       __u64                   loa_pfl_start;
+       __u64                   loa_pfl_end;
+};
+#endif
+
+struct filter_fid_old {
+       struct lu_fid   ff_parent;
+       __u64           ff_objid;
+       __u64           ff_seq;
+};
+
+struct filter_fid_210 {
+       struct lu_fid   ff_parent;
+       __u32           ff_stripe_size;
+       __u32           ff_stripe_count;
+       __u64           ff_pfl_start;
+       __u64           ff_pfl_end;
+       __u32           ff_pfl_id;
+};
+
+struct filter_fid {
+       struct lu_fid   ff_parent;
+       __u32           ff_stripe_size;
+       __u32           ff_stripe_count;
+       __u64           ff_pfl_start;
+       __u64           ff_pfl_end;
+       __u32           ff_pfl_id;
+       __u32           ff_layout_version;
+       __u32           ff_range;
+} __attribute__((packed));
+
+#define LMA_OLD_SIZE 64
+#endif /* !LMA_OLD_SIZE */
+
+#define PFID_STRIPE_IDX_BITS   16
+#define PFID_STRIPE_COUNT_MASK ((1 << PFID_STRIPE_IDX_BITS) - 1)
+
+#ifndef LINK_EA_MAGIC
+/** Hardlink data is name and parent fid.
+ * Stored in this crazy struct for maximum packing and endian-neutrality */
+struct link_ea_entry {
+       /** lee_reclen is a __u16 stored big-endian, unaligned */
+       unsigned char   lee_reclen[2];  /* record size in bytes */
+       unsigned char   lee_parent_fid[sizeof(struct lu_fid)];
+       char            lee_name[0];    /* filename without trailing NUL */
+}__attribute__((packed));
+
+/** The link ea holds 1 \a link_ea_entry for each hardlink */
+#define LINK_EA_MAGIC 0x11EAF1DFUL
+struct link_ea_header {
+       __u32 leh_magic;                /* LINK_EA_MAGIC */
+       __u32 leh_reccount;             /* number of records in leh_entry[] */
+       __u64 leh_len;                  /* total size in bytes */
+       __u32 leh_overflow_time;        /* when link xattr ran out of space */
+       __u32 padding;
+       struct link_ea_entry leh_entry[0]; /* packed array of variable-size entries */
+};
 #endif
 
 #endif /* LFSCK_H */
index c595721..f73ceba 100644 (file)
@@ -2496,6 +2496,7 @@ out:
 
 static int count_buffer_space(char *name, char *value EXT2FS_ATTR((unused)),
                              size_t value_len EXT2FS_ATTR((unused)),
+                             ext2_ino_t inode_num EXT2FS_ATTR((unused)),
                              void *data)
 {
        unsigned int *x = data;
@@ -2505,7 +2506,9 @@ static int count_buffer_space(char *name, char *value EXT2FS_ATTR((unused)),
 }
 
 static int copy_names(char *name, char *value EXT2FS_ATTR((unused)),
-                     size_t value_len EXT2FS_ATTR((unused)), void *data)
+                     size_t value_len EXT2FS_ATTR((unused)),
+                     ext2_ino_t inode_num EXT2FS_ATTR((unused)),
+                     void *data)
 {
        char **b = data;
 
diff --git a/tests/d_print_acl/expect b/tests/d_print_acl/expect
new file mode 100644 (file)
index 0000000..03dea43
--- /dev/null
@@ -0,0 +1,13 @@
+Extended attributes:
+  system.posix_acl_access:
+    user::rwx
+    group::r-x
+    group:42:r-x
+    mask::r-x
+    other::r-x
+  system.posix_acl_default:
+    user::rwx
+    group::r-x
+    group:4:r-x
+    mask::r-x
+    other::r-x
diff --git a/tests/d_print_acl/script b/tests/d_print_acl/script
new file mode 100644 (file)
index 0000000..d5cbd62
--- /dev/null
@@ -0,0 +1,55 @@
+test_description="decode and print Access Control Lists in debugfs"
+if ! test -x $DEBUGFS_EXE; then
+       echo "$test_name: $test_description: skipped (no debugfs)"
+       return 0
+fi
+
+if ! setfacl --help > /dev/null 2>&1 ; then
+       echo "$test_name: $test_description: skipped (no setfacl)"
+       return 0
+fi
+
+MKFS_DIR=$(mktemp -d ./$test_name-XXXXXX.tmp)
+OUT=$test_name.log
+EXP=$test_dir/expect
+
+mkdir $MKFS_DIR/acl_dir
+
+setfacl --restore=- <<EOF
+# file: $MKFS_DIR/acl_dir
+user::rwx
+group::r-x
+group:42:r-x
+mask::r-x
+other::r-x
+default:user::rwx
+default:group::r-x
+default:group:4:r-x
+default:mask::r-x
+default:other::r-x
+EOF
+
+if ! getfattr -d -m - $MKFS_DIR/acl_dir | grep -q posix_acl; then
+       echo "$test_name: $test_description: skipped (no posix_acl xattrs)"
+       rm -rf $MKFS_DIR
+       return 0
+fi
+
+$MKE2FS -q -F -o Linux -T ext4 -b 1024 -d $MKFS_DIR $TMPFILE 16384 > $OUT.new 2>&1
+
+$DEBUGFS -w -R "ea_list /acl_dir" $TMPFILE >> $OUT.new 2>&1
+sed -f $cmd_dir/filter.sed $OUT.new > $OUT
+rm -rf $MKFS_DIR $TMPFILE $OUT.new
+
+cmp -s $OUT $EXP
+status=$?
+
+if [ "$status" = 0 ] ; then
+       echo "$test_name: $test_description: ok"
+       touch $test_name.ok
+else
+        echo "$test_name: $test_description: failed"
+        diff $DIFF_OPTS $EXP $OUT > $test_name.failed
+fi
+
+unset MKFS_DIR OUT EXP
diff --git a/tests/d_trusted_fid/expect b/tests/d_trusted_fid/expect
new file mode 100644 (file)
index 0000000..e601771
--- /dev/null
@@ -0,0 +1,4 @@
+Extended attributes:
+  fid: parent=[0x200000402:0xc:0x0] stripe=1 stripe_size=1048576 stripe_count=2 layout_version=0 range=0
+Extended attributes:
+  fid: parent=[0x200000402:0x8:0x0] stripe=1 stripe_size=1048576 stripe_count=2 component_id=65537 component_start=0 component_end=18446744073709551615 layout_version=6 range=0
diff --git a/tests/d_trusted_fid/image.gz b/tests/d_trusted_fid/image.gz
new file mode 100644 (file)
index 0000000..9447f6f
Binary files /dev/null and b/tests/d_trusted_fid/image.gz differ
diff --git a/tests/d_trusted_fid/name b/tests/d_trusted_fid/name
new file mode 100644 (file)
index 0000000..bb7f001
--- /dev/null
@@ -0,0 +1 @@
+decode and print trusted.fid xattr in debugfs
diff --git a/tests/d_trusted_fid/script b/tests/d_trusted_fid/script
new file mode 100644 (file)
index 0000000..11ed9ad
--- /dev/null
@@ -0,0 +1,27 @@
+if ! test -x $DEBUGFS_EXE; then
+       echo "$test_name: $test_description: skipped (no debugfs)"
+       return 0
+fi
+
+IMAGE=$test_dir/image.gz
+EXP=$test_dir/expect
+OUT=$test_name.log
+gunzip < $IMAGE > $TMPFILE
+
+$DEBUGFS -w -R "ea_list /plain" $TMPFILE >> $OUT.new 2>&1
+$DEBUGFS -w -R "ea_list /pfl_flr" $TMPFILE >> $OUT.new 2>&1
+sed -f $cmd_dir/filter.sed $OUT.new > $OUT
+rm -f $TMPFILE $OUT.new
+
+cmp -s $OUT $EXP
+status=$?
+
+if [ "$status" = 0 ] ; then
+       echo "$test_name: $test_description: ok"
+       touch $test_name.ok
+else
+       echo "$test_name: $test_description: failed"
+       diff $DIFF_OPTS $EXP $OUT > $test_name.failed
+fi
+
+unset IMAGE EXP OUT
diff --git a/tests/d_trusted_link/expect b/tests/d_trusted_link/expect
new file mode 100644 (file)
index 0000000..5c2bbda
--- /dev/null
@@ -0,0 +1,12 @@
+Extended attributes:
+  linkea: idx=0 parent=[0x200000007:0x1:0x0] name='file'
+          idx=1 parent=[0x240000404:0x1:0x0] name='file-link-1'
+          idx=2 parent=[0x240000404:0x1:0x0] name='file-link-2'
+          idx=3 parent=[0x240000404:0x1:0x0] name='file-link-3'
+          idx=4 parent=[0x240000404:0x1:0x0] name='file-link-4'
+          idx=5 parent=[0x240000404:0x1:0x0] name='file-link-5'
+          idx=6 parent=[0x240000404:0x1:0x0] name='file-link-6'
+          idx=7 parent=[0x240000404:0x1:0x0] name='file-link-7'
+          idx=8 parent=[0x240000404:0x1:0x0] name='file-link-8'
+          idx=9 parent=[0x240000404:0x1:0x0] name='file-link-9'
+          idx=10 parent=[0x240000404:0x1:0x0] name='file-link-10'
diff --git a/tests/d_trusted_link/image.gz b/tests/d_trusted_link/image.gz
new file mode 100644 (file)
index 0000000..b3b7e1c
Binary files /dev/null and b/tests/d_trusted_link/image.gz differ
diff --git a/tests/d_trusted_link/name b/tests/d_trusted_link/name
new file mode 100644 (file)
index 0000000..d776f73
--- /dev/null
@@ -0,0 +1 @@
+decode and print trusted.link xattr in debugfs
diff --git a/tests/d_trusted_link/script b/tests/d_trusted_link/script
new file mode 100644 (file)
index 0000000..0d93015
--- /dev/null
@@ -0,0 +1,26 @@
+if ! test -x $DEBUGFS_EXE; then
+       echo "$test_name: $test_description: skipped (no debugfs)"
+       return 0
+fi
+
+IMAGE=$test_dir/image.gz
+EXP=$test_dir/expect
+OUT=$test_name.log
+gunzip < $IMAGE > $TMPFILE
+
+$DEBUGFS -w -R "ea_list /file" $TMPFILE >> $OUT.new 2>&1
+sed -f $cmd_dir/filter.sed $OUT.new > $OUT
+rm -f $TMPFILE $OUT.new
+
+cmp -s $OUT $EXP
+status=$?
+
+if [ "$status" = 0 ] ; then
+       echo "$test_name: $test_description: ok"
+       touch $test_name.ok
+else
+       echo "$test_name: $test_description: failed"
+       diff $DIFF_OPTS $EXP $OUT > $test_name.failed
+fi
+
+unset IMAGE EXP OUT
index 6a4d912..b961946 100644 (file)
@@ -36,7 +36,7 @@ ea_set -f d_xattr_edits.tmp / user.file_based_xattr
 Exit status is 0
 ea_list /
 Extended attributes:
-  user.file_based_xattr (108)
+  user.file_based_xattr (108) = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567\n"
 Exit status is 0
 ea_get / user.file_based_xattr
 user.file_based_xattr (108) = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567\n"
index 57f03e5..7bdb0a1 100644 (file)
@@ -10,8 +10,8 @@ Filesystem OS type:       Linux
 Inode count:              1024
 Block count:              16384
 Reserved block count:     819
-Overhead clusters:        1799
-Free blocks:              14533
+Overhead clusters:        2823
+Free blocks:              13509
 Free inodes:              1003
 First block:              1
 Block size:               1024
@@ -59,8 +59,8 @@ Group 1: (Blocks 8193-16383) [INODE_UNINIT]
   Block bitmap at 131 (bg #0 + 130)
   Inode bitmap at 133 (bg #0 + 132)
   Inode table at 390-645 (bg #0 + 389)
-  7038 free blocks, 512 free inodes, 0 directories, 512 unused inodes
-  Free blocks: 9346-16383
+  6014 free blocks, 512 free inodes, 0 directories, 512 unused inodes
+  Free blocks: 10370-16383
   Free inodes: 513-1024
 debugfs: stat /emptyfile
 Inode: III   Type: regular    
@@ -105,15 +105,30 @@ Extended attributes:
 debugfs: ea_list acl_dir
 Extended attributes:
   system.data (0)
-  system.posix_acl_access (28) = 01 00 00 00 01 00 07 00 04 00 05 00 08 00 05 00 2a 00 00 00 10 00 05 00 20 00 05 00 
-  system.posix_acl_default (28) = 01 00 00 00 01 00 07 00 04 00 05 00 08 00 05 00 04 00 00 00 10 00 05 00 20 00 05 00 
+  system.posix_acl_access:
+    user::rwx
+    group::r-x
+    group:42:r-x
+    mask::r-x
+    other::r-x
+  system.posix_acl_default:
+    user::rwx
+    group::r-x
+    group:4:r-x
+    mask::r-x
+    other::r-x
 debugfs: ea_list acl_dir/file
 Extended attributes:
   system.data (0)
-  system.posix_acl_access (28) = 01 00 00 00 01 00 07 00 04 00 05 00 08 00 05 00 2a 00 00 00 10 00 05 00 20 00 05 00 
+  system.posix_acl_access:
+    user::rwx
+    group::r-x
+    group:42:r-x
+    mask::r-x
+    other::r-x
 Pass 1: Checking inodes, blocks, and sizes
 Pass 2: Checking directory structure
 Pass 3: Checking directory connectivity
 Pass 4: Checking reference counts
 Pass 5: Checking group summary information
-test.img: 21/1024 files (0.0% non-contiguous), 1851/16384 blocks
+test.img: 21/1024 files (0.0% non-contiguous), 2875/16384 blocks
index 1251266..c9acffb 100755 (executable)
@@ -10,7 +10,8 @@ test "$num_failed" -eq 0 && exit 0
 
 echo -n "Tests failed: "
 for fname in $(ls *.failed); do
-       echo -n "${fname%%.failed} "
+       echo "${fname%%.failed} "
+       cat $fname
 done
 echo ""