linux/fs/fuse/xattr.c
<<
>>
Prefs
   1/*
   2 * FUSE: Filesystem in Userspace
   3 * Copyright (C) 2001-2016  Miklos Szeredi <miklos@szeredi.hu>
   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/xattr.h>
  12#include <linux/posix_acl_xattr.h>
  13
  14int fuse_setxattr(struct inode *inode, const char *name, const void *value,
  15                  size_t size, int flags)
  16{
  17        struct fuse_conn *fc = get_fuse_conn(inode);
  18        FUSE_ARGS(args);
  19        struct fuse_setxattr_in inarg;
  20        int err;
  21
  22        if (fc->no_setxattr)
  23                return -EOPNOTSUPP;
  24
  25        memset(&inarg, 0, sizeof(inarg));
  26        inarg.size = size;
  27        inarg.flags = flags;
  28        args.opcode = FUSE_SETXATTR;
  29        args.nodeid = get_node_id(inode);
  30        args.in_numargs = 3;
  31        args.in_args[0].size = sizeof(inarg);
  32        args.in_args[0].value = &inarg;
  33        args.in_args[1].size = strlen(name) + 1;
  34        args.in_args[1].value = name;
  35        args.in_args[2].size = size;
  36        args.in_args[2].value = value;
  37        err = fuse_simple_request(fc, &args);
  38        if (err == -ENOSYS) {
  39                fc->no_setxattr = 1;
  40                err = -EOPNOTSUPP;
  41        }
  42        if (!err) {
  43                fuse_invalidate_attr(inode);
  44                fuse_update_ctime(inode);
  45        }
  46        return err;
  47}
  48
  49ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value,
  50                      size_t size)
  51{
  52        struct fuse_conn *fc = get_fuse_conn(inode);
  53        FUSE_ARGS(args);
  54        struct fuse_getxattr_in inarg;
  55        struct fuse_getxattr_out outarg;
  56        ssize_t ret;
  57
  58        if (fc->no_getxattr)
  59                return -EOPNOTSUPP;
  60
  61        memset(&inarg, 0, sizeof(inarg));
  62        inarg.size = size;
  63        args.opcode = FUSE_GETXATTR;
  64        args.nodeid = get_node_id(inode);
  65        args.in_numargs = 2;
  66        args.in_args[0].size = sizeof(inarg);
  67        args.in_args[0].value = &inarg;
  68        args.in_args[1].size = strlen(name) + 1;
  69        args.in_args[1].value = name;
  70        /* This is really two different operations rolled into one */
  71        args.out_numargs = 1;
  72        if (size) {
  73                args.out_argvar = true;
  74                args.out_args[0].size = size;
  75                args.out_args[0].value = value;
  76        } else {
  77                args.out_args[0].size = sizeof(outarg);
  78                args.out_args[0].value = &outarg;
  79        }
  80        ret = fuse_simple_request(fc, &args);
  81        if (!ret && !size)
  82                ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX);
  83        if (ret == -ENOSYS) {
  84                fc->no_getxattr = 1;
  85                ret = -EOPNOTSUPP;
  86        }
  87        return ret;
  88}
  89
  90static int fuse_verify_xattr_list(char *list, size_t size)
  91{
  92        size_t origsize = size;
  93
  94        while (size) {
  95                size_t thislen = strnlen(list, size);
  96
  97                if (!thislen || thislen == size)
  98                        return -EIO;
  99
 100                size -= thislen + 1;
 101                list += thislen + 1;
 102        }
 103
 104        return origsize;
 105}
 106
 107ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
 108{
 109        struct inode *inode = d_inode(entry);
 110        struct fuse_conn *fc = get_fuse_conn(inode);
 111        FUSE_ARGS(args);
 112        struct fuse_getxattr_in inarg;
 113        struct fuse_getxattr_out outarg;
 114        ssize_t ret;
 115
 116        if (!fuse_allow_current_process(fc))
 117                return -EACCES;
 118
 119        if (fc->no_listxattr)
 120                return -EOPNOTSUPP;
 121
 122        memset(&inarg, 0, sizeof(inarg));
 123        inarg.size = size;
 124        args.opcode = FUSE_LISTXATTR;
 125        args.nodeid = get_node_id(inode);
 126        args.in_numargs = 1;
 127        args.in_args[0].size = sizeof(inarg);
 128        args.in_args[0].value = &inarg;
 129        /* This is really two different operations rolled into one */
 130        args.out_numargs = 1;
 131        if (size) {
 132                args.out_argvar = true;
 133                args.out_args[0].size = size;
 134                args.out_args[0].value = list;
 135        } else {
 136                args.out_args[0].size = sizeof(outarg);
 137                args.out_args[0].value = &outarg;
 138        }
 139        ret = fuse_simple_request(fc, &args);
 140        if (!ret && !size)
 141                ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX);
 142        if (ret > 0 && size)
 143                ret = fuse_verify_xattr_list(list, ret);
 144        if (ret == -ENOSYS) {
 145                fc->no_listxattr = 1;
 146                ret = -EOPNOTSUPP;
 147        }
 148        return ret;
 149}
 150
 151int fuse_removexattr(struct inode *inode, const char *name)
 152{
 153        struct fuse_conn *fc = get_fuse_conn(inode);
 154        FUSE_ARGS(args);
 155        int err;
 156
 157        if (fc->no_removexattr)
 158                return -EOPNOTSUPP;
 159
 160        args.opcode = FUSE_REMOVEXATTR;
 161        args.nodeid = get_node_id(inode);
 162        args.in_numargs = 1;
 163        args.in_args[0].size = strlen(name) + 1;
 164        args.in_args[0].value = name;
 165        err = fuse_simple_request(fc, &args);
 166        if (err == -ENOSYS) {
 167                fc->no_removexattr = 1;
 168                err = -EOPNOTSUPP;
 169        }
 170        if (!err) {
 171                fuse_invalidate_attr(inode);
 172                fuse_update_ctime(inode);
 173        }
 174        return err;
 175}
 176
 177static int fuse_xattr_get(const struct xattr_handler *handler,
 178                         struct dentry *dentry, struct inode *inode,
 179                         const char *name, void *value, size_t size)
 180{
 181        return fuse_getxattr(inode, name, value, size);
 182}
 183
 184static int fuse_xattr_set(const struct xattr_handler *handler,
 185                          struct dentry *dentry, struct inode *inode,
 186                          const char *name, const void *value, size_t size,
 187                          int flags)
 188{
 189        if (!value)
 190                return fuse_removexattr(inode, name);
 191
 192        return fuse_setxattr(inode, name, value, size, flags);
 193}
 194
 195static bool no_xattr_list(struct dentry *dentry)
 196{
 197        return false;
 198}
 199
 200static int no_xattr_get(const struct xattr_handler *handler,
 201                        struct dentry *dentry, struct inode *inode,
 202                        const char *name, void *value, size_t size)
 203{
 204        return -EOPNOTSUPP;
 205}
 206
 207static int no_xattr_set(const struct xattr_handler *handler,
 208                        struct dentry *dentry, struct inode *nodee,
 209                        const char *name, const void *value,
 210                        size_t size, int flags)
 211{
 212        return -EOPNOTSUPP;
 213}
 214
 215static const struct xattr_handler fuse_xattr_handler = {
 216        .prefix = "",
 217        .get    = fuse_xattr_get,
 218        .set    = fuse_xattr_set,
 219};
 220
 221const struct xattr_handler *fuse_xattr_handlers[] = {
 222        &fuse_xattr_handler,
 223        NULL
 224};
 225
 226const struct xattr_handler *fuse_acl_xattr_handlers[] = {
 227        &posix_acl_access_xattr_handler,
 228        &posix_acl_default_xattr_handler,
 229        &fuse_xattr_handler,
 230        NULL
 231};
 232
 233static const struct xattr_handler fuse_no_acl_access_xattr_handler = {
 234        .name  = XATTR_NAME_POSIX_ACL_ACCESS,
 235        .flags = ACL_TYPE_ACCESS,
 236        .list  = no_xattr_list,
 237        .get   = no_xattr_get,
 238        .set   = no_xattr_set,
 239};
 240
 241static const struct xattr_handler fuse_no_acl_default_xattr_handler = {
 242        .name  = XATTR_NAME_POSIX_ACL_DEFAULT,
 243        .flags = ACL_TYPE_ACCESS,
 244        .list  = no_xattr_list,
 245        .get   = no_xattr_get,
 246        .set   = no_xattr_set,
 247};
 248
 249const struct xattr_handler *fuse_no_acl_xattr_handlers[] = {
 250        &fuse_no_acl_access_xattr_handler,
 251        &fuse_no_acl_default_xattr_handler,
 252        &fuse_xattr_handler,
 253        NULL
 254};
 255