Branch data Line data Source code
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>
12 : : #include <linux/posix_acl_xattr.h>
13 : :
14 : 0 : int fuse_setxattr(struct inode *inode, const char *name, const void *value,
15 : : size_t size, int flags)
16 : : {
17 : : struct fuse_conn *fc = get_fuse_conn(inode);
18 : 0 : FUSE_ARGS(args);
19 : : struct fuse_setxattr_in inarg;
20 : : int err;
21 : :
22 [ # # ]: 0 : if (fc->no_setxattr)
23 : : return -EOPNOTSUPP;
24 : :
25 : 0 : memset(&inarg, 0, sizeof(inarg));
26 : 0 : inarg.size = size;
27 : 0 : inarg.flags = flags;
28 : 0 : args.opcode = FUSE_SETXATTR;
29 : 0 : args.nodeid = get_node_id(inode);
30 : 0 : args.in_numargs = 3;
31 : 0 : args.in_args[0].size = sizeof(inarg);
32 : 0 : args.in_args[0].value = &inarg;
33 : 0 : args.in_args[1].size = strlen(name) + 1;
34 : 0 : args.in_args[1].value = name;
35 : 0 : args.in_args[2].size = size;
36 : 0 : args.in_args[2].value = value;
37 : 0 : err = fuse_simple_request(fc, &args);
38 [ # # ]: 0 : if (err == -ENOSYS) {
39 : 0 : fc->no_setxattr = 1;
40 : : err = -EOPNOTSUPP;
41 : : }
42 [ # # ]: 0 : if (!err) {
43 : 0 : fuse_invalidate_attr(inode);
44 : 0 : fuse_update_ctime(inode);
45 : : }
46 : 0 : return err;
47 : : }
48 : :
49 : 0 : ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value,
50 : : size_t size)
51 : : {
52 : : struct fuse_conn *fc = get_fuse_conn(inode);
53 : 0 : FUSE_ARGS(args);
54 : : struct fuse_getxattr_in inarg;
55 : : struct fuse_getxattr_out outarg;
56 : : ssize_t ret;
57 : :
58 [ # # ]: 0 : if (fc->no_getxattr)
59 : : return -EOPNOTSUPP;
60 : :
61 : 0 : memset(&inarg, 0, sizeof(inarg));
62 : 0 : inarg.size = size;
63 : 0 : args.opcode = FUSE_GETXATTR;
64 : 0 : args.nodeid = get_node_id(inode);
65 : 0 : args.in_numargs = 2;
66 : 0 : args.in_args[0].size = sizeof(inarg);
67 : 0 : args.in_args[0].value = &inarg;
68 : 0 : args.in_args[1].size = strlen(name) + 1;
69 : 0 : args.in_args[1].value = name;
70 : : /* This is really two different operations rolled into one */
71 : 0 : args.out_numargs = 1;
72 [ # # ]: 0 : if (size) {
73 : 0 : args.out_argvar = true;
74 : 0 : args.out_args[0].size = size;
75 : 0 : args.out_args[0].value = value;
76 : : } else {
77 : 0 : args.out_args[0].size = sizeof(outarg);
78 : 0 : args.out_args[0].value = &outarg;
79 : : }
80 : 0 : ret = fuse_simple_request(fc, &args);
81 [ # # ]: 0 : if (!ret && !size)
82 : 0 : ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX);
83 [ # # ]: 0 : if (ret == -ENOSYS) {
84 : 0 : fc->no_getxattr = 1;
85 : : ret = -EOPNOTSUPP;
86 : : }
87 : 0 : return ret;
88 : : }
89 : :
90 : 0 : static int fuse_verify_xattr_list(char *list, size_t size)
91 : : {
92 : : size_t origsize = size;
93 : :
94 [ # # ]: 0 : while (size) {
95 : 0 : size_t thislen = strnlen(list, size);
96 : :
97 [ # # ]: 0 : if (!thislen || thislen == size)
98 : : return -EIO;
99 : :
100 : 0 : size -= thislen + 1;
101 : 0 : list += thislen + 1;
102 : : }
103 : :
104 : 0 : return origsize;
105 : : }
106 : :
107 : 0 : 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 : 0 : FUSE_ARGS(args);
112 : : struct fuse_getxattr_in inarg;
113 : : struct fuse_getxattr_out outarg;
114 : : ssize_t ret;
115 : :
116 [ # # ]: 0 : if (!fuse_allow_current_process(fc))
117 : : return -EACCES;
118 : :
119 [ # # ]: 0 : if (fc->no_listxattr)
120 : : return -EOPNOTSUPP;
121 : :
122 : 0 : memset(&inarg, 0, sizeof(inarg));
123 : 0 : inarg.size = size;
124 : 0 : args.opcode = FUSE_LISTXATTR;
125 : 0 : args.nodeid = get_node_id(inode);
126 : 0 : args.in_numargs = 1;
127 : 0 : args.in_args[0].size = sizeof(inarg);
128 : 0 : args.in_args[0].value = &inarg;
129 : : /* This is really two different operations rolled into one */
130 : 0 : args.out_numargs = 1;
131 [ # # ]: 0 : if (size) {
132 : 0 : args.out_argvar = true;
133 : 0 : args.out_args[0].size = size;
134 : 0 : args.out_args[0].value = list;
135 : : } else {
136 : 0 : args.out_args[0].size = sizeof(outarg);
137 : 0 : args.out_args[0].value = &outarg;
138 : : }
139 : 0 : ret = fuse_simple_request(fc, &args);
140 [ # # ]: 0 : if (!ret && !size)
141 : 0 : ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX);
142 [ # # ]: 0 : if (ret > 0 && size)
143 : 0 : ret = fuse_verify_xattr_list(list, ret);
144 [ # # ]: 0 : if (ret == -ENOSYS) {
145 : 0 : fc->no_listxattr = 1;
146 : : ret = -EOPNOTSUPP;
147 : : }
148 : 0 : return ret;
149 : : }
150 : :
151 : 0 : int fuse_removexattr(struct inode *inode, const char *name)
152 : : {
153 : : struct fuse_conn *fc = get_fuse_conn(inode);
154 : 0 : FUSE_ARGS(args);
155 : : int err;
156 : :
157 [ # # ]: 0 : if (fc->no_removexattr)
158 : : return -EOPNOTSUPP;
159 : :
160 : 0 : args.opcode = FUSE_REMOVEXATTR;
161 : 0 : args.nodeid = get_node_id(inode);
162 : 0 : args.in_numargs = 1;
163 : 0 : args.in_args[0].size = strlen(name) + 1;
164 : 0 : args.in_args[0].value = name;
165 : 0 : err = fuse_simple_request(fc, &args);
166 [ # # ]: 0 : if (err == -ENOSYS) {
167 : 0 : fc->no_removexattr = 1;
168 : : err = -EOPNOTSUPP;
169 : : }
170 [ # # ]: 0 : if (!err) {
171 : 0 : fuse_invalidate_attr(inode);
172 : 0 : fuse_update_ctime(inode);
173 : : }
174 : 0 : return err;
175 : : }
176 : :
177 : 0 : 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 : 0 : return fuse_getxattr(inode, name, value, size);
182 : : }
183 : :
184 : 0 : 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 [ # # ]: 0 : if (!value)
190 : 0 : return fuse_removexattr(inode, name);
191 : :
192 : 0 : return fuse_setxattr(inode, name, value, size, flags);
193 : : }
194 : :
195 : 0 : static bool no_xattr_list(struct dentry *dentry)
196 : : {
197 : 0 : return false;
198 : : }
199 : :
200 : 0 : 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 : 0 : return -EOPNOTSUPP;
205 : : }
206 : :
207 : 0 : 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 : 0 : return -EOPNOTSUPP;
213 : : }
214 : :
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 : : };
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 : : };
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 : : };
|