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