blob: 4bc1afcc476da7f6b7d61099be0d38e373050088 [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
17static inline unsigned long time_to_jiffies(unsigned long sec,
18 unsigned long nsec)
19{
20 struct timespec ts = {sec, nsec};
21 return jiffies + timespec_to_jiffies(&ts);
22}
23
24static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
25 struct dentry *entry,
26 struct fuse_entry_out *outarg)
27{
28 req->in.h.opcode = FUSE_LOOKUP;
29 req->in.h.nodeid = get_node_id(dir);
30 req->inode = dir;
31 req->in.numargs = 1;
32 req->in.args[0].size = entry->d_name.len + 1;
33 req->in.args[0].value = entry->d_name.name;
34 req->out.numargs = 1;
35 req->out.args[0].size = sizeof(struct fuse_entry_out);
36 req->out.args[0].value = outarg;
37}
38
39static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
40{
41 if (!entry->d_inode || is_bad_inode(entry->d_inode))
42 return 0;
43 else if (time_after(jiffies, entry->d_time)) {
44 int err;
Miklos Szeredie5e55582005-09-09 13:10:28 -070045 struct fuse_entry_out outarg;
46 struct inode *inode = entry->d_inode;
47 struct fuse_inode *fi = get_fuse_inode(inode);
48 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7c352bd2005-09-09 13:10:39 -070049 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredie5e55582005-09-09 13:10:28 -070050 if (!req)
51 return 0;
52
53 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
Miklos Szeredi7c352bd2005-09-09 13:10:39 -070054 request_send(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -070055 err = req->out.h.error;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -070056 if (!err) {
57 if (outarg.nodeid != get_node_id(inode)) {
58 fuse_send_forget(fc, req, outarg.nodeid, 1);
59 return 0;
60 }
61 fi->nlookup ++;
62 }
Miklos Szeredie5e55582005-09-09 13:10:28 -070063 fuse_put_request(fc, req);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -070064 if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
Miklos Szeredie5e55582005-09-09 13:10:28 -070065 return 0;
66
67 fuse_change_attributes(inode, &outarg.attr);
Miklos Szeredie5e55582005-09-09 13:10:28 -070068 entry->d_time = time_to_jiffies(outarg.entry_valid,
69 outarg.entry_valid_nsec);
70 fi->i_time = time_to_jiffies(outarg.attr_valid,
71 outarg.attr_valid_nsec);
72 }
73 return 1;
74}
75
76static struct dentry_operations fuse_dentry_operations = {
77 .d_revalidate = fuse_dentry_revalidate,
78};
79
80static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
81 struct inode **inodep)
82{
83 int err;
Miklos Szeredie5e55582005-09-09 13:10:28 -070084 struct fuse_entry_out outarg;
85 struct inode *inode = NULL;
86 struct fuse_conn *fc = get_fuse_conn(dir);
87 struct fuse_req *req;
88
89 if (entry->d_name.len > FUSE_NAME_MAX)
90 return -ENAMETOOLONG;
91
92 req = fuse_get_request(fc);
93 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -070094 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -070095
96 fuse_lookup_init(req, dir, entry, &outarg);
97 request_send(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -070098 err = req->out.h.error;
Miklos Szerediee4e5272005-09-27 21:45:21 -070099 if (!err && (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID))
100 err = -EIO;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700101 if (!err) {
102 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700103 &outarg.attr);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700104 if (!inode) {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700105 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700106 return -ENOMEM;
107 }
108 }
109 fuse_put_request(fc, req);
110 if (err && err != -ENOENT)
111 return err;
112
113 if (inode) {
114 struct fuse_inode *fi = get_fuse_inode(inode);
115 entry->d_time = time_to_jiffies(outarg.entry_valid,
116 outarg.entry_valid_nsec);
117 fi->i_time = time_to_jiffies(outarg.attr_valid,
118 outarg.attr_valid_nsec);
119 }
120
121 entry->d_op = &fuse_dentry_operations;
122 *inodep = inode;
123 return 0;
124}
125
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700126void fuse_invalidate_attr(struct inode *inode)
127{
128 get_fuse_inode(inode)->i_time = jiffies - 1;
129}
130
131static void fuse_invalidate_entry(struct dentry *entry)
132{
133 d_invalidate(entry);
134 entry->d_time = jiffies - 1;
135}
136
137static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
138 struct inode *dir, struct dentry *entry,
139 int mode)
140{
141 struct fuse_entry_out outarg;
142 struct inode *inode;
143 struct fuse_inode *fi;
144 int err;
145
146 req->in.h.nodeid = get_node_id(dir);
147 req->inode = dir;
148 req->out.numargs = 1;
149 req->out.args[0].size = sizeof(outarg);
150 req->out.args[0].value = &outarg;
151 request_send(fc, req);
152 err = req->out.h.error;
153 if (err) {
154 fuse_put_request(fc, req);
155 return err;
156 }
Miklos Szerediee4e5272005-09-27 21:45:21 -0700157 if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) {
158 fuse_put_request(fc, req);
159 return -EIO;
160 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700161 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
162 &outarg.attr);
163 if (!inode) {
164 fuse_send_forget(fc, req, outarg.nodeid, 1);
165 return -ENOMEM;
166 }
167 fuse_put_request(fc, req);
168
169 /* Don't allow userspace to do really stupid things... */
170 if ((inode->i_mode ^ mode) & S_IFMT) {
171 iput(inode);
172 return -EIO;
173 }
174
175 entry->d_time = time_to_jiffies(outarg.entry_valid,
176 outarg.entry_valid_nsec);
177
178 fi = get_fuse_inode(inode);
179 fi->i_time = time_to_jiffies(outarg.attr_valid,
180 outarg.attr_valid_nsec);
181
182 d_instantiate(entry, inode);
183 fuse_invalidate_attr(dir);
184 return 0;
185}
186
187static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
188 dev_t rdev)
189{
190 struct fuse_mknod_in inarg;
191 struct fuse_conn *fc = get_fuse_conn(dir);
192 struct fuse_req *req = fuse_get_request(fc);
193 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700194 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700195
196 memset(&inarg, 0, sizeof(inarg));
197 inarg.mode = mode;
198 inarg.rdev = new_encode_dev(rdev);
199 req->in.h.opcode = FUSE_MKNOD;
200 req->in.numargs = 2;
201 req->in.args[0].size = sizeof(inarg);
202 req->in.args[0].value = &inarg;
203 req->in.args[1].size = entry->d_name.len + 1;
204 req->in.args[1].value = entry->d_name.name;
205 return create_new_entry(fc, req, dir, entry, mode);
206}
207
208static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
209 struct nameidata *nd)
210{
211 return fuse_mknod(dir, entry, mode, 0);
212}
213
214static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
215{
216 struct fuse_mkdir_in inarg;
217 struct fuse_conn *fc = get_fuse_conn(dir);
218 struct fuse_req *req = fuse_get_request(fc);
219 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700220 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700221
222 memset(&inarg, 0, sizeof(inarg));
223 inarg.mode = mode;
224 req->in.h.opcode = FUSE_MKDIR;
225 req->in.numargs = 2;
226 req->in.args[0].size = sizeof(inarg);
227 req->in.args[0].value = &inarg;
228 req->in.args[1].size = entry->d_name.len + 1;
229 req->in.args[1].value = entry->d_name.name;
230 return create_new_entry(fc, req, dir, entry, S_IFDIR);
231}
232
233static int fuse_symlink(struct inode *dir, struct dentry *entry,
234 const char *link)
235{
236 struct fuse_conn *fc = get_fuse_conn(dir);
237 unsigned len = strlen(link) + 1;
238 struct fuse_req *req;
239
240 if (len > FUSE_SYMLINK_MAX)
241 return -ENAMETOOLONG;
242
243 req = fuse_get_request(fc);
244 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700245 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700246
247 req->in.h.opcode = FUSE_SYMLINK;
248 req->in.numargs = 2;
249 req->in.args[0].size = entry->d_name.len + 1;
250 req->in.args[0].value = entry->d_name.name;
251 req->in.args[1].size = len;
252 req->in.args[1].value = link;
253 return create_new_entry(fc, req, dir, entry, S_IFLNK);
254}
255
256static int fuse_unlink(struct inode *dir, struct dentry *entry)
257{
258 int err;
259 struct fuse_conn *fc = get_fuse_conn(dir);
260 struct fuse_req *req = fuse_get_request(fc);
261 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700262 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700263
264 req->in.h.opcode = FUSE_UNLINK;
265 req->in.h.nodeid = get_node_id(dir);
266 req->inode = dir;
267 req->in.numargs = 1;
268 req->in.args[0].size = entry->d_name.len + 1;
269 req->in.args[0].value = entry->d_name.name;
270 request_send(fc, req);
271 err = req->out.h.error;
272 fuse_put_request(fc, req);
273 if (!err) {
274 struct inode *inode = entry->d_inode;
275
276 /* Set nlink to zero so the inode can be cleared, if
277 the inode does have more links this will be
278 discovered at the next lookup/getattr */
279 inode->i_nlink = 0;
280 fuse_invalidate_attr(inode);
281 fuse_invalidate_attr(dir);
282 } else if (err == -EINTR)
283 fuse_invalidate_entry(entry);
284 return err;
285}
286
287static int fuse_rmdir(struct inode *dir, struct dentry *entry)
288{
289 int err;
290 struct fuse_conn *fc = get_fuse_conn(dir);
291 struct fuse_req *req = fuse_get_request(fc);
292 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700293 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700294
295 req->in.h.opcode = FUSE_RMDIR;
296 req->in.h.nodeid = get_node_id(dir);
297 req->inode = dir;
298 req->in.numargs = 1;
299 req->in.args[0].size = entry->d_name.len + 1;
300 req->in.args[0].value = entry->d_name.name;
301 request_send(fc, req);
302 err = req->out.h.error;
303 fuse_put_request(fc, req);
304 if (!err) {
305 entry->d_inode->i_nlink = 0;
306 fuse_invalidate_attr(dir);
307 } else if (err == -EINTR)
308 fuse_invalidate_entry(entry);
309 return err;
310}
311
312static int fuse_rename(struct inode *olddir, struct dentry *oldent,
313 struct inode *newdir, struct dentry *newent)
314{
315 int err;
316 struct fuse_rename_in inarg;
317 struct fuse_conn *fc = get_fuse_conn(olddir);
318 struct fuse_req *req = fuse_get_request(fc);
319 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700320 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700321
322 memset(&inarg, 0, sizeof(inarg));
323 inarg.newdir = get_node_id(newdir);
324 req->in.h.opcode = FUSE_RENAME;
325 req->in.h.nodeid = get_node_id(olddir);
326 req->inode = olddir;
327 req->inode2 = newdir;
328 req->in.numargs = 3;
329 req->in.args[0].size = sizeof(inarg);
330 req->in.args[0].value = &inarg;
331 req->in.args[1].size = oldent->d_name.len + 1;
332 req->in.args[1].value = oldent->d_name.name;
333 req->in.args[2].size = newent->d_name.len + 1;
334 req->in.args[2].value = newent->d_name.name;
335 request_send(fc, req);
336 err = req->out.h.error;
337 fuse_put_request(fc, req);
338 if (!err) {
339 fuse_invalidate_attr(olddir);
340 if (olddir != newdir)
341 fuse_invalidate_attr(newdir);
342 } else if (err == -EINTR) {
343 /* If request was interrupted, DEITY only knows if the
344 rename actually took place. If the invalidation
345 fails (e.g. some process has CWD under the renamed
346 directory), then there can be inconsistency between
347 the dcache and the real filesystem. Tough luck. */
348 fuse_invalidate_entry(oldent);
349 if (newent->d_inode)
350 fuse_invalidate_entry(newent);
351 }
352
353 return err;
354}
355
356static int fuse_link(struct dentry *entry, struct inode *newdir,
357 struct dentry *newent)
358{
359 int err;
360 struct fuse_link_in inarg;
361 struct inode *inode = entry->d_inode;
362 struct fuse_conn *fc = get_fuse_conn(inode);
363 struct fuse_req *req = fuse_get_request(fc);
364 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700365 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700366
367 memset(&inarg, 0, sizeof(inarg));
368 inarg.oldnodeid = get_node_id(inode);
369 req->in.h.opcode = FUSE_LINK;
370 req->inode2 = inode;
371 req->in.numargs = 2;
372 req->in.args[0].size = sizeof(inarg);
373 req->in.args[0].value = &inarg;
374 req->in.args[1].size = newent->d_name.len + 1;
375 req->in.args[1].value = newent->d_name.name;
376 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
377 /* Contrary to "normal" filesystems it can happen that link
378 makes two "logical" inodes point to the same "physical"
379 inode. We invalidate the attributes of the old one, so it
380 will reflect changes in the backing inode (link count,
381 etc.)
382 */
383 if (!err || err == -EINTR)
384 fuse_invalidate_attr(inode);
385 return err;
386}
387
Miklos Szeredie5e55582005-09-09 13:10:28 -0700388int fuse_do_getattr(struct inode *inode)
389{
390 int err;
391 struct fuse_attr_out arg;
392 struct fuse_conn *fc = get_fuse_conn(inode);
393 struct fuse_req *req = fuse_get_request(fc);
394 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700395 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700396
397 req->in.h.opcode = FUSE_GETATTR;
398 req->in.h.nodeid = get_node_id(inode);
399 req->inode = inode;
400 req->out.numargs = 1;
401 req->out.args[0].size = sizeof(arg);
402 req->out.args[0].value = &arg;
403 request_send(fc, req);
404 err = req->out.h.error;
405 fuse_put_request(fc, req);
406 if (!err) {
407 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
408 make_bad_inode(inode);
409 err = -EIO;
410 } else {
411 struct fuse_inode *fi = get_fuse_inode(inode);
412 fuse_change_attributes(inode, &arg.attr);
413 fi->i_time = time_to_jiffies(arg.attr_valid,
414 arg.attr_valid_nsec);
415 }
416 }
417 return err;
418}
419
Miklos Szeredi87729a52005-09-09 13:10:34 -0700420/*
421 * Calling into a user-controlled filesystem gives the filesystem
422 * daemon ptrace-like capabilities over the requester process. This
423 * means, that the filesystem daemon is able to record the exact
424 * filesystem operations performed, and can also control the behavior
425 * of the requester process in otherwise impossible ways. For example
426 * it can delay the operation for arbitrary length of time allowing
427 * DoS against the requester.
428 *
429 * For this reason only those processes can call into the filesystem,
430 * for which the owner of the mount has ptrace privilege. This
431 * excludes processes started by other users, suid or sgid processes.
432 */
433static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
434{
435 if (fc->flags & FUSE_ALLOW_OTHER)
436 return 1;
437
438 if (task->euid == fc->user_id &&
439 task->suid == fc->user_id &&
440 task->uid == fc->user_id &&
441 task->egid == fc->group_id &&
442 task->sgid == fc->group_id &&
443 task->gid == fc->group_id)
444 return 1;
445
446 return 0;
447}
448
Miklos Szeredie5e55582005-09-09 13:10:28 -0700449static int fuse_revalidate(struct dentry *entry)
450{
451 struct inode *inode = entry->d_inode;
452 struct fuse_inode *fi = get_fuse_inode(inode);
453 struct fuse_conn *fc = get_fuse_conn(inode);
454
Miklos Szeredi87729a52005-09-09 13:10:34 -0700455 if (!fuse_allow_task(fc, current))
456 return -EACCES;
457 if (get_node_id(inode) != FUSE_ROOT_ID &&
458 time_before_eq(jiffies, fi->i_time))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700459 return 0;
460
461 return fuse_do_getattr(inode);
462}
463
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800464static int fuse_access(struct inode *inode, int mask)
465{
466 struct fuse_conn *fc = get_fuse_conn(inode);
467 struct fuse_req *req;
468 struct fuse_access_in inarg;
469 int err;
470
471 if (fc->no_access)
472 return 0;
473
474 req = fuse_get_request(fc);
475 if (!req)
476 return -EINTR;
477
478 memset(&inarg, 0, sizeof(inarg));
479 inarg.mask = mask;
480 req->in.h.opcode = FUSE_ACCESS;
481 req->in.h.nodeid = get_node_id(inode);
482 req->inode = inode;
483 req->in.numargs = 1;
484 req->in.args[0].size = sizeof(inarg);
485 req->in.args[0].value = &inarg;
486 request_send(fc, req);
487 err = req->out.h.error;
488 fuse_put_request(fc, req);
489 if (err == -ENOSYS) {
490 fc->no_access = 1;
491 err = 0;
492 }
493 return err;
494}
495
Miklos Szeredie5e55582005-09-09 13:10:28 -0700496static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
497{
498 struct fuse_conn *fc = get_fuse_conn(inode);
499
Miklos Szeredi87729a52005-09-09 13:10:34 -0700500 if (!fuse_allow_task(fc, current))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700501 return -EACCES;
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700502 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
503 int err = generic_permission(inode, mask, NULL);
504
505 /* If permission is denied, try to refresh file
506 attributes. This is also needed, because the root
507 node will at first have no permissions */
508 if (err == -EACCES) {
509 err = fuse_do_getattr(inode);
510 if (!err)
511 err = generic_permission(inode, mask, NULL);
512 }
513
514 /* FIXME: Need some mechanism to revoke permissions:
515 currently if the filesystem suddenly changes the
516 file mode, we will not be informed about it, and
517 continue to allow access to the file/directory.
518
519 This is actually not so grave, since the user can
520 simply keep access to the file/directory anyway by
521 keeping it open... */
522
523 return err;
524 } else {
Miklos Szeredie5e55582005-09-09 13:10:28 -0700525 int mode = inode->i_mode;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700526 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
527 return -EACCES;
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800528
529 if (nd && (nd->flags & LOOKUP_ACCESS))
530 return fuse_access(inode, mask);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700531 return 0;
532 }
533}
534
535static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
536 void *dstbuf, filldir_t filldir)
537{
538 while (nbytes >= FUSE_NAME_OFFSET) {
539 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
540 size_t reclen = FUSE_DIRENT_SIZE(dirent);
541 int over;
542 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
543 return -EIO;
544 if (reclen > nbytes)
545 break;
546
547 over = filldir(dstbuf, dirent->name, dirent->namelen,
548 file->f_pos, dirent->ino, dirent->type);
549 if (over)
550 break;
551
552 buf += reclen;
553 nbytes -= reclen;
554 file->f_pos = dirent->off;
555 }
556
557 return 0;
558}
559
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700560static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
561 struct inode *inode, loff_t pos,
562 size_t count)
Miklos Szeredie5e55582005-09-09 13:10:28 -0700563{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700564 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700565}
566
567static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
568{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700569 int err;
570 size_t nbytes;
571 struct page *page;
572 struct inode *inode = file->f_dentry->d_inode;
573 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700574 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700575 if (!req)
576 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700577
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700578 page = alloc_page(GFP_KERNEL);
579 if (!page) {
580 fuse_put_request(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700581 return -ENOMEM;
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700582 }
583 req->num_pages = 1;
584 req->pages[0] = page;
585 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
586 err = req->out.h.error;
587 fuse_put_request(fc, req);
588 if (!err)
589 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
590 filldir);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700591
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700592 __free_page(page);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700593 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700594 return err;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700595}
596
597static char *read_link(struct dentry *dentry)
598{
599 struct inode *inode = dentry->d_inode;
600 struct fuse_conn *fc = get_fuse_conn(inode);
601 struct fuse_req *req = fuse_get_request(fc);
602 char *link;
603
604 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700605 return ERR_PTR(-EINTR);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700606
607 link = (char *) __get_free_page(GFP_KERNEL);
608 if (!link) {
609 link = ERR_PTR(-ENOMEM);
610 goto out;
611 }
612 req->in.h.opcode = FUSE_READLINK;
613 req->in.h.nodeid = get_node_id(inode);
614 req->inode = inode;
615 req->out.argvar = 1;
616 req->out.numargs = 1;
617 req->out.args[0].size = PAGE_SIZE - 1;
618 req->out.args[0].value = link;
619 request_send(fc, req);
620 if (req->out.h.error) {
621 free_page((unsigned long) link);
622 link = ERR_PTR(req->out.h.error);
623 } else
624 link[req->out.args[0].size] = '\0';
625 out:
626 fuse_put_request(fc, req);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700627 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700628 return link;
629}
630
631static void free_link(char *link)
632{
633 if (!IS_ERR(link))
634 free_page((unsigned long) link);
635}
636
637static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
638{
639 nd_set_link(nd, read_link(dentry));
640 return NULL;
641}
642
643static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
644{
645 free_link(nd_get_link(nd));
646}
647
648static int fuse_dir_open(struct inode *inode, struct file *file)
649{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700650 return fuse_open_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700651}
652
653static int fuse_dir_release(struct inode *inode, struct file *file)
654{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700655 return fuse_release_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700656}
657
Miklos Szeredi82547982005-09-09 13:10:38 -0700658static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
659{
660 /* nfsd can call this with no file */
661 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
662}
663
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700664static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
665{
666 unsigned ivalid = iattr->ia_valid;
667 unsigned fvalid = 0;
668
669 memset(fattr, 0, sizeof(*fattr));
670
671 if (ivalid & ATTR_MODE)
672 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
673 if (ivalid & ATTR_UID)
674 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
675 if (ivalid & ATTR_GID)
676 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
677 if (ivalid & ATTR_SIZE)
678 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
679 /* You can only _set_ these together (they may change by themselves) */
680 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
681 fvalid |= FATTR_ATIME | FATTR_MTIME;
682 fattr->atime = iattr->ia_atime.tv_sec;
683 fattr->mtime = iattr->ia_mtime.tv_sec;
684 }
685
686 return fvalid;
687}
688
689static int fuse_setattr(struct dentry *entry, struct iattr *attr)
690{
691 struct inode *inode = entry->d_inode;
692 struct fuse_conn *fc = get_fuse_conn(inode);
693 struct fuse_inode *fi = get_fuse_inode(inode);
694 struct fuse_req *req;
695 struct fuse_setattr_in inarg;
696 struct fuse_attr_out outarg;
697 int err;
698 int is_truncate = 0;
699
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700700 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
701 err = inode_change_ok(inode, attr);
702 if (err)
703 return err;
704 }
705
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700706 if (attr->ia_valid & ATTR_SIZE) {
707 unsigned long limit;
708 is_truncate = 1;
709 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
710 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
711 send_sig(SIGXFSZ, current, 0);
712 return -EFBIG;
713 }
714 }
715
716 req = fuse_get_request(fc);
717 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700718 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700719
720 memset(&inarg, 0, sizeof(inarg));
721 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
722 req->in.h.opcode = FUSE_SETATTR;
723 req->in.h.nodeid = get_node_id(inode);
724 req->inode = inode;
725 req->in.numargs = 1;
726 req->in.args[0].size = sizeof(inarg);
727 req->in.args[0].value = &inarg;
728 req->out.numargs = 1;
729 req->out.args[0].size = sizeof(outarg);
730 req->out.args[0].value = &outarg;
731 request_send(fc, req);
732 err = req->out.h.error;
733 fuse_put_request(fc, req);
734 if (!err) {
735 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
736 make_bad_inode(inode);
737 err = -EIO;
738 } else {
739 if (is_truncate) {
740 loff_t origsize = i_size_read(inode);
741 i_size_write(inode, outarg.attr.size);
742 if (origsize > outarg.attr.size)
743 vmtruncate(inode, outarg.attr.size);
744 }
745 fuse_change_attributes(inode, &outarg.attr);
746 fi->i_time = time_to_jiffies(outarg.attr_valid,
747 outarg.attr_valid_nsec);
748 }
749 } else if (err == -EINTR)
750 fuse_invalidate_attr(inode);
751
752 return err;
753}
754
Miklos Szeredie5e55582005-09-09 13:10:28 -0700755static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
756 struct kstat *stat)
757{
758 struct inode *inode = entry->d_inode;
759 int err = fuse_revalidate(entry);
760 if (!err)
761 generic_fillattr(inode, stat);
762
763 return err;
764}
765
766static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
767 struct nameidata *nd)
768{
769 struct inode *inode;
770 int err = fuse_lookup_iget(dir, entry, &inode);
771 if (err)
772 return ERR_PTR(err);
773 if (inode && S_ISDIR(inode->i_mode)) {
774 /* Don't allow creating an alias to a directory */
775 struct dentry *alias = d_find_alias(inode);
Miklos Szeredif12ec442005-10-30 15:02:25 -0800776 if (alias) {
Miklos Szeredie5e55582005-09-09 13:10:28 -0700777 dput(alias);
778 iput(inode);
779 return ERR_PTR(-EIO);
780 }
781 }
Miklos Szeredif12ec442005-10-30 15:02:25 -0800782 d_add(entry, inode);
783 return NULL;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700784}
785
Miklos Szeredi92a87802005-09-09 13:10:31 -0700786static int fuse_setxattr(struct dentry *entry, const char *name,
787 const void *value, size_t size, int flags)
788{
789 struct inode *inode = entry->d_inode;
790 struct fuse_conn *fc = get_fuse_conn(inode);
791 struct fuse_req *req;
792 struct fuse_setxattr_in inarg;
793 int err;
794
795 if (size > FUSE_XATTR_SIZE_MAX)
796 return -E2BIG;
797
798 if (fc->no_setxattr)
799 return -EOPNOTSUPP;
800
801 req = fuse_get_request(fc);
802 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700803 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700804
805 memset(&inarg, 0, sizeof(inarg));
806 inarg.size = size;
807 inarg.flags = flags;
808 req->in.h.opcode = FUSE_SETXATTR;
809 req->in.h.nodeid = get_node_id(inode);
810 req->inode = inode;
811 req->in.numargs = 3;
812 req->in.args[0].size = sizeof(inarg);
813 req->in.args[0].value = &inarg;
814 req->in.args[1].size = strlen(name) + 1;
815 req->in.args[1].value = name;
816 req->in.args[2].size = size;
817 req->in.args[2].value = value;
818 request_send(fc, req);
819 err = req->out.h.error;
820 fuse_put_request(fc, req);
821 if (err == -ENOSYS) {
822 fc->no_setxattr = 1;
823 err = -EOPNOTSUPP;
824 }
825 return err;
826}
827
828static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
829 void *value, size_t size)
830{
831 struct inode *inode = entry->d_inode;
832 struct fuse_conn *fc = get_fuse_conn(inode);
833 struct fuse_req *req;
834 struct fuse_getxattr_in inarg;
835 struct fuse_getxattr_out outarg;
836 ssize_t ret;
837
838 if (fc->no_getxattr)
839 return -EOPNOTSUPP;
840
841 req = fuse_get_request(fc);
842 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700843 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700844
845 memset(&inarg, 0, sizeof(inarg));
846 inarg.size = size;
847 req->in.h.opcode = FUSE_GETXATTR;
848 req->in.h.nodeid = get_node_id(inode);
849 req->inode = inode;
850 req->in.numargs = 2;
851 req->in.args[0].size = sizeof(inarg);
852 req->in.args[0].value = &inarg;
853 req->in.args[1].size = strlen(name) + 1;
854 req->in.args[1].value = name;
855 /* This is really two different operations rolled into one */
856 req->out.numargs = 1;
857 if (size) {
858 req->out.argvar = 1;
859 req->out.args[0].size = size;
860 req->out.args[0].value = value;
861 } else {
862 req->out.args[0].size = sizeof(outarg);
863 req->out.args[0].value = &outarg;
864 }
865 request_send(fc, req);
866 ret = req->out.h.error;
867 if (!ret)
868 ret = size ? req->out.args[0].size : outarg.size;
869 else {
870 if (ret == -ENOSYS) {
871 fc->no_getxattr = 1;
872 ret = -EOPNOTSUPP;
873 }
874 }
875 fuse_put_request(fc, req);
876 return ret;
877}
878
879static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
880{
881 struct inode *inode = entry->d_inode;
882 struct fuse_conn *fc = get_fuse_conn(inode);
883 struct fuse_req *req;
884 struct fuse_getxattr_in inarg;
885 struct fuse_getxattr_out outarg;
886 ssize_t ret;
887
888 if (fc->no_listxattr)
889 return -EOPNOTSUPP;
890
891 req = fuse_get_request(fc);
892 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700893 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700894
895 memset(&inarg, 0, sizeof(inarg));
896 inarg.size = size;
897 req->in.h.opcode = FUSE_LISTXATTR;
898 req->in.h.nodeid = get_node_id(inode);
899 req->inode = inode;
900 req->in.numargs = 1;
901 req->in.args[0].size = sizeof(inarg);
902 req->in.args[0].value = &inarg;
903 /* This is really two different operations rolled into one */
904 req->out.numargs = 1;
905 if (size) {
906 req->out.argvar = 1;
907 req->out.args[0].size = size;
908 req->out.args[0].value = list;
909 } else {
910 req->out.args[0].size = sizeof(outarg);
911 req->out.args[0].value = &outarg;
912 }
913 request_send(fc, req);
914 ret = req->out.h.error;
915 if (!ret)
916 ret = size ? req->out.args[0].size : outarg.size;
917 else {
918 if (ret == -ENOSYS) {
919 fc->no_listxattr = 1;
920 ret = -EOPNOTSUPP;
921 }
922 }
923 fuse_put_request(fc, req);
924 return ret;
925}
926
927static int fuse_removexattr(struct dentry *entry, const char *name)
928{
929 struct inode *inode = entry->d_inode;
930 struct fuse_conn *fc = get_fuse_conn(inode);
931 struct fuse_req *req;
932 int err;
933
934 if (fc->no_removexattr)
935 return -EOPNOTSUPP;
936
937 req = fuse_get_request(fc);
938 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700939 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700940
941 req->in.h.opcode = FUSE_REMOVEXATTR;
942 req->in.h.nodeid = get_node_id(inode);
943 req->inode = inode;
944 req->in.numargs = 1;
945 req->in.args[0].size = strlen(name) + 1;
946 req->in.args[0].value = name;
947 request_send(fc, req);
948 err = req->out.h.error;
949 fuse_put_request(fc, req);
950 if (err == -ENOSYS) {
951 fc->no_removexattr = 1;
952 err = -EOPNOTSUPP;
953 }
954 return err;
955}
956
Miklos Szeredie5e55582005-09-09 13:10:28 -0700957static struct inode_operations fuse_dir_inode_operations = {
958 .lookup = fuse_lookup,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700959 .mkdir = fuse_mkdir,
960 .symlink = fuse_symlink,
961 .unlink = fuse_unlink,
962 .rmdir = fuse_rmdir,
963 .rename = fuse_rename,
964 .link = fuse_link,
965 .setattr = fuse_setattr,
966 .create = fuse_create,
967 .mknod = fuse_mknod,
Miklos Szeredie5e55582005-09-09 13:10:28 -0700968 .permission = fuse_permission,
969 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -0700970 .setxattr = fuse_setxattr,
971 .getxattr = fuse_getxattr,
972 .listxattr = fuse_listxattr,
973 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -0700974};
975
976static struct file_operations fuse_dir_operations = {
Miklos Szeredib6aeade2005-09-09 13:10:30 -0700977 .llseek = generic_file_llseek,
Miklos Szeredie5e55582005-09-09 13:10:28 -0700978 .read = generic_read_dir,
979 .readdir = fuse_readdir,
980 .open = fuse_dir_open,
981 .release = fuse_dir_release,
Miklos Szeredi82547982005-09-09 13:10:38 -0700982 .fsync = fuse_dir_fsync,
Miklos Szeredie5e55582005-09-09 13:10:28 -0700983};
984
985static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700986 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -0700987 .permission = fuse_permission,
988 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -0700989 .setxattr = fuse_setxattr,
990 .getxattr = fuse_getxattr,
991 .listxattr = fuse_listxattr,
992 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -0700993};
994
995static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700996 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -0700997 .follow_link = fuse_follow_link,
998 .put_link = fuse_put_link,
999 .readlink = generic_readlink,
1000 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001001 .setxattr = fuse_setxattr,
1002 .getxattr = fuse_getxattr,
1003 .listxattr = fuse_listxattr,
1004 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001005};
1006
1007void fuse_init_common(struct inode *inode)
1008{
1009 inode->i_op = &fuse_common_inode_operations;
1010}
1011
1012void fuse_init_dir(struct inode *inode)
1013{
1014 inode->i_op = &fuse_dir_inode_operations;
1015 inode->i_fop = &fuse_dir_operations;
1016}
1017
1018void fuse_init_symlink(struct inode *inode)
1019{
1020 inode->i_op = &fuse_symlink_inode_operations;
1021}