Whamcloud - gitweb
libext2fs: translate internal ext4 acl to Posix ACL in ext2fs_xattr_[sg]et()
authorTheodore Ts'o <tytso@mit.edu>
Sun, 29 Jan 2017 03:34:16 +0000 (22:34 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Sun, 29 Jan 2017 03:34:16 +0000 (22:34 -0500)
ext2fs_xattr_[sg]et() will now translate the Posix ACL xattrs to and
from the internal ext4 attr format, since the callers of the libext2fs
are much more likely to want to use the public Posix ACL format.

For debugfs and those applications that want to see the on-disk
format, the new ext4fs_xattr_flags() function will allow those callers
to request the raw format.

Addresses-Launchpad-Bug: #1645232

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
debugfs/xattrs.c
lib/ext2fs/Makefile.in
lib/ext2fs/ext2fs.h
lib/ext2fs/ext4_acl.h [new file with mode: 0644]
lib/ext2fs/ext_attr.c
lib/support/Makefile.in

index bbf5863..1112da4 100644 (file)
@@ -146,10 +146,11 @@ void do_get_xattr(int argc, char **argv)
        size_t buflen;
        int i;
        int print_flags = 0;
+       int handle_flags = 0;
        errcode_t err;
 
        reset_getopt();
-       while ((i = getopt(argc, argv, "Cf:xV")) != -1) {
+       while ((i = getopt(argc, argv, "Cf:rxV")) != -1) {
                switch (i) {
                case 'f':
                        if (fp)
@@ -160,6 +161,9 @@ void do_get_xattr(int argc, char **argv)
                                return;
                        }
                        break;
+               case 'r':
+                       handle_flags |= XATTR_HANDLE_FLAG_RAW;
+                       break;
                case 'x':
                        print_flags |= PRINT_XATTR_HEX;
                        break;
@@ -176,8 +180,9 @@ void do_get_xattr(int argc, char **argv)
 
        if (optind != argc - 2) {
        usage:
-               printf("%s: Usage: %s <file> <attr> [-f outfile]|[-xVC]\n",
+               printf("%s: Usage: %s [-f outfile]|[-xVC] [-r] <file> <attr>\n",
                               argv[0], argv[0]);
+
                goto out2;
        }
 
@@ -192,6 +197,10 @@ void do_get_xattr(int argc, char **argv)
        if (err)
                goto out2;
 
+       err = ext2fs_xattrs_flags(h, &handle_flags, NULL);
+       if (err)
+               goto out;
+
        err = ext2fs_xattrs_read(h);
        if (err)
                goto out;
@@ -231,11 +240,13 @@ void do_set_xattr(int argc, char **argv)
        FILE *fp = NULL;
        char *buf = NULL;
        size_t buflen;
+       int print_flags = 0;
+       int handle_flags = 0;
        int i;
        errcode_t err;
 
        reset_getopt();
-       while ((i = getopt(argc, argv, "f:")) != -1) {
+       while ((i = getopt(argc, argv, "f:r")) != -1) {
                switch (i) {
                case 'f':
                        if (fp)
@@ -246,6 +257,9 @@ void do_set_xattr(int argc, char **argv)
                                return;
                        }
                        break;
+               case 'r':
+                       handle_flags |= XATTR_HANDLE_FLAG_RAW;
+                       break;
                default:
                        goto print_usage;
                }
@@ -254,7 +268,7 @@ void do_set_xattr(int argc, char **argv)
        if (!(fp && optind == argc - 2) && !(!fp && optind == argc - 3)) {
        print_usage:
                printf("Usage:\t%s <file> <attr> <value>\n", argv[0]);
-               printf("\t%s -f <value_file> <file> <attr>\n", argv[0]);
+               printf("\t%s -f <value_file> [-r] <file> <attr>\n", argv[0]);
                goto out2;
        }
 
@@ -273,6 +287,10 @@ void do_set_xattr(int argc, char **argv)
        if (err)
                goto out2;
 
+       err = ext2fs_xattrs_flags(h, &handle_flags, NULL);
+       if (err)
+               goto out;
+
        err = ext2fs_xattrs_read(h);
        if (err)
                goto out;
index 1e90dd8..2081da8 100644 (file)
@@ -789,8 +789,8 @@ expanddir.o: $(srcdir)/expanddir.c $(top_builddir)/lib/config.h \
 ext_attr.o: $(srcdir)/ext_attr.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
+ $(srcdir)/ext4_acl.h $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h \
+ $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
  $(srcdir)/bitops.h
 extent.o: $(srcdir)/extent.c $(top_builddir)/lib/config.h \
@@ -1319,11 +1319,11 @@ quota.o: $(top_srcdir)/debugfs/quota.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/support/dqblk_v2.h \
  $(top_srcdir)/lib/support/quotaio_tree.h
 xattrs.o: $(top_srcdir)/debugfs/xattrs.c $(top_builddir)/lib/config.h \
- $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
- $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
- $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/support/cstring.h \
+ $(top_srcdir)/debugfs/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(srcdir)/ext2fs.h $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
  $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
  $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/quotaio.h \
index 786ded8..8ff49ca 100644 (file)
@@ -1218,6 +1218,9 @@ errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino,
 errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count);
 errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino,
                                      size_t *size);
+#define XATTR_HANDLE_FLAG_RAW  0x0001
+errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle,
+                             unsigned int *new_flags, unsigned int *old_flags);
 
 /* extent.c */
 extern errcode_t ext2fs_extent_header_verify(void *ptr, int size);
diff --git a/lib/ext2fs/ext4_acl.h b/lib/ext2fs/ext4_acl.h
new file mode 100644 (file)
index 0000000..69ff79d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Ext4's on-disk acl format.  From linux/fs/ext4/acl.h
+ */
+
+#define EXT4_ACL_VERSION        0x0001
+
+/* 23.2.5 acl_tag_t values */
+
+#define ACL_UNDEFINED_TAG      (0x00)
+#define ACL_USER_OBJ           (0x01)
+#define ACL_USER               (0x02)
+#define ACL_GROUP_OBJ          (0x04)
+#define ACL_GROUP              (0x08)
+#define ACL_MASK               (0x10)
+#define ACL_OTHER              (0x20)
+
+/* 23.3.6 acl_type_t values */
+
+#define ACL_TYPE_ACCESS                (0x8000)
+#define ACL_TYPE_DEFAULT       (0x4000)
+
+/* 23.2.7 ACL qualifier constants */
+
+#define ACL_UNDEFINED_ID       ((id_t)-1)
+
+typedef struct {
+        __le16          e_tag;
+        __le16          e_perm;
+        __le32          e_id;
+ } ext4_acl_entry;
+typedef struct {
+        __le16          e_tag;
+        __le16          e_perm;
+} ext4_acl_entry_short;
+
+typedef struct {
+         __le32          a_version;
+} ext4_acl_header;
+
+
+/* Supported ACL a_version fields */
+ #define POSIX_ACL_XATTR_VERSION 0x0002
+
+typedef struct {
+        __le16                  e_tag;
+        __le16                  e_perm;
+        __le32                  e_id;
+} posix_acl_xattr_entry;
+
+typedef struct {
+        __le32                  a_version;
+        posix_acl_xattr_entry   a_entries[0];
+} posix_acl_xattr_header;
+
index 5eeb940..0314f9f 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "ext2_fs.h"
 #include "ext2_ext_attr.h"
+#include "ext4_acl.h"
 
 #include "ext2fs.h"
 
@@ -215,6 +216,7 @@ struct ext2_xattr_handle {
        struct ext2_xattr *attrs;
        size_t length, count;
        ext2_ino_t ino;
+       unsigned int flags;
        int dirty;
 };
 
@@ -452,6 +454,136 @@ out:
 }
 
 
+static inline int
+posix_acl_xattr_count(size_t size)
+{
+        if (size < sizeof(posix_acl_xattr_header))
+                return -1;
+        size -= sizeof(posix_acl_xattr_header);
+        if (size % sizeof(posix_acl_xattr_entry))
+                return -1;
+        return size / sizeof(posix_acl_xattr_entry);
+}
+
+/*
+ * The lgetxattr function returns data formatted in the POSIX extended
+ * attribute format.  The on-disk format uses a more compact encoding.
+ * See the ext4_acl_to_disk in fs/ext4/acl.c.
+ */
+static errcode_t convert_posix_acl_to_disk_buffer(const void *value, size_t size,
+                                                 void *out_buf, size_t *size_out)
+{
+       posix_acl_xattr_header *header = (posix_acl_xattr_header*) value;
+       posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
+       ext4_acl_header *ext_acl;
+       size_t s;
+       void *e;
+       int err;
+
+       int count;
+
+       if (!value)
+               return EINVAL;
+       if (size < sizeof(posix_acl_xattr_header))
+               return ENOMEM;
+       if (header->a_version != ext2fs_cpu_to_le32(POSIX_ACL_XATTR_VERSION))
+               return EINVAL;
+
+       count = posix_acl_xattr_count(size);
+       ext_acl = out_buf;
+       ext_acl->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION);
+
+       if (count <= 0)
+               return EINVAL;
+
+       e = (char *) out_buf + sizeof(ext4_acl_header);
+       s = sizeof(ext4_acl_header);
+       for (end = entry + count; entry != end;entry++) {
+               ext4_acl_entry *disk_entry = (ext4_acl_entry*) e;
+               disk_entry->e_tag = ext2fs_cpu_to_le16(entry->e_tag);
+               disk_entry->e_perm = ext2fs_cpu_to_le16(entry->e_perm);
+
+               switch(entry->e_tag) {
+                       case ACL_USER_OBJ:
+                       case ACL_GROUP_OBJ:
+                       case ACL_MASK:
+                       case ACL_OTHER:
+                               e += sizeof(ext4_acl_entry_short);
+                               s += sizeof(ext4_acl_entry_short);
+                               break;
+                       case ACL_USER:
+                       case ACL_GROUP:
+                               disk_entry->e_id =  ext2fs_cpu_to_le32(entry->e_id);
+                               e += sizeof(ext4_acl_entry);
+                               s += sizeof(ext4_acl_entry);
+                               break;
+               }
+       }
+       *size_out = s;
+       return 0;
+}
+
+static errcode_t convert_disk_buffer_to_posix_acl(const void *value, size_t size,
+                                                 void **out_buf, size_t *size_out)
+{
+       posix_acl_xattr_header *header;
+       posix_acl_xattr_entry *entry;
+       ext4_acl_header *ext_acl = (ext4_acl_header *) value;
+       errcode_t err;
+       const char *cp;
+       char *out;
+       int count;
+
+       if ((!value) ||
+           (size < sizeof(ext4_acl_header)) ||
+           (ext_acl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION)))
+               return EINVAL;
+
+       err = ext2fs_get_mem(size * 2, &out);
+       if (err)
+               return err;
+
+       header = (posix_acl_xattr_header *) out;
+       header->a_version = ext2fs_cpu_to_le32(POSIX_ACL_XATTR_VERSION);
+       entry = (posix_acl_xattr_entry *) (out + sizeof(posix_acl_xattr_header));
+
+       cp = value + sizeof(ext4_acl_header);
+       size -= sizeof(ext4_acl_header);
+
+       while (size > 0) {
+               const ext4_acl_entry *disk_entry = (const ext4_acl_entry *) cp;
+
+               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_GROUP_OBJ:
+                       case ACL_MASK:
+                       case ACL_OTHER:
+                               entry->e_id = 0;
+                               cp += sizeof(ext4_acl_entry_short);
+                               size -= sizeof(ext4_acl_entry_short);
+                               break;
+                       case ACL_USER:
+                       case ACL_GROUP:
+                               entry->e_id = ext2fs_le32_to_cpu(disk_entry->e_id);
+                               cp += sizeof(ext4_acl_entry);
+                               size -= sizeof(ext4_acl_entry);
+                               break;
+               default:
+                       ext2fs_free_mem(&out);
+                       return EINVAL;
+                       break;
+               }
+               entry++;
+       }
+       *out_buf = out;
+       *size_out = ((char *) entry - out);
+       return 0;
+}
+
+
 static errcode_t write_xattrs_to_buffer(struct ext2_xattr_handle *handle,
                                        struct ext2_xattr **pos,
                                        void *entries_start,
@@ -914,10 +1046,16 @@ errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
 
        EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
        for (x = h->attrs; x < h->attrs + h->length; x++) {
-               if (!x->name)
+               if (!x->name || strcmp(x->name, key))
                        continue;
 
-               if (strcmp(x->name, key) == 0) {
+               if (!(h->flags & XATTR_HANDLE_FLAG_RAW) &&
+                   ((strcmp(key, "system.posix_acl_default") == 0) ||
+                    (strcmp(key, "system.posix_acl_access") == 0))) {
+                       err = convert_disk_buffer_to_posix_acl(x->value, x->value_len,
+                                                              value, value_len);
+                       return err;
+               } else {
                        err = ext2fs_get_mem(x->value_len, &val);
                        if (err)
                                return err;
@@ -1002,6 +1140,20 @@ errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
 
        EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
        last_empty = NULL;
+
+       err = ext2fs_get_mem(value_len, &new_value);
+       if (err)
+               return err;
+       if (!(handle->flags & XATTR_HANDLE_FLAG_RAW) &&
+           ((strcmp(key, "system.posix_acl_default") == 0) ||
+            (strcmp(key, "system.posix_acl_access") == 0))) {
+               err = convert_posix_acl_to_disk_buffer(value, value_len,
+                                                      new_value, &value_len);
+               if (err)
+                       goto errout;
+       } else
+               memcpy(new_value, value, value_len);
+
        for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
                if (!x->name) {
                        last_empty = x;
@@ -1010,10 +1162,6 @@ errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
 
                /* Replace xattr */
                if (strcmp(x->name, key) == 0) {
-                       err = ext2fs_get_mem(value_len, &new_value);
-                       if (err)
-                               return err;
-                       memcpy(new_value, value, value_len);
                        ext2fs_free_mem(&x->value);
                        x->value = new_value;
                        x->value_len = value_len;
@@ -1026,13 +1174,9 @@ errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
        if (last_empty) {
                err = ext2fs_get_mem(strlen(key) + 1, &last_empty->name);
                if (err)
-                       return err;
+                       goto errout;
                strcpy(last_empty->name, key);
-
-               err = ext2fs_get_mem(value_len, &last_empty->value);
-               if (err)
-                       return err;
-               memcpy(last_empty->value, value, value_len);
+               last_empty->value = new_value;
                last_empty->value_len = value_len;
                handle->dirty = 1;
                handle->count++;
@@ -1058,6 +1202,9 @@ errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
        handle->dirty = 1;
        handle->count++;
        return 0;
+errout:
+       ext2fs_free_mem(&new_value);
+       return err;
 }
 
 errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
@@ -1137,3 +1284,14 @@ errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count)
        *count = handle->count;
        return 0;
 }
+
+errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle,
+                             unsigned int *new_flags, unsigned int *old_flags)
+{
+       EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
+       if (old_flags)
+               *old_flags = handle->flags;
+       if (new_flags)
+               handle->flags = *new_flags;
+       return 0;
+}
index cede23e..d5a6f26 100644 (file)
@@ -104,7 +104,7 @@ $(OBJS):
 argv_parse.o: $(srcdir)/argv_parse.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/argv_parse.h
 cstring.o: $(srcdir)/cstring.c $(top_builddir)/lib/config.h \
- $(top_builddir)/lib/dirpaths.h
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/cstring.h
 mkquota.o: $(srcdir)/mkquota.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \