Branch data Line data Source code
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 : : 14 : 0 : int 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 : 0 : FUSE_ARGS(args); 19 : : struct fuse_setxattr_in inarg; 20 : : int err; 21 : : 22 : 0 : if (fc->no_setxattr) 23 : : return -EOPNOTSUPP; 24 : : 25 : 0 : memset(&inarg, 0, sizeof(inarg)); 26 : 0 : inarg.size = size; 27 : 0 : inarg.flags = flags; 28 : 0 : args.opcode = FUSE_SETXATTR; 29 : 0 : args.nodeid = get_node_id(inode); 30 : 0 : args.in_numargs = 3; 31 : 0 : args.in_args[0].size = sizeof(inarg); 32 : 0 : args.in_args[0].value = &inarg; 33 : 0 : args.in_args[1].size = strlen(name) + 1; 34 : 0 : args.in_args[1].value = name; 35 : 0 : args.in_args[2].size = size; 36 : 0 : args.in_args[2].value = value; 37 : 0 : err = fuse_simple_request(fc, &args); 38 : 0 : if (err == -ENOSYS) { 39 : 0 : fc->no_setxattr = 1; 40 : : err = -EOPNOTSUPP; 41 : : } 42 : 0 : if (!err) { 43 : 0 : fuse_invalidate_attr(inode); 44 : 0 : fuse_update_ctime(inode); 45 : : } 46 : 0 : return err; 47 : : } 48 : : 49 : 0 : ssize_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 : 0 : FUSE_ARGS(args); 54 : : struct fuse_getxattr_in inarg; 55 : : struct fuse_getxattr_out outarg; 56 : : ssize_t ret; 57 : : 58 : 0 : if (fc->no_getxattr) 59 : : return -EOPNOTSUPP; 60 : : 61 : 0 : memset(&inarg, 0, sizeof(inarg)); 62 : 0 : inarg.size = size; 63 : 0 : args.opcode = FUSE_GETXATTR; 64 : 0 : args.nodeid = get_node_id(inode); 65 : 0 : args.in_numargs = 2; 66 : 0 : args.in_args[0].size = sizeof(inarg); 67 : 0 : args.in_args[0].value = &inarg; 68 : 0 : args.in_args[1].size = strlen(name) + 1; 69 : 0 : args.in_args[1].value = name; 70 : : /* This is really two different operations rolled into one */ 71 : 0 : args.out_numargs = 1; 72 : 0 : if (size) { 73 : 0 : args.out_argvar = true; 74 : 0 : args.out_args[0].size = size; 75 : 0 : args.out_args[0].value = value; 76 : : } else { 77 : 0 : args.out_args[0].size = sizeof(outarg); 78 : 0 : args.out_args[0].value = &outarg; 79 : : } 80 : 0 : ret = fuse_simple_request(fc, &args); 81 : 0 : if (!ret && !size) 82 : 0 : ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX); 83 : 0 : if (ret == -ENOSYS) { 84 : 0 : fc->no_getxattr = 1; 85 : : ret = -EOPNOTSUPP; 86 : : } 87 : 0 : return ret; 88 : : } 89 : : 90 : 0 : static int fuse_verify_xattr_list(char *list, size_t size) 91 : : { 92 : : size_t origsize = size; 93 : : 94 : 0 : while (size) { 95 : 0 : size_t thislen = strnlen(list, size); 96 : : 97 : 0 : if (!thislen || thislen == size) 98 : : return -EIO; 99 : : 100 : 0 : size -= thislen + 1; 101 : 0 : list += thislen + 1; 102 : : } 103 : : 104 : 0 : return origsize; 105 : : } 106 : : 107 : 0 : ssize_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 : 0 : FUSE_ARGS(args); 112 : : struct fuse_getxattr_in inarg; 113 : : struct fuse_getxattr_out outarg; 114 : : ssize_t ret; 115 : : 116 : 0 : if (!fuse_allow_current_process(fc)) 117 : : return -EACCES; 118 : : 119 : 0 : if (fc->no_listxattr) 120 : : return -EOPNOTSUPP; 121 : : 122 : 0 : memset(&inarg, 0, sizeof(inarg)); 123 : 0 : inarg.size = size; 124 : 0 : args.opcode = FUSE_LISTXATTR; 125 : 0 : args.nodeid = get_node_id(inode); 126 : 0 : args.in_numargs = 1; 127 : 0 : args.in_args[0].size = sizeof(inarg); 128 : 0 : args.in_args[0].value = &inarg; 129 : : /* This is really two different operations rolled into one */ 130 : 0 : args.out_numargs = 1; 131 : 0 : if (size) { 132 : 0 : args.out_argvar = true; 133 : 0 : args.out_args[0].size = size; 134 : 0 : args.out_args[0].value = list; 135 : : } else { 136 : 0 : args.out_args[0].size = sizeof(outarg); 137 : 0 : args.out_args[0].value = &outarg; 138 : : } 139 : 0 : ret = fuse_simple_request(fc, &args); 140 : 0 : if (!ret && !size) 141 : 0 : ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX); 142 : 0 : if (ret > 0 && size) 143 : 0 : ret = fuse_verify_xattr_list(list, ret); 144 : 0 : if (ret == -ENOSYS) { 145 : 0 : fc->no_listxattr = 1; 146 : : ret = -EOPNOTSUPP; 147 : : } 148 : 0 : return ret; 149 : : } 150 : : 151 : 0 : int fuse_removexattr(struct inode *inode, const char *name) 152 : : { 153 : : struct fuse_conn *fc = get_fuse_conn(inode); 154 : 0 : FUSE_ARGS(args); 155 : : int err; 156 : : 157 : 0 : if (fc->no_removexattr) 158 : : return -EOPNOTSUPP; 159 : : 160 : 0 : args.opcode = FUSE_REMOVEXATTR; 161 : 0 : args.nodeid = get_node_id(inode); 162 : 0 : args.in_numargs = 1; 163 : 0 : args.in_args[0].size = strlen(name) + 1; 164 : 0 : args.in_args[0].value = name; 165 : 0 : err = fuse_simple_request(fc, &args); 166 : 0 : if (err == -ENOSYS) { 167 : 0 : fc->no_removexattr = 1; 168 : : err = -EOPNOTSUPP; 169 : : } 170 : 0 : if (!err) { 171 : 0 : fuse_invalidate_attr(inode); 172 : 0 : fuse_update_ctime(inode); 173 : : } 174 : 0 : return err; 175 : : } 176 : : 177 : 0 : static 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 : 0 : return fuse_getxattr(inode, name, value, size); 182 : : } 183 : : 184 : 0 : static 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 : 0 : if (!value) 190 : 0 : return fuse_removexattr(inode, name); 191 : : 192 : 0 : return fuse_setxattr(inode, name, value, size, flags); 193 : : } 194 : : 195 : 0 : static bool no_xattr_list(struct dentry *dentry) 196 : : { 197 : 0 : return false; 198 : : } 199 : : 200 : 0 : static 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 : 0 : return -EOPNOTSUPP; 205 : : } 206 : : 207 : 0 : static 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 : 0 : return -EOPNOTSUPP; 213 : : } 214 : : 215 : : static const struct xattr_handler fuse_xattr_handler = { 216 : : .prefix = "", 217 : : .get = fuse_xattr_get, 218 : : .set = fuse_xattr_set, 219 : : }; 220 : : 221 : : const struct xattr_handler *fuse_xattr_handlers[] = { 222 : : &fuse_xattr_handler, 223 : : NULL 224 : : }; 225 : : 226 : : const 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 : : 233 : : static 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 : : 241 : : static 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 : : 249 : : const 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 : : };