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)
return;
}
break;
+ case 'r':
+ handle_flags |= XATTR_HANDLE_FLAG_RAW;
+ break;
case 'x':
print_flags |= PRINT_XATTR_HEX;
break;
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;
}
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;
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)
return;
}
break;
+ case 'r':
+ handle_flags |= XATTR_HANDLE_FLAG_RAW;
+ break;
default:
goto print_usage;
}
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;
}
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;
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 \
$(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 \
#include "ext2_fs.h"
#include "ext2_ext_attr.h"
+#include "ext4_acl.h"
#include "ext2fs.h"
struct ext2_xattr *attrs;
size_t length, count;
ext2_ino_t ino;
+ unsigned int flags;
int dirty;
};
}
+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,
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;
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;
/* 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;
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++;
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,
*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;
+}