int ext4_to_fuse_acl(acl_ea_header **facl, size_t *facl_sz, const ext4_acl_header *eacl, size_t eacl_sz) { int i, eacl_count; acl_ea_header *f; ext4_acl_entry *e; acl_ea_entry *a; size_t f_sz; unsigned char *hptr; int err = 0; eacl_count = ext4_acl_count(eacl_sz); f_sz = acl_ea_size(eacl_count); if (eacl_count < 0 || eacl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION)) return -EINVAL; f = malloc(f_sz); if (!f) return -ENOMEM; f->a_version = ACL_EA_VERSION; hptr = (unsigned char *) (eacl + 1); for (i = 0, a = f->a_entries; i < eacl_count; i++, a++) { e = (ext4_acl_entry *) hptr; a->e_tag = ext2fs_le16_to_cpu(e->e_tag); a->e_perm = ext2fs_le16_to_cpu(e->e_perm); switch (a->e_tag) { case ACL_USER: case ACL_GROUP: a->e_id = ext2fs_le32_to_cpu(e->e_id); hptr += sizeof(ext4_acl_entry); break; case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_MASK: case ACL_OTHER: hptr += sizeof(ext4_acl_entry_short); break; default: err = -EINVAL; goto out; } } *facl = f; *facl_sz = f_sz; return err; out: free(f); return err; }
/* * Convert from filesystem to in-memory representation. */ static struct posix_acl * ext4_acl_from_disk(const void *value, size_t size) { const char *end = (char *)value + size; int n, count; struct posix_acl *acl; if (!value) return NULL; if (size < sizeof(ext4_acl_header)) return ERR_PTR(-EINVAL); if (((ext4_acl_header *)value)->a_version != cpu_to_le32(EXT4_ACL_VERSION)) return ERR_PTR(-EINVAL); value = (char *)value + sizeof(ext4_acl_header); count = ext4_acl_count(size); if (count < 0) return ERR_PTR(-EINVAL); if (count == 0) return NULL; acl = posix_acl_alloc(count, GFP_NOFS); if (!acl) return ERR_PTR(-ENOMEM); for (n = 0; n < count; n++) { ext4_acl_entry *entry = (ext4_acl_entry *)value; if ((char *)value + sizeof(ext4_acl_entry_short) > end) goto fail; acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); switch (acl->a_entries[n].e_tag) { case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_MASK: case ACL_OTHER: value = (char *)value + sizeof(ext4_acl_entry_short); acl->a_entries[n].e_id = ACL_UNDEFINED_ID; break; case ACL_USER: case ACL_GROUP: value = (char *)value + sizeof(ext4_acl_entry); if ((char *)value > end) goto fail; acl->a_entries[n].e_id = le32_to_cpu(entry->e_id); break; default: goto fail; } } if (value != end) goto fail; return acl; fail: posix_acl_release(acl); return ERR_PTR(-EINVAL); }