1 /* 2 * FUSE: Filesystem in Userspace 3 * Copyright (C) 2016 Canonical Ltd. <seth.forshee@canonical.com> 4 * 5 * This program can be distributed under the terms of the GNU GPL. 6 * See the file COPYING. 7 */ 8 9 #include "fuse_i.h" 10 11 #include <linux/posix_acl.h> 12 #include <linux/posix_acl_xattr.h> 13 14 struct posix_acl *fuse_get_acl(struct inode *inode, int type) 15 { 16 struct fuse_conn *fc = get_fuse_conn(inode); 17 int size; 18 const char *name; 19 void *value = NULL; 20 struct posix_acl *acl; 21 22 if (!fc->posix_acl || fc->no_getxattr) 23 return NULL; 24 25 if (type == ACL_TYPE_ACCESS) 26 name = XATTR_NAME_POSIX_ACL_ACCESS; 27 else if (type == ACL_TYPE_DEFAULT) 28 name = XATTR_NAME_POSIX_ACL_DEFAULT; 29 else 30 return ERR_PTR(-EOPNOTSUPP); 31 32 value = kmalloc(PAGE_SIZE, GFP_KERNEL); 33 if (!value) 34 return ERR_PTR(-ENOMEM); 35 size = fuse_getxattr(inode, name, value, PAGE_SIZE); 36 if (size > 0) 37 acl = posix_acl_from_xattr(fc->user_ns, value, size); 38 else if ((size == 0) || (size == -ENODATA) || 39 (size == -EOPNOTSUPP && fc->no_getxattr)) 40 acl = NULL; 41 else if (size == -ERANGE) 42 acl = ERR_PTR(-E2BIG); 43 else 44 acl = ERR_PTR(size); 45 46 kfree(value); 47 return acl; 48 } 49 50 int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type) 51 { 52 struct fuse_conn *fc = get_fuse_conn(inode); 53 const char *name; 54 int ret; 55 56 if (!fc->posix_acl || fc->no_setxattr) 57 return -EOPNOTSUPP; 58 59 if (type == ACL_TYPE_ACCESS) 60 name = XATTR_NAME_POSIX_ACL_ACCESS; 61 else if (type == ACL_TYPE_DEFAULT) 62 name = XATTR_NAME_POSIX_ACL_DEFAULT; 63 else 64 return -EINVAL; 65 66 if (acl) { 67 /* 68 * Fuse userspace is responsible for updating access 69 * permissions in the inode, if needed. fuse_setxattr 70 * invalidates the inode attributes, which will force 71 * them to be refreshed the next time they are used, 72 * and it also updates i_ctime. 73 */ 74 size_t size = posix_acl_xattr_size(acl->a_count); 75 void *value; 76 77 if (size > PAGE_SIZE) 78 return -E2BIG; 79 80 value = kmalloc(size, GFP_KERNEL); 81 if (!value) 82 return -ENOMEM; 83 84 ret = posix_acl_to_xattr(fc->user_ns, acl, value, size); 85 if (ret < 0) { 86 kfree(value); 87 return ret; 88 } 89 90 ret = fuse_setxattr(inode, name, value, size, 0); 91 kfree(value); 92 } else { 93 ret = fuse_removexattr(inode, name); 94 } 95 forget_all_cached_acls(inode); 96 fuse_invalidate_attr(inode); 97 98 return ret; 99 } 100