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
, unsigned int extra_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 inarg
.setxattr_flags
= extra_flags
;
30 args
.opcode
= FUSE_SETXATTR
;
31 args
.nodeid
= get_node_id(inode
);
33 args
.in_args
[0].size
= fm
->fc
->setxattr_ext
?
34 sizeof(inarg
) : FUSE_COMPAT_SETXATTR_IN_SIZE
;
35 args
.in_args
[0].value
= &inarg
;
36 args
.in_args
[1].size
= strlen(name
) + 1;
37 args
.in_args
[1].value
= name
;
38 args
.in_args
[2].size
= size
;
39 args
.in_args
[2].value
= value
;
40 err
= fuse_simple_request(fm
, &args
);
42 fm
->fc
->no_setxattr
= 1;
46 fuse_update_ctime(inode
);
51 ssize_t
fuse_getxattr(struct inode
*inode
, const char *name
, void *value
,
54 struct fuse_mount
*fm
= get_fuse_mount(inode
);
56 struct fuse_getxattr_in inarg
;
57 struct fuse_getxattr_out outarg
;
60 if (fm
->fc
->no_getxattr
)
63 memset(&inarg
, 0, sizeof(inarg
));
65 args
.opcode
= FUSE_GETXATTR
;
66 args
.nodeid
= get_node_id(inode
);
68 args
.in_args
[0].size
= sizeof(inarg
);
69 args
.in_args
[0].value
= &inarg
;
70 args
.in_args
[1].size
= strlen(name
) + 1;
71 args
.in_args
[1].value
= name
;
72 /* This is really two different operations rolled into one */
75 args
.out_argvar
= true;
76 args
.out_args
[0].size
= size
;
77 args
.out_args
[0].value
= value
;
79 args
.out_args
[0].size
= sizeof(outarg
);
80 args
.out_args
[0].value
= &outarg
;
82 ret
= fuse_simple_request(fm
, &args
);
84 ret
= min_t(size_t, outarg
.size
, XATTR_SIZE_MAX
);
86 fm
->fc
->no_getxattr
= 1;
92 static int fuse_verify_xattr_list(char *list
, size_t size
)
94 size_t origsize
= size
;
97 size_t thislen
= strnlen(list
, size
);
99 if (!thislen
|| thislen
== size
)
109 ssize_t
fuse_listxattr(struct dentry
*entry
, char *list
, size_t size
)
111 struct inode
*inode
= d_inode(entry
);
112 struct fuse_mount
*fm
= get_fuse_mount(inode
);
114 struct fuse_getxattr_in inarg
;
115 struct fuse_getxattr_out outarg
;
118 if (fuse_is_bad(inode
))
121 if (!fuse_allow_current_process(fm
->fc
))
124 if (fm
->fc
->no_listxattr
)
127 memset(&inarg
, 0, sizeof(inarg
));
129 args
.opcode
= FUSE_LISTXATTR
;
130 args
.nodeid
= get_node_id(inode
);
132 args
.in_args
[0].size
= sizeof(inarg
);
133 args
.in_args
[0].value
= &inarg
;
134 /* This is really two different operations rolled into one */
135 args
.out_numargs
= 1;
137 args
.out_argvar
= true;
138 args
.out_args
[0].size
= size
;
139 args
.out_args
[0].value
= list
;
141 args
.out_args
[0].size
= sizeof(outarg
);
142 args
.out_args
[0].value
= &outarg
;
144 ret
= fuse_simple_request(fm
, &args
);
146 ret
= min_t(size_t, outarg
.size
, XATTR_LIST_MAX
);
148 ret
= fuse_verify_xattr_list(list
, ret
);
149 if (ret
== -ENOSYS
) {
150 fm
->fc
->no_listxattr
= 1;
156 int fuse_removexattr(struct inode
*inode
, const char *name
)
158 struct fuse_mount
*fm
= get_fuse_mount(inode
);
162 if (fm
->fc
->no_removexattr
)
165 args
.opcode
= FUSE_REMOVEXATTR
;
166 args
.nodeid
= get_node_id(inode
);
168 args
.in_args
[0].size
= strlen(name
) + 1;
169 args
.in_args
[0].value
= name
;
170 err
= fuse_simple_request(fm
, &args
);
171 if (err
== -ENOSYS
) {
172 fm
->fc
->no_removexattr
= 1;
176 fuse_update_ctime(inode
);
181 static int fuse_xattr_get(const struct xattr_handler
*handler
,
182 struct dentry
*dentry
, struct inode
*inode
,
183 const char *name
, void *value
, size_t size
)
185 if (fuse_is_bad(inode
))
188 return fuse_getxattr(inode
, name
, value
, size
);
191 static int fuse_xattr_set(const struct xattr_handler
*handler
,
192 struct mnt_idmap
*idmap
,
193 struct dentry
*dentry
, struct inode
*inode
,
194 const char *name
, const void *value
, size_t size
,
197 if (fuse_is_bad(inode
))
201 return fuse_removexattr(inode
, name
);
203 return fuse_setxattr(inode
, name
, value
, size
, flags
, 0);
206 static const struct xattr_handler fuse_xattr_handler
= {
208 .get
= fuse_xattr_get
,
209 .set
= fuse_xattr_set
,
212 const struct xattr_handler
* const fuse_xattr_handlers
[] = {