]>
Commit | Line | Data |
---|---|---|
703c7362 SF |
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> | |
60bcc88a | 12 | #include <linux/posix_acl_xattr.h> |
703c7362 | 13 | |
60bcc88a SF |
14 | int fuse_setxattr(struct inode *inode, const char *name, const void *value, |
15 | size_t size, int flags) | |
703c7362 | 16 | { |
fcee216b | 17 | struct fuse_mount *fm = get_fuse_mount(inode); |
703c7362 SF |
18 | FUSE_ARGS(args); |
19 | struct fuse_setxattr_in inarg; | |
20 | int err; | |
21 | ||
fcee216b | 22 | if (fm->fc->no_setxattr) |
703c7362 SF |
23 | return -EOPNOTSUPP; |
24 | ||
25 | memset(&inarg, 0, sizeof(inarg)); | |
26 | inarg.size = size; | |
27 | inarg.flags = flags; | |
d5b48543 MS |
28 | args.opcode = FUSE_SETXATTR; |
29 | args.nodeid = get_node_id(inode); | |
30 | args.in_numargs = 3; | |
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; | |
fcee216b | 37 | err = fuse_simple_request(fm, &args); |
703c7362 | 38 | if (err == -ENOSYS) { |
fcee216b | 39 | fm->fc->no_setxattr = 1; |
703c7362 SF |
40 | err = -EOPNOTSUPP; |
41 | } | |
42 | if (!err) { | |
43 | fuse_invalidate_attr(inode); | |
44 | fuse_update_ctime(inode); | |
45 | } | |
46 | return err; | |
47 | } | |
48 | ||
60bcc88a SF |
49 | ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value, |
50 | size_t size) | |
703c7362 | 51 | { |
fcee216b | 52 | struct fuse_mount *fm = get_fuse_mount(inode); |
703c7362 SF |
53 | FUSE_ARGS(args); |
54 | struct fuse_getxattr_in inarg; | |
55 | struct fuse_getxattr_out outarg; | |
56 | ssize_t ret; | |
57 | ||
fcee216b | 58 | if (fm->fc->no_getxattr) |
703c7362 SF |
59 | return -EOPNOTSUPP; |
60 | ||
61 | memset(&inarg, 0, sizeof(inarg)); | |
62 | inarg.size = size; | |
d5b48543 MS |
63 | args.opcode = FUSE_GETXATTR; |
64 | args.nodeid = get_node_id(inode); | |
65 | args.in_numargs = 2; | |
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; | |
703c7362 | 70 | /* This is really two different operations rolled into one */ |
d5b48543 | 71 | args.out_numargs = 1; |
703c7362 | 72 | if (size) { |
1f4e9d03 | 73 | args.out_argvar = true; |
d5b48543 MS |
74 | args.out_args[0].size = size; |
75 | args.out_args[0].value = value; | |
703c7362 | 76 | } else { |
d5b48543 MS |
77 | args.out_args[0].size = sizeof(outarg); |
78 | args.out_args[0].value = &outarg; | |
703c7362 | 79 | } |
fcee216b | 80 | ret = fuse_simple_request(fm, &args); |
703c7362 | 81 | if (!ret && !size) |
63401ccd | 82 | ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX); |
703c7362 | 83 | if (ret == -ENOSYS) { |
fcee216b | 84 | fm->fc->no_getxattr = 1; |
703c7362 SF |
85 | ret = -EOPNOTSUPP; |
86 | } | |
87 | return ret; | |
88 | } | |
89 | ||
90 | static int fuse_verify_xattr_list(char *list, size_t size) | |
91 | { | |
92 | size_t origsize = size; | |
93 | ||
94 | while (size) { | |
95 | size_t thislen = strnlen(list, size); | |
96 | ||
97 | if (!thislen || thislen == size) | |
98 | return -EIO; | |
99 | ||
100 | size -= thislen + 1; | |
101 | list += thislen + 1; | |
102 | } | |
103 | ||
104 | return origsize; | |
105 | } | |
106 | ||
107 | ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) | |
108 | { | |
109 | struct inode *inode = d_inode(entry); | |
fcee216b | 110 | struct fuse_mount *fm = get_fuse_mount(inode); |
703c7362 SF |
111 | FUSE_ARGS(args); |
112 | struct fuse_getxattr_in inarg; | |
113 | struct fuse_getxattr_out outarg; | |
114 | ssize_t ret; | |
115 | ||
5d069dbe MS |
116 | if (fuse_is_bad(inode)) |
117 | return -EIO; | |
118 | ||
fcee216b | 119 | if (!fuse_allow_current_process(fm->fc)) |
703c7362 SF |
120 | return -EACCES; |
121 | ||
fcee216b | 122 | if (fm->fc->no_listxattr) |
703c7362 SF |
123 | return -EOPNOTSUPP; |
124 | ||
125 | memset(&inarg, 0, sizeof(inarg)); | |
126 | inarg.size = size; | |
d5b48543 MS |
127 | args.opcode = FUSE_LISTXATTR; |
128 | args.nodeid = get_node_id(inode); | |
129 | args.in_numargs = 1; | |
130 | args.in_args[0].size = sizeof(inarg); | |
131 | args.in_args[0].value = &inarg; | |
703c7362 | 132 | /* This is really two different operations rolled into one */ |
d5b48543 | 133 | args.out_numargs = 1; |
703c7362 | 134 | if (size) { |
1f4e9d03 | 135 | args.out_argvar = true; |
d5b48543 MS |
136 | args.out_args[0].size = size; |
137 | args.out_args[0].value = list; | |
703c7362 | 138 | } else { |
d5b48543 MS |
139 | args.out_args[0].size = sizeof(outarg); |
140 | args.out_args[0].value = &outarg; | |
703c7362 | 141 | } |
fcee216b | 142 | ret = fuse_simple_request(fm, &args); |
703c7362 | 143 | if (!ret && !size) |
63401ccd | 144 | ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX); |
703c7362 SF |
145 | if (ret > 0 && size) |
146 | ret = fuse_verify_xattr_list(list, ret); | |
147 | if (ret == -ENOSYS) { | |
fcee216b | 148 | fm->fc->no_listxattr = 1; |
703c7362 SF |
149 | ret = -EOPNOTSUPP; |
150 | } | |
151 | return ret; | |
152 | } | |
153 | ||
60bcc88a | 154 | int fuse_removexattr(struct inode *inode, const char *name) |
703c7362 | 155 | { |
fcee216b | 156 | struct fuse_mount *fm = get_fuse_mount(inode); |
703c7362 SF |
157 | FUSE_ARGS(args); |
158 | int err; | |
159 | ||
fcee216b | 160 | if (fm->fc->no_removexattr) |
703c7362 SF |
161 | return -EOPNOTSUPP; |
162 | ||
d5b48543 MS |
163 | args.opcode = FUSE_REMOVEXATTR; |
164 | args.nodeid = get_node_id(inode); | |
165 | args.in_numargs = 1; | |
166 | args.in_args[0].size = strlen(name) + 1; | |
167 | args.in_args[0].value = name; | |
fcee216b | 168 | err = fuse_simple_request(fm, &args); |
703c7362 | 169 | if (err == -ENOSYS) { |
fcee216b | 170 | fm->fc->no_removexattr = 1; |
703c7362 SF |
171 | err = -EOPNOTSUPP; |
172 | } | |
173 | if (!err) { | |
174 | fuse_invalidate_attr(inode); | |
175 | fuse_update_ctime(inode); | |
176 | } | |
177 | return err; | |
178 | } | |
179 | ||
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) | |
183 | { | |
5d069dbe MS |
184 | if (fuse_is_bad(inode)) |
185 | return -EIO; | |
186 | ||
703c7362 SF |
187 | return fuse_getxattr(inode, name, value, size); |
188 | } | |
189 | ||
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, | |
193 | int flags) | |
194 | { | |
5d069dbe MS |
195 | if (fuse_is_bad(inode)) |
196 | return -EIO; | |
197 | ||
703c7362 SF |
198 | if (!value) |
199 | return fuse_removexattr(inode, name); | |
200 | ||
201 | return fuse_setxattr(inode, name, value, size, flags); | |
202 | } | |
203 | ||
e45b2546 EB |
204 | static bool no_xattr_list(struct dentry *dentry) |
205 | { | |
206 | return false; | |
207 | } | |
208 | ||
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) | |
212 | { | |
213 | return -EOPNOTSUPP; | |
214 | } | |
215 | ||
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) | |
220 | { | |
221 | return -EOPNOTSUPP; | |
222 | } | |
223 | ||
703c7362 SF |
224 | static const struct xattr_handler fuse_xattr_handler = { |
225 | .prefix = "", | |
226 | .get = fuse_xattr_get, | |
227 | .set = fuse_xattr_set, | |
228 | }; | |
229 | ||
230 | const struct xattr_handler *fuse_xattr_handlers[] = { | |
231 | &fuse_xattr_handler, | |
232 | NULL | |
233 | }; | |
60bcc88a SF |
234 | |
235 | const struct xattr_handler *fuse_acl_xattr_handlers[] = { | |
236 | &posix_acl_access_xattr_handler, | |
237 | &posix_acl_default_xattr_handler, | |
238 | &fuse_xattr_handler, | |
239 | NULL | |
240 | }; | |
e45b2546 EB |
241 | |
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, | |
246 | .get = no_xattr_get, | |
247 | .set = no_xattr_set, | |
248 | }; | |
249 | ||
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, | |
254 | .get = no_xattr_get, | |
255 | .set = no_xattr_set, | |
256 | }; | |
257 | ||
258 | const struct xattr_handler *fuse_no_acl_xattr_handlers[] = { | |
259 | &fuse_no_acl_access_xattr_handler, | |
260 | &fuse_no_acl_default_xattr_handler, | |
261 | &fuse_xattr_handler, | |
262 | NULL | |
263 | }; |