| /* |
| * Copyright IBM Corporation, 2010 |
| * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of version 2.1 of the GNU Lesser General Public License |
| * as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it would be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| * |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/fs.h> |
| #include <net/9p/9p.h> |
| #include <net/9p/client.h> |
| #include <linux/slab.h> |
| #include <linux/posix_acl_xattr.h> |
| #include "xattr.h" |
| #include "acl.h" |
| |
| static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name) |
| { |
| ssize_t size; |
| void *value = NULL; |
| struct posix_acl *acl = NULL;; |
| |
| size = v9fs_fid_xattr_get(fid, name, NULL, 0); |
| if (size > 0) { |
| value = kzalloc(size, GFP_NOFS); |
| if (!value) |
| return ERR_PTR(-ENOMEM); |
| size = v9fs_fid_xattr_get(fid, name, value, size); |
| if (size > 0) { |
| acl = posix_acl_from_xattr(value, size); |
| if (IS_ERR(acl)) |
| goto err_out; |
| } |
| } else if (size == -ENODATA || size == 0 || |
| size == -ENOSYS || size == -EOPNOTSUPP) { |
| acl = NULL; |
| } else |
| acl = ERR_PTR(-EIO); |
| |
| err_out: |
| kfree(value); |
| return acl; |
| } |
| |
| int v9fs_get_acl(struct inode *inode, struct p9_fid *fid) |
| { |
| int retval = 0; |
| struct posix_acl *pacl, *dacl; |
| |
| /* get the default/access acl values and cache them */ |
| dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT); |
| pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS); |
| |
| if (!IS_ERR(dacl) && !IS_ERR(pacl)) { |
| set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl); |
| set_cached_acl(inode, ACL_TYPE_ACCESS, pacl); |
| posix_acl_release(dacl); |
| posix_acl_release(pacl); |
| } else |
| retval = -EIO; |
| |
| return retval; |
| } |
| |
| static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type) |
| { |
| struct posix_acl *acl; |
| /* |
| * 9p Always cache the acl value when |
| * instantiating the inode (v9fs_inode_from_fid) |
| */ |
| acl = get_cached_acl(inode, type); |
| BUG_ON(acl == ACL_NOT_CACHED); |
| return acl; |
| } |
| |
| int v9fs_check_acl(struct inode *inode, int mask) |
| { |
| struct posix_acl *acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS); |
| |
| if (IS_ERR(acl)) |
| return PTR_ERR(acl); |
| if (acl) { |
| int error = posix_acl_permission(inode, acl, mask); |
| posix_acl_release(acl); |
| return error; |
| } |
| return -EAGAIN; |
| } |