blob: f156392d019e5b19ecec16223fe5fc4a0455dd8b [file] [log] [blame]
Miklos Szeredie5e55582005-09-09 13:10:28 -07001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 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/pagemap.h>
12#include <linux/file.h>
13#include <linux/gfp.h>
14#include <linux/sched.h>
15#include <linux/namei.h>
16
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080017/*
18 * FUSE caches dentries and attributes with separate timeout. The
19 * time in jiffies until the dentry/attributes are valid is stored in
20 * dentry->d_time and fuse_inode->i_time respectively.
21 */
22
23/*
24 * Calculate the time in jiffies until a dentry/attributes are valid
25 */
Miklos Szeredie5e55582005-09-09 13:10:28 -070026static inline unsigned long time_to_jiffies(unsigned long sec,
27 unsigned long nsec)
28{
29 struct timespec ts = {sec, nsec};
30 return jiffies + timespec_to_jiffies(&ts);
31}
32
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080033/*
34 * Set dentry and possibly attribute timeouts from the lookup/mk*
35 * replies
36 */
Miklos Szeredi0aa7c692006-01-06 00:19:34 -080037static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
38{
Miklos Szeredi0aa7c692006-01-06 00:19:34 -080039 entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080040 if (entry->d_inode)
41 get_fuse_inode(entry->d_inode)->i_time =
42 time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
43}
44
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080045/*
46 * Mark the attributes as stale, so that at the next call to
47 * ->getattr() they will be fetched from userspace
48 */
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080049void fuse_invalidate_attr(struct inode *inode)
50{
51 get_fuse_inode(inode)->i_time = jiffies - 1;
52}
53
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080054/*
55 * Just mark the entry as stale, so that a next attempt to look it up
56 * will result in a new lookup call to userspace
57 *
58 * This is called when a dentry is about to become negative and the
59 * timeout is unknown (unlink, rmdir, rename and in some cases
60 * lookup)
61 */
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080062static void fuse_invalidate_entry_cache(struct dentry *entry)
63{
64 entry->d_time = jiffies - 1;
65}
66
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080067/*
68 * Same as fuse_invalidate_entry_cache(), but also try to remove the
69 * dentry from the hash
70 */
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080071static void fuse_invalidate_entry(struct dentry *entry)
72{
73 d_invalidate(entry);
74 fuse_invalidate_entry_cache(entry);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -080075}
76
Miklos Szeredie5e55582005-09-09 13:10:28 -070077static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
78 struct dentry *entry,
79 struct fuse_entry_out *outarg)
80{
81 req->in.h.opcode = FUSE_LOOKUP;
82 req->in.h.nodeid = get_node_id(dir);
83 req->inode = dir;
84 req->in.numargs = 1;
85 req->in.args[0].size = entry->d_name.len + 1;
86 req->in.args[0].value = entry->d_name.name;
87 req->out.numargs = 1;
88 req->out.args[0].size = sizeof(struct fuse_entry_out);
89 req->out.args[0].value = outarg;
90}
91
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080092/*
93 * Check whether the dentry is still valid
94 *
95 * If the entry validity timeout has expired and the dentry is
96 * positive, try to redo the lookup. If the lookup results in a
97 * different inode, then let the VFS invalidate the dentry and redo
98 * the lookup once more. If the lookup results in the same inode,
99 * then refresh the attributes, timeouts and mark the dentry valid.
100 */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700101static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
102{
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800103 struct inode *inode = entry->d_inode;
104
105 if (inode && is_bad_inode(inode))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700106 return 0;
107 else if (time_after(jiffies, entry->d_time)) {
108 int err;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700109 struct fuse_entry_out outarg;
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800110 struct fuse_conn *fc;
111 struct fuse_req *req;
112
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800113 /* Doesn't hurt to "reset" the validity timeout */
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800114 fuse_invalidate_entry_cache(entry);
115 if (!inode)
116 return 0;
117
118 fc = get_fuse_conn(inode);
119 req = fuse_get_request(fc);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700120 if (!req)
121 return 0;
122
123 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700124 request_send(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700125 err = req->out.h.error;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700126 if (!err) {
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800127 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700128 if (outarg.nodeid != get_node_id(inode)) {
129 fuse_send_forget(fc, req, outarg.nodeid, 1);
130 return 0;
131 }
132 fi->nlookup ++;
133 }
Miklos Szeredie5e55582005-09-09 13:10:28 -0700134 fuse_put_request(fc, req);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700135 if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
Miklos Szeredie5e55582005-09-09 13:10:28 -0700136 return 0;
137
138 fuse_change_attributes(inode, &outarg.attr);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800139 fuse_change_timeout(entry, &outarg);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700140 }
141 return 1;
142}
143
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800144/*
145 * Check if there's already a hashed alias of this directory inode.
146 * If yes, then lookup and mkdir must not create a new alias.
147 */
Miklos Szeredif007d5c2005-11-28 13:44:16 -0800148static int dir_alias(struct inode *inode)
149{
150 if (S_ISDIR(inode->i_mode)) {
Miklos Szeredif007d5c2005-11-28 13:44:16 -0800151 struct dentry *alias = d_find_alias(inode);
152 if (alias) {
153 dput(alias);
154 return 1;
155 }
156 }
157 return 0;
158}
159
Miklos Szeredi2827d0b22005-11-28 13:44:16 -0800160static inline int invalid_nodeid(u64 nodeid)
161{
162 return !nodeid || nodeid == FUSE_ROOT_ID;
163}
164
Miklos Szeredie5e55582005-09-09 13:10:28 -0700165static struct dentry_operations fuse_dentry_operations = {
166 .d_revalidate = fuse_dentry_revalidate,
167};
168
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800169static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
170 struct nameidata *nd)
Miklos Szeredie5e55582005-09-09 13:10:28 -0700171{
172 int err;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700173 struct fuse_entry_out outarg;
174 struct inode *inode = NULL;
175 struct fuse_conn *fc = get_fuse_conn(dir);
176 struct fuse_req *req;
177
178 if (entry->d_name.len > FUSE_NAME_MAX)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800179 return ERR_PTR(-ENAMETOOLONG);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700180
181 req = fuse_get_request(fc);
182 if (!req)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800183 return ERR_PTR(-EINTR);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700184
185 fuse_lookup_init(req, dir, entry, &outarg);
186 request_send(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700187 err = req->out.h.error;
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800188 if (!err && outarg.nodeid && invalid_nodeid(outarg.nodeid))
Miklos Szerediee4e5272005-09-27 21:45:21 -0700189 err = -EIO;
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800190 if (!err && outarg.nodeid) {
Miklos Szeredie5e55582005-09-09 13:10:28 -0700191 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700192 &outarg.attr);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700193 if (!inode) {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700194 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800195 return ERR_PTR(-ENOMEM);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700196 }
197 }
198 fuse_put_request(fc, req);
199 if (err && err != -ENOENT)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800200 return ERR_PTR(err);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700201
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800202 if (inode && dir_alias(inode)) {
203 iput(inode);
204 return ERR_PTR(-EIO);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700205 }
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800206 d_add(entry, inode);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700207 entry->d_op = &fuse_dentry_operations;
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800208 if (!err)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800209 fuse_change_timeout(entry, &outarg);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800210 else
211 fuse_invalidate_entry_cache(entry);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800212 return NULL;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700213}
214
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800215/*
216 * Atomic create+open operation
217 *
218 * If the filesystem doesn't support this, then fall back to separate
219 * 'mknod' + 'open' requests.
220 */
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800221static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
222 struct nameidata *nd)
223{
224 int err;
225 struct inode *inode;
226 struct fuse_conn *fc = get_fuse_conn(dir);
227 struct fuse_req *req;
228 struct fuse_open_in inarg;
229 struct fuse_open_out outopen;
230 struct fuse_entry_out outentry;
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800231 struct fuse_file *ff;
232 struct file *file;
233 int flags = nd->intent.open.flags - 1;
234
235 err = -ENOSYS;
236 if (fc->no_create)
237 goto out;
238
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800239 err = -EINTR;
240 req = fuse_get_request(fc);
241 if (!req)
242 goto out;
243
244 ff = fuse_file_alloc();
245 if (!ff)
246 goto out_put_request;
247
248 flags &= ~O_NOCTTY;
249 memset(&inarg, 0, sizeof(inarg));
250 inarg.flags = flags;
251 inarg.mode = mode;
252 req->in.h.opcode = FUSE_CREATE;
253 req->in.h.nodeid = get_node_id(dir);
254 req->inode = dir;
255 req->in.numargs = 2;
256 req->in.args[0].size = sizeof(inarg);
257 req->in.args[0].value = &inarg;
258 req->in.args[1].size = entry->d_name.len + 1;
259 req->in.args[1].value = entry->d_name.name;
260 req->out.numargs = 2;
261 req->out.args[0].size = sizeof(outentry);
262 req->out.args[0].value = &outentry;
263 req->out.args[1].size = sizeof(outopen);
264 req->out.args[1].value = &outopen;
265 request_send(fc, req);
266 err = req->out.h.error;
267 if (err) {
268 if (err == -ENOSYS)
269 fc->no_create = 1;
270 goto out_free_ff;
271 }
272
273 err = -EIO;
Miklos Szeredi2827d0b22005-11-28 13:44:16 -0800274 if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800275 goto out_free_ff;
276
277 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
278 &outentry.attr);
279 err = -ENOMEM;
280 if (!inode) {
281 flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
282 ff->fh = outopen.fh;
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800283 /* Special release, with inode = NULL, this will
284 trigger a 'forget' request when the release is
285 complete */
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800286 fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
287 goto out_put_request;
288 }
289 fuse_put_request(fc, req);
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800290 d_instantiate(entry, inode);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800291 fuse_change_timeout(entry, &outentry);
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800292 file = lookup_instantiate_filp(nd, entry, generic_file_open);
293 if (IS_ERR(file)) {
294 ff->fh = outopen.fh;
295 fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
296 return PTR_ERR(file);
297 }
298 fuse_finish_open(inode, file, ff, &outopen);
299 return 0;
300
301 out_free_ff:
302 fuse_file_free(ff);
303 out_put_request:
304 fuse_put_request(fc, req);
305 out:
306 return err;
307}
308
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800309/*
310 * Code shared between mknod, mkdir, symlink and link
311 */
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700312static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
313 struct inode *dir, struct dentry *entry,
314 int mode)
315{
316 struct fuse_entry_out outarg;
317 struct inode *inode;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700318 int err;
319
320 req->in.h.nodeid = get_node_id(dir);
321 req->inode = dir;
322 req->out.numargs = 1;
323 req->out.args[0].size = sizeof(outarg);
324 req->out.args[0].value = &outarg;
325 request_send(fc, req);
326 err = req->out.h.error;
327 if (err) {
328 fuse_put_request(fc, req);
329 return err;
330 }
Miklos Szeredi2827d0b22005-11-28 13:44:16 -0800331 if (invalid_nodeid(outarg.nodeid)) {
Miklos Szerediee4e5272005-09-27 21:45:21 -0700332 fuse_put_request(fc, req);
333 return -EIO;
334 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700335 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
336 &outarg.attr);
337 if (!inode) {
338 fuse_send_forget(fc, req, outarg.nodeid, 1);
339 return -ENOMEM;
340 }
341 fuse_put_request(fc, req);
342
343 /* Don't allow userspace to do really stupid things... */
Miklos Szeredif007d5c2005-11-28 13:44:16 -0800344 if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700345 iput(inode);
346 return -EIO;
347 }
348
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700349 d_instantiate(entry, inode);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800350 fuse_change_timeout(entry, &outarg);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700351 fuse_invalidate_attr(dir);
352 return 0;
353}
354
355static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
356 dev_t rdev)
357{
358 struct fuse_mknod_in inarg;
359 struct fuse_conn *fc = get_fuse_conn(dir);
360 struct fuse_req *req = fuse_get_request(fc);
361 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700362 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700363
364 memset(&inarg, 0, sizeof(inarg));
365 inarg.mode = mode;
366 inarg.rdev = new_encode_dev(rdev);
367 req->in.h.opcode = FUSE_MKNOD;
368 req->in.numargs = 2;
369 req->in.args[0].size = sizeof(inarg);
370 req->in.args[0].value = &inarg;
371 req->in.args[1].size = entry->d_name.len + 1;
372 req->in.args[1].value = entry->d_name.name;
373 return create_new_entry(fc, req, dir, entry, mode);
374}
375
376static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
377 struct nameidata *nd)
378{
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800379 if (nd && (nd->flags & LOOKUP_CREATE)) {
380 int err = fuse_create_open(dir, entry, mode, nd);
381 if (err != -ENOSYS)
382 return err;
383 /* Fall back on mknod */
384 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700385 return fuse_mknod(dir, entry, mode, 0);
386}
387
388static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
389{
390 struct fuse_mkdir_in inarg;
391 struct fuse_conn *fc = get_fuse_conn(dir);
392 struct fuse_req *req = fuse_get_request(fc);
393 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700394 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700395
396 memset(&inarg, 0, sizeof(inarg));
397 inarg.mode = mode;
398 req->in.h.opcode = FUSE_MKDIR;
399 req->in.numargs = 2;
400 req->in.args[0].size = sizeof(inarg);
401 req->in.args[0].value = &inarg;
402 req->in.args[1].size = entry->d_name.len + 1;
403 req->in.args[1].value = entry->d_name.name;
404 return create_new_entry(fc, req, dir, entry, S_IFDIR);
405}
406
407static int fuse_symlink(struct inode *dir, struct dentry *entry,
408 const char *link)
409{
410 struct fuse_conn *fc = get_fuse_conn(dir);
411 unsigned len = strlen(link) + 1;
Miklos Szeredi1d3d7522006-01-06 00:19:40 -0800412 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700413 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700414 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700415
416 req->in.h.opcode = FUSE_SYMLINK;
417 req->in.numargs = 2;
418 req->in.args[0].size = entry->d_name.len + 1;
419 req->in.args[0].value = entry->d_name.name;
420 req->in.args[1].size = len;
421 req->in.args[1].value = link;
422 return create_new_entry(fc, req, dir, entry, S_IFLNK);
423}
424
425static int fuse_unlink(struct inode *dir, struct dentry *entry)
426{
427 int err;
428 struct fuse_conn *fc = get_fuse_conn(dir);
429 struct fuse_req *req = fuse_get_request(fc);
430 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700431 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700432
433 req->in.h.opcode = FUSE_UNLINK;
434 req->in.h.nodeid = get_node_id(dir);
435 req->inode = dir;
436 req->in.numargs = 1;
437 req->in.args[0].size = entry->d_name.len + 1;
438 req->in.args[0].value = entry->d_name.name;
439 request_send(fc, req);
440 err = req->out.h.error;
441 fuse_put_request(fc, req);
442 if (!err) {
443 struct inode *inode = entry->d_inode;
444
445 /* Set nlink to zero so the inode can be cleared, if
446 the inode does have more links this will be
447 discovered at the next lookup/getattr */
448 inode->i_nlink = 0;
449 fuse_invalidate_attr(inode);
450 fuse_invalidate_attr(dir);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800451 fuse_invalidate_entry_cache(entry);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700452 } else if (err == -EINTR)
453 fuse_invalidate_entry(entry);
454 return err;
455}
456
457static int fuse_rmdir(struct inode *dir, struct dentry *entry)
458{
459 int err;
460 struct fuse_conn *fc = get_fuse_conn(dir);
461 struct fuse_req *req = fuse_get_request(fc);
462 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700463 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700464
465 req->in.h.opcode = FUSE_RMDIR;
466 req->in.h.nodeid = get_node_id(dir);
467 req->inode = dir;
468 req->in.numargs = 1;
469 req->in.args[0].size = entry->d_name.len + 1;
470 req->in.args[0].value = entry->d_name.name;
471 request_send(fc, req);
472 err = req->out.h.error;
473 fuse_put_request(fc, req);
474 if (!err) {
475 entry->d_inode->i_nlink = 0;
476 fuse_invalidate_attr(dir);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800477 fuse_invalidate_entry_cache(entry);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700478 } else if (err == -EINTR)
479 fuse_invalidate_entry(entry);
480 return err;
481}
482
483static int fuse_rename(struct inode *olddir, struct dentry *oldent,
484 struct inode *newdir, struct dentry *newent)
485{
486 int err;
487 struct fuse_rename_in inarg;
488 struct fuse_conn *fc = get_fuse_conn(olddir);
489 struct fuse_req *req = fuse_get_request(fc);
490 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700491 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700492
493 memset(&inarg, 0, sizeof(inarg));
494 inarg.newdir = get_node_id(newdir);
495 req->in.h.opcode = FUSE_RENAME;
496 req->in.h.nodeid = get_node_id(olddir);
497 req->inode = olddir;
498 req->inode2 = newdir;
499 req->in.numargs = 3;
500 req->in.args[0].size = sizeof(inarg);
501 req->in.args[0].value = &inarg;
502 req->in.args[1].size = oldent->d_name.len + 1;
503 req->in.args[1].value = oldent->d_name.name;
504 req->in.args[2].size = newent->d_name.len + 1;
505 req->in.args[2].value = newent->d_name.name;
506 request_send(fc, req);
507 err = req->out.h.error;
508 fuse_put_request(fc, req);
509 if (!err) {
510 fuse_invalidate_attr(olddir);
511 if (olddir != newdir)
512 fuse_invalidate_attr(newdir);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800513
514 /* newent will end up negative */
515 if (newent->d_inode)
516 fuse_invalidate_entry_cache(newent);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700517 } else if (err == -EINTR) {
518 /* If request was interrupted, DEITY only knows if the
519 rename actually took place. If the invalidation
520 fails (e.g. some process has CWD under the renamed
521 directory), then there can be inconsistency between
522 the dcache and the real filesystem. Tough luck. */
523 fuse_invalidate_entry(oldent);
524 if (newent->d_inode)
525 fuse_invalidate_entry(newent);
526 }
527
528 return err;
529}
530
531static int fuse_link(struct dentry *entry, struct inode *newdir,
532 struct dentry *newent)
533{
534 int err;
535 struct fuse_link_in inarg;
536 struct inode *inode = entry->d_inode;
537 struct fuse_conn *fc = get_fuse_conn(inode);
538 struct fuse_req *req = fuse_get_request(fc);
539 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700540 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700541
542 memset(&inarg, 0, sizeof(inarg));
543 inarg.oldnodeid = get_node_id(inode);
544 req->in.h.opcode = FUSE_LINK;
545 req->inode2 = inode;
546 req->in.numargs = 2;
547 req->in.args[0].size = sizeof(inarg);
548 req->in.args[0].value = &inarg;
549 req->in.args[1].size = newent->d_name.len + 1;
550 req->in.args[1].value = newent->d_name.name;
551 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
552 /* Contrary to "normal" filesystems it can happen that link
553 makes two "logical" inodes point to the same "physical"
554 inode. We invalidate the attributes of the old one, so it
555 will reflect changes in the backing inode (link count,
556 etc.)
557 */
558 if (!err || err == -EINTR)
559 fuse_invalidate_attr(inode);
560 return err;
561}
562
Miklos Szeredie5e55582005-09-09 13:10:28 -0700563int fuse_do_getattr(struct inode *inode)
564{
565 int err;
566 struct fuse_attr_out arg;
567 struct fuse_conn *fc = get_fuse_conn(inode);
568 struct fuse_req *req = fuse_get_request(fc);
569 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700570 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700571
572 req->in.h.opcode = FUSE_GETATTR;
573 req->in.h.nodeid = get_node_id(inode);
574 req->inode = inode;
575 req->out.numargs = 1;
576 req->out.args[0].size = sizeof(arg);
577 req->out.args[0].value = &arg;
578 request_send(fc, req);
579 err = req->out.h.error;
580 fuse_put_request(fc, req);
581 if (!err) {
582 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
583 make_bad_inode(inode);
584 err = -EIO;
585 } else {
586 struct fuse_inode *fi = get_fuse_inode(inode);
587 fuse_change_attributes(inode, &arg.attr);
588 fi->i_time = time_to_jiffies(arg.attr_valid,
589 arg.attr_valid_nsec);
590 }
591 }
592 return err;
593}
594
Miklos Szeredi87729a52005-09-09 13:10:34 -0700595/*
596 * Calling into a user-controlled filesystem gives the filesystem
597 * daemon ptrace-like capabilities over the requester process. This
598 * means, that the filesystem daemon is able to record the exact
599 * filesystem operations performed, and can also control the behavior
600 * of the requester process in otherwise impossible ways. For example
601 * it can delay the operation for arbitrary length of time allowing
602 * DoS against the requester.
603 *
604 * For this reason only those processes can call into the filesystem,
605 * for which the owner of the mount has ptrace privilege. This
606 * excludes processes started by other users, suid or sgid processes.
607 */
608static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
609{
610 if (fc->flags & FUSE_ALLOW_OTHER)
611 return 1;
612
613 if (task->euid == fc->user_id &&
614 task->suid == fc->user_id &&
615 task->uid == fc->user_id &&
616 task->egid == fc->group_id &&
617 task->sgid == fc->group_id &&
618 task->gid == fc->group_id)
619 return 1;
620
621 return 0;
622}
623
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800624/*
625 * Check whether the inode attributes are still valid
626 *
627 * If the attribute validity timeout has expired, then fetch the fresh
628 * attributes with a 'getattr' request
629 *
630 * I'm not sure why cached attributes are never returned for the root
631 * inode, this is probably being too cautious.
632 */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700633static int fuse_revalidate(struct dentry *entry)
634{
635 struct inode *inode = entry->d_inode;
636 struct fuse_inode *fi = get_fuse_inode(inode);
637 struct fuse_conn *fc = get_fuse_conn(inode);
638
Miklos Szeredi87729a52005-09-09 13:10:34 -0700639 if (!fuse_allow_task(fc, current))
640 return -EACCES;
641 if (get_node_id(inode) != FUSE_ROOT_ID &&
642 time_before_eq(jiffies, fi->i_time))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700643 return 0;
644
645 return fuse_do_getattr(inode);
646}
647
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800648static int fuse_access(struct inode *inode, int mask)
649{
650 struct fuse_conn *fc = get_fuse_conn(inode);
651 struct fuse_req *req;
652 struct fuse_access_in inarg;
653 int err;
654
655 if (fc->no_access)
656 return 0;
657
658 req = fuse_get_request(fc);
659 if (!req)
660 return -EINTR;
661
662 memset(&inarg, 0, sizeof(inarg));
663 inarg.mask = mask;
664 req->in.h.opcode = FUSE_ACCESS;
665 req->in.h.nodeid = get_node_id(inode);
666 req->inode = inode;
667 req->in.numargs = 1;
668 req->in.args[0].size = sizeof(inarg);
669 req->in.args[0].value = &inarg;
670 request_send(fc, req);
671 err = req->out.h.error;
672 fuse_put_request(fc, req);
673 if (err == -ENOSYS) {
674 fc->no_access = 1;
675 err = 0;
676 }
677 return err;
678}
679
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800680/*
681 * Check permission. The two basic access models of FUSE are:
682 *
683 * 1) Local access checking ('default_permissions' mount option) based
684 * on file mode. This is the plain old disk filesystem permission
685 * modell.
686 *
687 * 2) "Remote" access checking, where server is responsible for
688 * checking permission in each inode operation. An exception to this
689 * is if ->permission() was invoked from sys_access() in which case an
690 * access request is sent. Execute permission is still checked
691 * locally based on file mode.
692 */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700693static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
694{
695 struct fuse_conn *fc = get_fuse_conn(inode);
696
Miklos Szeredi87729a52005-09-09 13:10:34 -0700697 if (!fuse_allow_task(fc, current))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700698 return -EACCES;
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700699 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
700 int err = generic_permission(inode, mask, NULL);
701
702 /* If permission is denied, try to refresh file
703 attributes. This is also needed, because the root
704 node will at first have no permissions */
705 if (err == -EACCES) {
706 err = fuse_do_getattr(inode);
707 if (!err)
708 err = generic_permission(inode, mask, NULL);
709 }
710
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800711 /* Note: the opposite of the above test does not
712 exist. So if permissions are revoked this won't be
713 noticed immediately, only after the attribute
714 timeout has expired */
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700715
716 return err;
717 } else {
Miklos Szeredie5e55582005-09-09 13:10:28 -0700718 int mode = inode->i_mode;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700719 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
720 return -EACCES;
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800721
722 if (nd && (nd->flags & LOOKUP_ACCESS))
723 return fuse_access(inode, mask);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700724 return 0;
725 }
726}
727
728static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
729 void *dstbuf, filldir_t filldir)
730{
731 while (nbytes >= FUSE_NAME_OFFSET) {
732 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
733 size_t reclen = FUSE_DIRENT_SIZE(dirent);
734 int over;
735 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
736 return -EIO;
737 if (reclen > nbytes)
738 break;
739
740 over = filldir(dstbuf, dirent->name, dirent->namelen,
741 file->f_pos, dirent->ino, dirent->type);
742 if (over)
743 break;
744
745 buf += reclen;
746 nbytes -= reclen;
747 file->f_pos = dirent->off;
748 }
749
750 return 0;
751}
752
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700753static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
754 struct inode *inode, loff_t pos,
755 size_t count)
Miklos Szeredie5e55582005-09-09 13:10:28 -0700756{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700757 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700758}
759
760static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
761{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700762 int err;
763 size_t nbytes;
764 struct page *page;
765 struct inode *inode = file->f_dentry->d_inode;
766 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi248d86e2006-01-06 00:19:39 -0800767 struct fuse_req *req;
768
769 if (is_bad_inode(inode))
770 return -EIO;
771
772 req = fuse_get_request(fc);
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700773 if (!req)
774 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700775
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700776 page = alloc_page(GFP_KERNEL);
777 if (!page) {
778 fuse_put_request(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700779 return -ENOMEM;
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700780 }
781 req->num_pages = 1;
782 req->pages[0] = page;
783 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
784 err = req->out.h.error;
785 fuse_put_request(fc, req);
786 if (!err)
787 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
788 filldir);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700789
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700790 __free_page(page);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700791 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700792 return err;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700793}
794
795static char *read_link(struct dentry *dentry)
796{
797 struct inode *inode = dentry->d_inode;
798 struct fuse_conn *fc = get_fuse_conn(inode);
799 struct fuse_req *req = fuse_get_request(fc);
800 char *link;
801
802 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700803 return ERR_PTR(-EINTR);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700804
805 link = (char *) __get_free_page(GFP_KERNEL);
806 if (!link) {
807 link = ERR_PTR(-ENOMEM);
808 goto out;
809 }
810 req->in.h.opcode = FUSE_READLINK;
811 req->in.h.nodeid = get_node_id(inode);
812 req->inode = inode;
813 req->out.argvar = 1;
814 req->out.numargs = 1;
815 req->out.args[0].size = PAGE_SIZE - 1;
816 req->out.args[0].value = link;
817 request_send(fc, req);
818 if (req->out.h.error) {
819 free_page((unsigned long) link);
820 link = ERR_PTR(req->out.h.error);
821 } else
822 link[req->out.args[0].size] = '\0';
823 out:
824 fuse_put_request(fc, req);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700825 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700826 return link;
827}
828
829static void free_link(char *link)
830{
831 if (!IS_ERR(link))
832 free_page((unsigned long) link);
833}
834
835static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
836{
837 nd_set_link(nd, read_link(dentry));
838 return NULL;
839}
840
841static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
842{
843 free_link(nd_get_link(nd));
844}
845
846static int fuse_dir_open(struct inode *inode, struct file *file)
847{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700848 return fuse_open_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700849}
850
851static int fuse_dir_release(struct inode *inode, struct file *file)
852{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700853 return fuse_release_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700854}
855
Miklos Szeredi82547982005-09-09 13:10:38 -0700856static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
857{
858 /* nfsd can call this with no file */
859 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
860}
861
Miklos Szeredibefc6492005-11-07 00:59:52 -0800862static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700863{
864 unsigned ivalid = iattr->ia_valid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700865
866 if (ivalid & ATTR_MODE)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800867 arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700868 if (ivalid & ATTR_UID)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800869 arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700870 if (ivalid & ATTR_GID)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800871 arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700872 if (ivalid & ATTR_SIZE)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800873 arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700874 /* You can only _set_ these together (they may change by themselves) */
875 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredibefc6492005-11-07 00:59:52 -0800876 arg->valid |= FATTR_ATIME | FATTR_MTIME;
877 arg->atime = iattr->ia_atime.tv_sec;
878 arg->mtime = iattr->ia_mtime.tv_sec;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700879 }
Miklos Szeredibefc6492005-11-07 00:59:52 -0800880 if (ivalid & ATTR_FILE) {
881 struct fuse_file *ff = iattr->ia_file->private_data;
882 arg->valid |= FATTR_FH;
883 arg->fh = ff->fh;
884 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700885}
886
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800887/*
888 * Set attributes, and at the same time refresh them.
889 *
890 * Truncation is slightly complicated, because the 'truncate' request
891 * may fail, in which case we don't want to touch the mapping.
892 * vmtruncate() doesn't allow for this case. So do the rlimit
893 * checking by hand and call vmtruncate() only after the file has
894 * actually been truncated.
895 */
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700896static int fuse_setattr(struct dentry *entry, struct iattr *attr)
897{
898 struct inode *inode = entry->d_inode;
899 struct fuse_conn *fc = get_fuse_conn(inode);
900 struct fuse_inode *fi = get_fuse_inode(inode);
901 struct fuse_req *req;
902 struct fuse_setattr_in inarg;
903 struct fuse_attr_out outarg;
904 int err;
905 int is_truncate = 0;
906
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700907 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
908 err = inode_change_ok(inode, attr);
909 if (err)
910 return err;
911 }
912
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700913 if (attr->ia_valid & ATTR_SIZE) {
914 unsigned long limit;
915 is_truncate = 1;
916 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
917 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
918 send_sig(SIGXFSZ, current, 0);
919 return -EFBIG;
920 }
921 }
922
923 req = fuse_get_request(fc);
924 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700925 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700926
927 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredibefc6492005-11-07 00:59:52 -0800928 iattr_to_fattr(attr, &inarg);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700929 req->in.h.opcode = FUSE_SETATTR;
930 req->in.h.nodeid = get_node_id(inode);
931 req->inode = inode;
932 req->in.numargs = 1;
933 req->in.args[0].size = sizeof(inarg);
934 req->in.args[0].value = &inarg;
935 req->out.numargs = 1;
936 req->out.args[0].size = sizeof(outarg);
937 req->out.args[0].value = &outarg;
938 request_send(fc, req);
939 err = req->out.h.error;
940 fuse_put_request(fc, req);
941 if (!err) {
942 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
943 make_bad_inode(inode);
944 err = -EIO;
945 } else {
946 if (is_truncate) {
947 loff_t origsize = i_size_read(inode);
948 i_size_write(inode, outarg.attr.size);
949 if (origsize > outarg.attr.size)
950 vmtruncate(inode, outarg.attr.size);
951 }
952 fuse_change_attributes(inode, &outarg.attr);
953 fi->i_time = time_to_jiffies(outarg.attr_valid,
954 outarg.attr_valid_nsec);
955 }
956 } else if (err == -EINTR)
957 fuse_invalidate_attr(inode);
958
959 return err;
960}
961
Miklos Szeredie5e55582005-09-09 13:10:28 -0700962static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
963 struct kstat *stat)
964{
965 struct inode *inode = entry->d_inode;
966 int err = fuse_revalidate(entry);
967 if (!err)
968 generic_fillattr(inode, stat);
969
970 return err;
971}
972
Miklos Szeredi92a87802005-09-09 13:10:31 -0700973static int fuse_setxattr(struct dentry *entry, const char *name,
974 const void *value, size_t size, int flags)
975{
976 struct inode *inode = entry->d_inode;
977 struct fuse_conn *fc = get_fuse_conn(inode);
978 struct fuse_req *req;
979 struct fuse_setxattr_in inarg;
980 int err;
981
Miklos Szeredi92a87802005-09-09 13:10:31 -0700982 if (fc->no_setxattr)
983 return -EOPNOTSUPP;
984
985 req = fuse_get_request(fc);
986 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700987 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700988
989 memset(&inarg, 0, sizeof(inarg));
990 inarg.size = size;
991 inarg.flags = flags;
992 req->in.h.opcode = FUSE_SETXATTR;
993 req->in.h.nodeid = get_node_id(inode);
994 req->inode = inode;
995 req->in.numargs = 3;
996 req->in.args[0].size = sizeof(inarg);
997 req->in.args[0].value = &inarg;
998 req->in.args[1].size = strlen(name) + 1;
999 req->in.args[1].value = name;
1000 req->in.args[2].size = size;
1001 req->in.args[2].value = value;
1002 request_send(fc, req);
1003 err = req->out.h.error;
1004 fuse_put_request(fc, req);
1005 if (err == -ENOSYS) {
1006 fc->no_setxattr = 1;
1007 err = -EOPNOTSUPP;
1008 }
1009 return err;
1010}
1011
1012static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
1013 void *value, size_t size)
1014{
1015 struct inode *inode = entry->d_inode;
1016 struct fuse_conn *fc = get_fuse_conn(inode);
1017 struct fuse_req *req;
1018 struct fuse_getxattr_in inarg;
1019 struct fuse_getxattr_out outarg;
1020 ssize_t ret;
1021
1022 if (fc->no_getxattr)
1023 return -EOPNOTSUPP;
1024
1025 req = fuse_get_request(fc);
1026 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -07001027 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -07001028
1029 memset(&inarg, 0, sizeof(inarg));
1030 inarg.size = size;
1031 req->in.h.opcode = FUSE_GETXATTR;
1032 req->in.h.nodeid = get_node_id(inode);
1033 req->inode = inode;
1034 req->in.numargs = 2;
1035 req->in.args[0].size = sizeof(inarg);
1036 req->in.args[0].value = &inarg;
1037 req->in.args[1].size = strlen(name) + 1;
1038 req->in.args[1].value = name;
1039 /* This is really two different operations rolled into one */
1040 req->out.numargs = 1;
1041 if (size) {
1042 req->out.argvar = 1;
1043 req->out.args[0].size = size;
1044 req->out.args[0].value = value;
1045 } else {
1046 req->out.args[0].size = sizeof(outarg);
1047 req->out.args[0].value = &outarg;
1048 }
1049 request_send(fc, req);
1050 ret = req->out.h.error;
1051 if (!ret)
1052 ret = size ? req->out.args[0].size : outarg.size;
1053 else {
1054 if (ret == -ENOSYS) {
1055 fc->no_getxattr = 1;
1056 ret = -EOPNOTSUPP;
1057 }
1058 }
1059 fuse_put_request(fc, req);
1060 return ret;
1061}
1062
1063static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1064{
1065 struct inode *inode = entry->d_inode;
1066 struct fuse_conn *fc = get_fuse_conn(inode);
1067 struct fuse_req *req;
1068 struct fuse_getxattr_in inarg;
1069 struct fuse_getxattr_out outarg;
1070 ssize_t ret;
1071
1072 if (fc->no_listxattr)
1073 return -EOPNOTSUPP;
1074
1075 req = fuse_get_request(fc);
1076 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -07001077 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -07001078
1079 memset(&inarg, 0, sizeof(inarg));
1080 inarg.size = size;
1081 req->in.h.opcode = FUSE_LISTXATTR;
1082 req->in.h.nodeid = get_node_id(inode);
1083 req->inode = inode;
1084 req->in.numargs = 1;
1085 req->in.args[0].size = sizeof(inarg);
1086 req->in.args[0].value = &inarg;
1087 /* This is really two different operations rolled into one */
1088 req->out.numargs = 1;
1089 if (size) {
1090 req->out.argvar = 1;
1091 req->out.args[0].size = size;
1092 req->out.args[0].value = list;
1093 } else {
1094 req->out.args[0].size = sizeof(outarg);
1095 req->out.args[0].value = &outarg;
1096 }
1097 request_send(fc, req);
1098 ret = req->out.h.error;
1099 if (!ret)
1100 ret = size ? req->out.args[0].size : outarg.size;
1101 else {
1102 if (ret == -ENOSYS) {
1103 fc->no_listxattr = 1;
1104 ret = -EOPNOTSUPP;
1105 }
1106 }
1107 fuse_put_request(fc, req);
1108 return ret;
1109}
1110
1111static int fuse_removexattr(struct dentry *entry, const char *name)
1112{
1113 struct inode *inode = entry->d_inode;
1114 struct fuse_conn *fc = get_fuse_conn(inode);
1115 struct fuse_req *req;
1116 int err;
1117
1118 if (fc->no_removexattr)
1119 return -EOPNOTSUPP;
1120
1121 req = fuse_get_request(fc);
1122 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -07001123 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -07001124
1125 req->in.h.opcode = FUSE_REMOVEXATTR;
1126 req->in.h.nodeid = get_node_id(inode);
1127 req->inode = inode;
1128 req->in.numargs = 1;
1129 req->in.args[0].size = strlen(name) + 1;
1130 req->in.args[0].value = name;
1131 request_send(fc, req);
1132 err = req->out.h.error;
1133 fuse_put_request(fc, req);
1134 if (err == -ENOSYS) {
1135 fc->no_removexattr = 1;
1136 err = -EOPNOTSUPP;
1137 }
1138 return err;
1139}
1140
Miklos Szeredie5e55582005-09-09 13:10:28 -07001141static struct inode_operations fuse_dir_inode_operations = {
1142 .lookup = fuse_lookup,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001143 .mkdir = fuse_mkdir,
1144 .symlink = fuse_symlink,
1145 .unlink = fuse_unlink,
1146 .rmdir = fuse_rmdir,
1147 .rename = fuse_rename,
1148 .link = fuse_link,
1149 .setattr = fuse_setattr,
1150 .create = fuse_create,
1151 .mknod = fuse_mknod,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001152 .permission = fuse_permission,
1153 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001154 .setxattr = fuse_setxattr,
1155 .getxattr = fuse_getxattr,
1156 .listxattr = fuse_listxattr,
1157 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001158};
1159
1160static struct file_operations fuse_dir_operations = {
Miklos Szeredib6aeade2005-09-09 13:10:30 -07001161 .llseek = generic_file_llseek,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001162 .read = generic_read_dir,
1163 .readdir = fuse_readdir,
1164 .open = fuse_dir_open,
1165 .release = fuse_dir_release,
Miklos Szeredi82547982005-09-09 13:10:38 -07001166 .fsync = fuse_dir_fsync,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001167};
1168
1169static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001170 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001171 .permission = fuse_permission,
1172 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001173 .setxattr = fuse_setxattr,
1174 .getxattr = fuse_getxattr,
1175 .listxattr = fuse_listxattr,
1176 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001177};
1178
1179static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001180 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001181 .follow_link = fuse_follow_link,
1182 .put_link = fuse_put_link,
1183 .readlink = generic_readlink,
1184 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001185 .setxattr = fuse_setxattr,
1186 .getxattr = fuse_getxattr,
1187 .listxattr = fuse_listxattr,
1188 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001189};
1190
1191void fuse_init_common(struct inode *inode)
1192{
1193 inode->i_op = &fuse_common_inode_operations;
1194}
1195
1196void fuse_init_dir(struct inode *inode)
1197{
1198 inode->i_op = &fuse_dir_inode_operations;
1199 inode->i_fop = &fuse_dir_operations;
1200}
1201
1202void fuse_init_symlink(struct inode *inode)
1203{
1204 inode->i_op = &fuse_symlink_inode_operations;
1205}