/* * inode->i_sem: don't care */ static struct posix_acl * ext2_get_acl(struct inode *inode, int type) { const size_t max_size = ext2_acl_size(EXT2_ACL_MAX_ENTRIES); struct ext2_inode_info *ei = EXT2_I(inode); int name_index; char *value; struct posix_acl *acl; int retval; if (!test_opt(inode->i_sb, POSIX_ACL)) return 0; switch(type) { case ACL_TYPE_ACCESS: acl = ext2_iget_acl(inode, &ei->i_acl); if (acl != EXT2_ACL_NOT_CACHED) return acl; name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; break; case ACL_TYPE_DEFAULT: acl = ext2_iget_acl(inode, &ei->i_default_acl); if (acl != EXT2_ACL_NOT_CACHED) return acl; name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; break; default: return ERR_PTR(-EINVAL); } value = kmalloc(max_size, GFP_KERNEL); if (!value) return ERR_PTR(-ENOMEM); retval = ext2_xattr_get(inode, name_index, "", value, max_size); acl = ERR_PTR(retval); if (retval >= 0) acl = ext2_acl_from_disk(value, retval); else if (retval == -ENODATA || retval == -ENOSYS) acl = NULL; kfree(value); if (!IS_ERR(acl)) { switch(type) { case ACL_TYPE_ACCESS: ext2_iset_acl(inode, &ei->i_acl, acl); break; case ACL_TYPE_DEFAULT: ext2_iset_acl(inode, &ei->i_default_acl, acl); break; } } return acl; }
/* * Convert from in-memory to filesystem representation. */ static void * ext2_acl_to_disk(const struct posix_acl *acl, size_t *size) { ext2_acl_header *ext_acl; char *e; size_t n; *size = ext2_acl_size(acl->a_count); ext_acl = kmalloc(sizeof(ext2_acl_header) + acl->a_count * sizeof(ext2_acl_entry), GFP_KERNEL); if (!ext_acl) return ERR_PTR(-ENOMEM); ext_acl->a_version = cpu_to_le32(EXT2_ACL_VERSION); e = (char *)ext_acl + sizeof(ext2_acl_header); for (n=0; n < acl->a_count; n++) { const struct posix_acl_entry *acl_e = &acl->a_entries[n]; ext2_acl_entry *entry = (ext2_acl_entry *)e; entry->e_tag = cpu_to_le16(acl_e->e_tag); entry->e_perm = cpu_to_le16(acl_e->e_perm); switch(acl_e->e_tag) { case ACL_USER: entry->e_id = cpu_to_le32( from_kuid(&init_user_ns, acl_e->e_uid)); e += sizeof(ext2_acl_entry); break; case ACL_GROUP: entry->e_id = cpu_to_le32( from_kgid(&init_user_ns, acl_e->e_gid)); e += sizeof(ext2_acl_entry); break; case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_MASK: case ACL_OTHER: e += sizeof(ext2_acl_entry_short); break; default: goto fail; } } return (char *)ext_acl; fail: kfree(ext_acl); return ERR_PTR(-EINVAL); }