2 * FUSE: Filesystem in Userspace
3 * Copyright (C) 2001-2016 Miklos Szeredi <miklos@szeredi.hu>
5 * This program can be distributed under the terms of the GNU GPL.
6 * See the file COPYING.
11 #include <linux/xattr.h>
12 #include <linux/posix_acl_xattr.h>
14 int fuse_setxattr(struct inode
*inode
, const char *name
, const void *value
,
15 size_t size
, int flags
)
17 struct fuse_mount
*fm
= get_fuse_mount(inode
);
19 struct fuse_setxattr_in inarg
;
22 if (fm
->fc
->no_setxattr
)
25 memset(&inarg
, 0, sizeof(inarg
));
28 args
.opcode
= FUSE_SETXATTR
;
29 args
.nodeid
= get_node_id(inode
);
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(fm
, &args
);
39 fm
->fc
->no_setxattr
= 1;
43 fuse_invalidate_attr(inode
);
44 fuse_update_ctime(inode
);
49 ssize_t
fuse_getxattr(struct inode
*inode
, const char *name
, void *value
,
52 struct fuse_mount
*fm
= get_fuse_mount(inode
);
54 struct fuse_getxattr_in inarg
;
55 struct fuse_getxattr_out outarg
;
58 if (fm
->fc
->no_getxattr
)
61 memset(&inarg
, 0, sizeof(inarg
));
63 args
.opcode
= FUSE_GETXATTR
;
64 args
.nodeid
= get_node_id(inode
);
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 */
73 args
.out_argvar
= true;
74 args
.out_args
[0].size
= size
;
75 args
.out_args
[0].value
= value
;
77 args
.out_args
[0].size
= sizeof(outarg
);
78 args
.out_args
[0].value
= &outarg
;
80 ret
= fuse_simple_request(fm
, &args
);
82 ret
= min_t(ssize_t
, outarg
.size
, XATTR_SIZE_MAX
);
84 fm
->fc
->no_getxattr
= 1;
90 static int fuse_verify_xattr_list(char *list
, size_t size
)
92 size_t origsize
= size
;
95 size_t thislen
= strnlen(list
, size
);
97 if (!thislen
|| thislen
== size
)
107 ssize_t
fuse_listxattr(struct dentry
*entry
, char *list
, size_t size
)
109 struct inode
*inode
= d_inode(entry
);
110 struct fuse_mount
*fm
= get_fuse_mount(inode
);
112 struct fuse_getxattr_in inarg
;
113 struct fuse_getxattr_out outarg
;
116 if (fuse_is_bad(inode
))
119 if (!fuse_allow_current_process(fm
->fc
))
122 if (fm
->fc
->no_listxattr
)
125 memset(&inarg
, 0, sizeof(inarg
));
127 args
.opcode
= FUSE_LISTXATTR
;
128 args
.nodeid
= get_node_id(inode
);
130 args
.in_args
[0].size
= sizeof(inarg
);
131 args
.in_args
[0].value
= &inarg
;
132 /* This is really two different operations rolled into one */
133 args
.out_numargs
= 1;
135 args
.out_argvar
= true;
136 args
.out_args
[0].size
= size
;
137 args
.out_args
[0].value
= list
;
139 args
.out_args
[0].size
= sizeof(outarg
);
140 args
.out_args
[0].value
= &outarg
;
142 ret
= fuse_simple_request(fm
, &args
);
144 ret
= min_t(ssize_t
, outarg
.size
, XATTR_LIST_MAX
);
146 ret
= fuse_verify_xattr_list(list
, ret
);
147 if (ret
== -ENOSYS
) {
148 fm
->fc
->no_listxattr
= 1;
154 int fuse_removexattr(struct inode
*inode
, const char *name
)
156 struct fuse_mount
*fm
= get_fuse_mount(inode
);
160 if (fm
->fc
->no_removexattr
)
163 args
.opcode
= FUSE_REMOVEXATTR
;
164 args
.nodeid
= get_node_id(inode
);
166 args
.in_args
[0].size
= strlen(name
) + 1;
167 args
.in_args
[0].value
= name
;
168 err
= fuse_simple_request(fm
, &args
);
169 if (err
== -ENOSYS
) {
170 fm
->fc
->no_removexattr
= 1;
174 fuse_invalidate_attr(inode
);
175 fuse_update_ctime(inode
);
180 static int fuse_xattr_get(const struct xattr_handler
*handler
,
181 struct dentry
*dentry
, struct inode
*inode
,
182 const char *name
, void *value
, size_t size
)
184 if (fuse_is_bad(inode
))
187 return fuse_getxattr(inode
, name
, value
, size
);
190 static int fuse_xattr_set(const struct xattr_handler
*handler
,
191 struct dentry
*dentry
, struct inode
*inode
,
192 const char *name
, const void *value
, size_t size
,
195 if (fuse_is_bad(inode
))
199 return fuse_removexattr(inode
, name
);
201 return fuse_setxattr(inode
, name
, value
, size
, flags
);
204 static bool no_xattr_list(struct dentry
*dentry
)
209 static int no_xattr_get(const struct xattr_handler
*handler
,
210 struct dentry
*dentry
, struct inode
*inode
,
211 const char *name
, void *value
, size_t size
)
216 static int no_xattr_set(const struct xattr_handler
*handler
,
217 struct dentry
*dentry
, struct inode
*nodee
,
218 const char *name
, const void *value
,
219 size_t size
, int flags
)
224 static const struct xattr_handler fuse_xattr_handler
= {
226 .get
= fuse_xattr_get
,
227 .set
= fuse_xattr_set
,
230 const struct xattr_handler
*fuse_xattr_handlers
[] = {
235 const struct xattr_handler
*fuse_acl_xattr_handlers
[] = {
236 &posix_acl_access_xattr_handler
,
237 &posix_acl_default_xattr_handler
,
242 static const struct xattr_handler fuse_no_acl_access_xattr_handler
= {
243 .name
= XATTR_NAME_POSIX_ACL_ACCESS
,
244 .flags
= ACL_TYPE_ACCESS
,
245 .list
= no_xattr_list
,
250 static const struct xattr_handler fuse_no_acl_default_xattr_handler
= {
251 .name
= XATTR_NAME_POSIX_ACL_DEFAULT
,
252 .flags
= ACL_TYPE_ACCESS
,
253 .list
= no_xattr_list
,
258 const struct xattr_handler
*fuse_no_acl_xattr_handlers
[] = {
259 &fuse_no_acl_access_xattr_handler
,
260 &fuse_no_acl_default_xattr_handler
,