xref: /OK3568_Linux_fs/kernel/fs/fuse/xattr.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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