18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * FUSE: Filesystem in Userspace 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Canonical Ltd. <seth.forshee@canonical.com> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This program can be distributed under the terms of the GNU GPL. 68c2ecf20Sopenharmony_ci * See the file COPYING. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "fuse_i.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/posix_acl.h> 128c2ecf20Sopenharmony_ci#include <linux/posix_acl_xattr.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistruct posix_acl *fuse_get_acl(struct inode *inode, int type) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 178c2ecf20Sopenharmony_ci int size; 188c2ecf20Sopenharmony_ci const char *name; 198c2ecf20Sopenharmony_ci void *value = NULL; 208c2ecf20Sopenharmony_ci struct posix_acl *acl; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci if (fuse_is_bad(inode)) 238c2ecf20Sopenharmony_ci return ERR_PTR(-EIO); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci if (!fc->posix_acl || fc->no_getxattr) 268c2ecf20Sopenharmony_ci return NULL; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci if (type == ACL_TYPE_ACCESS) 298c2ecf20Sopenharmony_ci name = XATTR_NAME_POSIX_ACL_ACCESS; 308c2ecf20Sopenharmony_ci else if (type == ACL_TYPE_DEFAULT) 318c2ecf20Sopenharmony_ci name = XATTR_NAME_POSIX_ACL_DEFAULT; 328c2ecf20Sopenharmony_ci else 338c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci value = kmalloc(PAGE_SIZE, GFP_KERNEL); 368c2ecf20Sopenharmony_ci if (!value) 378c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 388c2ecf20Sopenharmony_ci size = fuse_getxattr(inode, name, value, PAGE_SIZE); 398c2ecf20Sopenharmony_ci if (size > 0) 408c2ecf20Sopenharmony_ci acl = posix_acl_from_xattr(fc->user_ns, value, size); 418c2ecf20Sopenharmony_ci else if ((size == 0) || (size == -ENODATA) || 428c2ecf20Sopenharmony_ci (size == -EOPNOTSUPP && fc->no_getxattr)) 438c2ecf20Sopenharmony_ci acl = NULL; 448c2ecf20Sopenharmony_ci else if (size == -ERANGE) 458c2ecf20Sopenharmony_ci acl = ERR_PTR(-E2BIG); 468c2ecf20Sopenharmony_ci else 478c2ecf20Sopenharmony_ci acl = ERR_PTR(size); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci kfree(value); 508c2ecf20Sopenharmony_ci return acl; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciint fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct fuse_conn *fc = get_fuse_conn(inode); 568c2ecf20Sopenharmony_ci const char *name; 578c2ecf20Sopenharmony_ci int ret; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (fuse_is_bad(inode)) 608c2ecf20Sopenharmony_ci return -EIO; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (!fc->posix_acl || fc->no_setxattr) 638c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (type == ACL_TYPE_ACCESS) 668c2ecf20Sopenharmony_ci name = XATTR_NAME_POSIX_ACL_ACCESS; 678c2ecf20Sopenharmony_ci else if (type == ACL_TYPE_DEFAULT) 688c2ecf20Sopenharmony_ci name = XATTR_NAME_POSIX_ACL_DEFAULT; 698c2ecf20Sopenharmony_ci else 708c2ecf20Sopenharmony_ci return -EINVAL; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (acl) { 738c2ecf20Sopenharmony_ci /* 748c2ecf20Sopenharmony_ci * Fuse userspace is responsible for updating access 758c2ecf20Sopenharmony_ci * permissions in the inode, if needed. fuse_setxattr 768c2ecf20Sopenharmony_ci * invalidates the inode attributes, which will force 778c2ecf20Sopenharmony_ci * them to be refreshed the next time they are used, 788c2ecf20Sopenharmony_ci * and it also updates i_ctime. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci size_t size = posix_acl_xattr_size(acl->a_count); 818c2ecf20Sopenharmony_ci void *value; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (size > PAGE_SIZE) 848c2ecf20Sopenharmony_ci return -E2BIG; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci value = kmalloc(size, GFP_KERNEL); 878c2ecf20Sopenharmony_ci if (!value) 888c2ecf20Sopenharmony_ci return -ENOMEM; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci ret = posix_acl_to_xattr(fc->user_ns, acl, value, size); 918c2ecf20Sopenharmony_ci if (ret < 0) { 928c2ecf20Sopenharmony_ci kfree(value); 938c2ecf20Sopenharmony_ci return ret; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci ret = fuse_setxattr(inode, name, value, size, 0); 978c2ecf20Sopenharmony_ci kfree(value); 988c2ecf20Sopenharmony_ci } else { 998c2ecf20Sopenharmony_ci ret = fuse_removexattr(inode, name); 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci forget_all_cached_acls(inode); 1028c2ecf20Sopenharmony_ci fuse_invalidate_attr(inode); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return ret; 1058c2ecf20Sopenharmony_ci} 106