linux/fs/fuse/acl.c
<<
>>
Prefs
   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
  14struct 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(&init_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
  50int 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(&init_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