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.in.h.opcode = FUSE_SETXATTR;
  29        args.in.h.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.in.h.opcode = FUSE_GETXATTR;
  64        args.in.h.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 = 1;
  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.in.h.opcode = FUSE_LISTXATTR;
 125        args.in.h.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 = 1;
 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.in.h.opcode = FUSE_REMOVEXATTR;
 161        args.in.h.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 const struct xattr_handler fuse_xattr_handler = {
 196        .prefix = "",
 197        .get    = fuse_xattr_get,
 198        .set    = fuse_xattr_set,
 199};
 200
 201const struct xattr_handler *fuse_xattr_handlers[] = {
 202        &fuse_xattr_handler,
 203        NULL
 204};
 205
 206const struct xattr_handler *fuse_acl_xattr_handlers[] = {
 207        &posix_acl_access_xattr_handler,
 208        &posix_acl_default_xattr_handler,
 209        &fuse_xattr_handler,
 210        NULL
 211};
 212