]>
Commit | Line | Data |
---|---|---|
703c7362 SF |
1 | /* |
2 | * FUSE: Filesystem in Userspace | |
3 | * Copyright (C) 2001-2016 Miklos Szeredi <[email protected]> | |
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 SF |
16 | { |
17 | struct fuse_conn *fc = get_fuse_conn(inode); | |
18 | FUSE_ARGS(args); | |
19 | struct fuse_setxattr_in inarg; | |
20 | int err; | |
21 | ||
22 | if (fc->no_setxattr) | |
23 | return -EOPNOTSUPP; | |
24 | ||
25 | memset(&inarg, 0, sizeof(inarg)); | |
26 | inarg.size = size; | |
27 | inarg.flags = flags; | |
28 | args.in.h.opcode = FUSE_SETXATTR; | |
29 | args.in.h.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; | |
37 | err = fuse_simple_request(fc, &args); | |
38 | if (err == -ENOSYS) { | |
39 | fc->no_setxattr = 1; | |
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 SF |
51 | { |
52 | struct fuse_conn *fc = get_fuse_conn(inode); | |
53 | FUSE_ARGS(args); | |
54 | struct fuse_getxattr_in inarg; | |
55 | struct fuse_getxattr_out outarg; | |
56 | ssize_t ret; | |
57 | ||
58 | if (fc->no_getxattr) | |
59 | return -EOPNOTSUPP; | |
60 | ||
61 | memset(&inarg, 0, sizeof(inarg)); | |
62 | inarg.size = size; | |
63 | args.in.h.opcode = FUSE_GETXATTR; | |
64 | args.in.h.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; | |
70 | /* This is really two different operations rolled into one */ | |
71 | args.out.numargs = 1; | |
72 | if (size) { | |
73 | args.out.argvar = 1; | |
74 | args.out.args[0].size = size; | |
75 | args.out.args[0].value = value; | |
76 | } else { | |
77 | args.out.args[0].size = sizeof(outarg); | |
78 | args.out.args[0].value = &outarg; | |
79 | } | |
80 | ret = fuse_simple_request(fc, &args); | |
81 | if (!ret && !size) | |
63401ccd | 82 | ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX); |
703c7362 SF |
83 | if (ret == -ENOSYS) { |
84 | fc->no_getxattr = 1; | |
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); | |
110 | struct fuse_conn *fc = get_fuse_conn(inode); | |
111 | FUSE_ARGS(args); | |
112 | struct fuse_getxattr_in inarg; | |
113 | struct fuse_getxattr_out outarg; | |
114 | ssize_t ret; | |
115 | ||
116 | if (!fuse_allow_current_process(fc)) | |
117 | return -EACCES; | |
118 | ||
119 | if (fc->no_listxattr) | |
120 | return -EOPNOTSUPP; | |
121 | ||
122 | memset(&inarg, 0, sizeof(inarg)); | |
123 | inarg.size = size; | |
124 | args.in.h.opcode = FUSE_LISTXATTR; | |
125 | args.in.h.nodeid = get_node_id(inode); | |
126 | args.in.numargs = 1; | |
127 | args.in.args[0].size = sizeof(inarg); | |
128 | args.in.args[0].value = &inarg; | |
129 | /* This is really two different operations rolled into one */ | |
130 | args.out.numargs = 1; | |
131 | if (size) { | |
132 | args.out.argvar = 1; | |
133 | args.out.args[0].size = size; | |
134 | args.out.args[0].value = list; | |
135 | } else { | |
136 | args.out.args[0].size = sizeof(outarg); | |
137 | args.out.args[0].value = &outarg; | |
138 | } | |
139 | ret = fuse_simple_request(fc, &args); | |
140 | if (!ret && !size) | |
63401ccd | 141 | ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX); |
703c7362 SF |
142 | if (ret > 0 && size) |
143 | ret = fuse_verify_xattr_list(list, ret); | |
144 | if (ret == -ENOSYS) { | |
145 | fc->no_listxattr = 1; | |
146 | ret = -EOPNOTSUPP; | |
147 | } | |
148 | return ret; | |
149 | } | |
150 | ||
60bcc88a | 151 | int fuse_removexattr(struct inode *inode, const char *name) |
703c7362 SF |
152 | { |
153 | struct fuse_conn *fc = get_fuse_conn(inode); | |
154 | FUSE_ARGS(args); | |
155 | int err; | |
156 | ||
157 | if (fc->no_removexattr) | |
158 | return -EOPNOTSUPP; | |
159 | ||
160 | args.in.h.opcode = FUSE_REMOVEXATTR; | |
161 | args.in.h.nodeid = get_node_id(inode); | |
162 | args.in.numargs = 1; | |
163 | args.in.args[0].size = strlen(name) + 1; | |
164 | args.in.args[0].value = name; | |
165 | err = fuse_simple_request(fc, &args); | |
166 | if (err == -ENOSYS) { | |
167 | fc->no_removexattr = 1; | |
168 | err = -EOPNOTSUPP; | |
169 | } | |
170 | if (!err) { | |
171 | fuse_invalidate_attr(inode); | |
172 | fuse_update_ctime(inode); | |
173 | } | |
174 | return err; | |
175 | } | |
176 | ||
177 | static int fuse_xattr_get(const struct xattr_handler *handler, | |
178 | struct dentry *dentry, struct inode *inode, | |
179 | const char *name, void *value, size_t size) | |
180 | { | |
181 | return fuse_getxattr(inode, name, value, size); | |
182 | } | |
183 | ||
184 | static int fuse_xattr_set(const struct xattr_handler *handler, | |
185 | struct dentry *dentry, struct inode *inode, | |
186 | const char *name, const void *value, size_t size, | |
187 | int flags) | |
188 | { | |
189 | if (!value) | |
190 | return fuse_removexattr(inode, name); | |
191 | ||
192 | return fuse_setxattr(inode, name, value, size, flags); | |
193 | } | |
194 | ||
e45b2546 EB |
195 | static bool no_xattr_list(struct dentry *dentry) |
196 | { | |
197 | return false; | |
198 | } | |
199 | ||
200 | static int no_xattr_get(const struct xattr_handler *handler, | |
201 | struct dentry *dentry, struct inode *inode, | |
202 | const char *name, void *value, size_t size) | |
203 | { | |
204 | return -EOPNOTSUPP; | |
205 | } | |
206 | ||
207 | static int no_xattr_set(const struct xattr_handler *handler, | |
208 | struct dentry *dentry, struct inode *nodee, | |
209 | const char *name, const void *value, | |
210 | size_t size, int flags) | |
211 | { | |
212 | return -EOPNOTSUPP; | |
213 | } | |
214 | ||
703c7362 SF |
215 | static const struct xattr_handler fuse_xattr_handler = { |
216 | .prefix = "", | |
217 | .get = fuse_xattr_get, | |
218 | .set = fuse_xattr_set, | |
219 | }; | |
220 | ||
221 | const struct xattr_handler *fuse_xattr_handlers[] = { | |
222 | &fuse_xattr_handler, | |
223 | NULL | |
224 | }; | |
60bcc88a SF |
225 | |
226 | const struct xattr_handler *fuse_acl_xattr_handlers[] = { | |
227 | &posix_acl_access_xattr_handler, | |
228 | &posix_acl_default_xattr_handler, | |
229 | &fuse_xattr_handler, | |
230 | NULL | |
231 | }; | |
e45b2546 EB |
232 | |
233 | static const struct xattr_handler fuse_no_acl_access_xattr_handler = { | |
234 | .name = XATTR_NAME_POSIX_ACL_ACCESS, | |
235 | .flags = ACL_TYPE_ACCESS, | |
236 | .list = no_xattr_list, | |
237 | .get = no_xattr_get, | |
238 | .set = no_xattr_set, | |
239 | }; | |
240 | ||
241 | static const struct xattr_handler fuse_no_acl_default_xattr_handler = { | |
242 | .name = XATTR_NAME_POSIX_ACL_DEFAULT, | |
243 | .flags = ACL_TYPE_ACCESS, | |
244 | .list = no_xattr_list, | |
245 | .get = no_xattr_get, | |
246 | .set = no_xattr_set, | |
247 | }; | |
248 | ||
249 | const struct xattr_handler *fuse_no_acl_xattr_handlers[] = { | |
250 | &fuse_no_acl_access_xattr_handler, | |
251 | &fuse_no_acl_default_xattr_handler, | |
252 | &fuse_xattr_handler, | |
253 | NULL | |
254 | }; |