/* * Inode operation get_posix_acl(). * * inode->i_sem: don't care * BKL: held */ struct posix_acl * ext3_get_acl(struct inode *inode, int type) { const size_t max_size = ext3_acl_size(EXT3_ACL_MAX_ENTRIES); struct ext3_inode_info *ei = EXT3_I(inode); int name_index; char *value; struct posix_acl *acl; int retval; if (!IS_POSIXACL(inode)) return 0; switch(type) { case ACL_TYPE_ACCESS: if (ei->i_acl != EXT3_ACL_NOT_CACHED) return posix_acl_dup(ei->i_acl); name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; break; case ACL_TYPE_DEFAULT: if (ei->i_default_acl != EXT3_ACL_NOT_CACHED) return posix_acl_dup(ei->i_default_acl); name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; break; default: return ERR_PTR(-EINVAL); } value = kmalloc(max_size, GFP_KERNEL); if (!value) return ERR_PTR(-ENOMEM); retval = ext3_xattr_get(inode, name_index, "", value, max_size); acl = ERR_PTR(retval); if (retval > 0) acl = ext3_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: ei->i_acl = posix_acl_dup(acl); break; case ACL_TYPE_DEFAULT: ei->i_default_acl = posix_acl_dup(acl); break; } } return acl; }
/* * Convert from in-memory to filesystem representation. */ static void * ext3_acl_to_disk(const struct posix_acl *acl, size_t *size) { ext3_acl_header *ext_acl; char *e; size_t n; *size = ext3_acl_size(acl->a_count); ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) + acl->a_count * sizeof(ext3_acl_entry), GFP_KERNEL); if (!ext_acl) return ERR_PTR(-ENOMEM); ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION); e = (char *)ext_acl + sizeof(ext3_acl_header); for (n=0; n < acl->a_count; n++) { ext3_acl_entry *entry = (ext3_acl_entry *)e; entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); switch(acl->a_entries[n].e_tag) { case ACL_USER: case ACL_GROUP: entry->e_id = cpu_to_le32(acl->a_entries[n].e_id); e += sizeof(ext3_acl_entry); break; case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_MASK: case ACL_OTHER: e += sizeof(ext3_acl_entry_short); break; default: goto fail; } } return (char *)ext_acl; fail: kfree(ext_acl); return ERR_PTR(-EINVAL); }