blob: c045cc70c74931864e01763c3573eeae19c2d1e8 [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>
Miklos Szeredifd72faa2005-11-07 00:59:51 -080016#include <linux/mount.h>
Miklos Szeredie5e55582005-09-09 13:10:28 -070017
18static inline unsigned long time_to_jiffies(unsigned long sec,
19 unsigned long nsec)
20{
21 struct timespec ts = {sec, nsec};
22 return jiffies + timespec_to_jiffies(&ts);
23}
24
25static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
26 struct dentry *entry,
27 struct fuse_entry_out *outarg)
28{
29 req->in.h.opcode = FUSE_LOOKUP;
30 req->in.h.nodeid = get_node_id(dir);
31 req->inode = dir;
32 req->in.numargs = 1;
33 req->in.args[0].size = entry->d_name.len + 1;
34 req->in.args[0].value = entry->d_name.name;
35 req->out.numargs = 1;
36 req->out.args[0].size = sizeof(struct fuse_entry_out);
37 req->out.args[0].value = outarg;
38}
39
40static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
41{
42 if (!entry->d_inode || is_bad_inode(entry->d_inode))
43 return 0;
44 else if (time_after(jiffies, entry->d_time)) {
45 int err;
Miklos Szeredie5e55582005-09-09 13:10:28 -070046 struct fuse_entry_out outarg;
47 struct inode *inode = entry->d_inode;
48 struct fuse_inode *fi = get_fuse_inode(inode);
49 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7c352bd2005-09-09 13:10:39 -070050 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredie5e55582005-09-09 13:10:28 -070051 if (!req)
52 return 0;
53
54 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
Miklos Szeredi7c352bd2005-09-09 13:10:39 -070055 request_send(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -070056 err = req->out.h.error;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -070057 if (!err) {
58 if (outarg.nodeid != get_node_id(inode)) {
59 fuse_send_forget(fc, req, outarg.nodeid, 1);
60 return 0;
61 }
62 fi->nlookup ++;
63 }
Miklos Szeredie5e55582005-09-09 13:10:28 -070064 fuse_put_request(fc, req);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -070065 if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
Miklos Szeredie5e55582005-09-09 13:10:28 -070066 return 0;
67
68 fuse_change_attributes(inode, &outarg.attr);
Miklos Szeredie5e55582005-09-09 13:10:28 -070069 entry->d_time = time_to_jiffies(outarg.entry_valid,
70 outarg.entry_valid_nsec);
71 fi->i_time = time_to_jiffies(outarg.attr_valid,
72 outarg.attr_valid_nsec);
73 }
74 return 1;
75}
76
77static struct dentry_operations fuse_dentry_operations = {
78 .d_revalidate = fuse_dentry_revalidate,
79};
80
81static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
82 struct inode **inodep)
83{
84 int err;
Miklos Szeredie5e55582005-09-09 13:10:28 -070085 struct fuse_entry_out outarg;
86 struct inode *inode = NULL;
87 struct fuse_conn *fc = get_fuse_conn(dir);
88 struct fuse_req *req;
89
90 if (entry->d_name.len > FUSE_NAME_MAX)
91 return -ENAMETOOLONG;
92
93 req = fuse_get_request(fc);
94 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -070095 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -070096
97 fuse_lookup_init(req, dir, entry, &outarg);
98 request_send(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -070099 err = req->out.h.error;
Miklos Szerediee4e5272005-09-27 21:45:21 -0700100 if (!err && (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID))
101 err = -EIO;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700102 if (!err) {
103 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700104 &outarg.attr);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700105 if (!inode) {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700106 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700107 return -ENOMEM;
108 }
109 }
110 fuse_put_request(fc, req);
111 if (err && err != -ENOENT)
112 return err;
113
114 if (inode) {
115 struct fuse_inode *fi = get_fuse_inode(inode);
116 entry->d_time = time_to_jiffies(outarg.entry_valid,
117 outarg.entry_valid_nsec);
118 fi->i_time = time_to_jiffies(outarg.attr_valid,
119 outarg.attr_valid_nsec);
120 }
121
122 entry->d_op = &fuse_dentry_operations;
123 *inodep = inode;
124 return 0;
125}
126
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700127void fuse_invalidate_attr(struct inode *inode)
128{
129 get_fuse_inode(inode)->i_time = jiffies - 1;
130}
131
132static void fuse_invalidate_entry(struct dentry *entry)
133{
134 d_invalidate(entry);
135 entry->d_time = jiffies - 1;
136}
137
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800138static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
139 struct nameidata *nd)
140{
141 int err;
142 struct inode *inode;
143 struct fuse_conn *fc = get_fuse_conn(dir);
144 struct fuse_req *req;
145 struct fuse_open_in inarg;
146 struct fuse_open_out outopen;
147 struct fuse_entry_out outentry;
148 struct fuse_inode *fi;
149 struct fuse_file *ff;
150 struct file *file;
151 int flags = nd->intent.open.flags - 1;
152
153 err = -ENOSYS;
154 if (fc->no_create)
155 goto out;
156
157 err = -ENAMETOOLONG;
158 if (entry->d_name.len > FUSE_NAME_MAX)
159 goto out;
160
161 err = -EINTR;
162 req = fuse_get_request(fc);
163 if (!req)
164 goto out;
165
166 ff = fuse_file_alloc();
167 if (!ff)
168 goto out_put_request;
169
170 flags &= ~O_NOCTTY;
171 memset(&inarg, 0, sizeof(inarg));
172 inarg.flags = flags;
173 inarg.mode = mode;
174 req->in.h.opcode = FUSE_CREATE;
175 req->in.h.nodeid = get_node_id(dir);
176 req->inode = dir;
177 req->in.numargs = 2;
178 req->in.args[0].size = sizeof(inarg);
179 req->in.args[0].value = &inarg;
180 req->in.args[1].size = entry->d_name.len + 1;
181 req->in.args[1].value = entry->d_name.name;
182 req->out.numargs = 2;
183 req->out.args[0].size = sizeof(outentry);
184 req->out.args[0].value = &outentry;
185 req->out.args[1].size = sizeof(outopen);
186 req->out.args[1].value = &outopen;
187 request_send(fc, req);
188 err = req->out.h.error;
189 if (err) {
190 if (err == -ENOSYS)
191 fc->no_create = 1;
192 goto out_free_ff;
193 }
194
195 err = -EIO;
196 if (!S_ISREG(outentry.attr.mode))
197 goto out_free_ff;
198
199 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
200 &outentry.attr);
201 err = -ENOMEM;
202 if (!inode) {
203 flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
204 ff->fh = outopen.fh;
205 fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
206 goto out_put_request;
207 }
208 fuse_put_request(fc, req);
209 entry->d_time = time_to_jiffies(outentry.entry_valid,
210 outentry.entry_valid_nsec);
211 fi = get_fuse_inode(inode);
212 fi->i_time = time_to_jiffies(outentry.attr_valid,
213 outentry.attr_valid_nsec);
214
215 d_instantiate(entry, inode);
216 file = lookup_instantiate_filp(nd, entry, generic_file_open);
217 if (IS_ERR(file)) {
218 ff->fh = outopen.fh;
219 fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
220 return PTR_ERR(file);
221 }
222 fuse_finish_open(inode, file, ff, &outopen);
223 return 0;
224
225 out_free_ff:
226 fuse_file_free(ff);
227 out_put_request:
228 fuse_put_request(fc, req);
229 out:
230 return err;
231}
232
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700233static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
234 struct inode *dir, struct dentry *entry,
235 int mode)
236{
237 struct fuse_entry_out outarg;
238 struct inode *inode;
239 struct fuse_inode *fi;
240 int err;
241
242 req->in.h.nodeid = get_node_id(dir);
243 req->inode = dir;
244 req->out.numargs = 1;
245 req->out.args[0].size = sizeof(outarg);
246 req->out.args[0].value = &outarg;
247 request_send(fc, req);
248 err = req->out.h.error;
249 if (err) {
250 fuse_put_request(fc, req);
251 return err;
252 }
Miklos Szerediee4e5272005-09-27 21:45:21 -0700253 if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) {
254 fuse_put_request(fc, req);
255 return -EIO;
256 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700257 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
258 &outarg.attr);
259 if (!inode) {
260 fuse_send_forget(fc, req, outarg.nodeid, 1);
261 return -ENOMEM;
262 }
263 fuse_put_request(fc, req);
264
265 /* Don't allow userspace to do really stupid things... */
266 if ((inode->i_mode ^ mode) & S_IFMT) {
267 iput(inode);
268 return -EIO;
269 }
270
271 entry->d_time = time_to_jiffies(outarg.entry_valid,
272 outarg.entry_valid_nsec);
273
274 fi = get_fuse_inode(inode);
275 fi->i_time = time_to_jiffies(outarg.attr_valid,
276 outarg.attr_valid_nsec);
277
278 d_instantiate(entry, inode);
279 fuse_invalidate_attr(dir);
280 return 0;
281}
282
283static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
284 dev_t rdev)
285{
286 struct fuse_mknod_in inarg;
287 struct fuse_conn *fc = get_fuse_conn(dir);
288 struct fuse_req *req = fuse_get_request(fc);
289 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700290 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700291
292 memset(&inarg, 0, sizeof(inarg));
293 inarg.mode = mode;
294 inarg.rdev = new_encode_dev(rdev);
295 req->in.h.opcode = FUSE_MKNOD;
296 req->in.numargs = 2;
297 req->in.args[0].size = sizeof(inarg);
298 req->in.args[0].value = &inarg;
299 req->in.args[1].size = entry->d_name.len + 1;
300 req->in.args[1].value = entry->d_name.name;
301 return create_new_entry(fc, req, dir, entry, mode);
302}
303
304static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
305 struct nameidata *nd)
306{
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800307 if (nd && (nd->flags & LOOKUP_CREATE)) {
308 int err = fuse_create_open(dir, entry, mode, nd);
309 if (err != -ENOSYS)
310 return err;
311 /* Fall back on mknod */
312 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700313 return fuse_mknod(dir, entry, mode, 0);
314}
315
316static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
317{
318 struct fuse_mkdir_in inarg;
319 struct fuse_conn *fc = get_fuse_conn(dir);
320 struct fuse_req *req = fuse_get_request(fc);
321 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700322 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700323
324 memset(&inarg, 0, sizeof(inarg));
325 inarg.mode = mode;
326 req->in.h.opcode = FUSE_MKDIR;
327 req->in.numargs = 2;
328 req->in.args[0].size = sizeof(inarg);
329 req->in.args[0].value = &inarg;
330 req->in.args[1].size = entry->d_name.len + 1;
331 req->in.args[1].value = entry->d_name.name;
332 return create_new_entry(fc, req, dir, entry, S_IFDIR);
333}
334
335static int fuse_symlink(struct inode *dir, struct dentry *entry,
336 const char *link)
337{
338 struct fuse_conn *fc = get_fuse_conn(dir);
339 unsigned len = strlen(link) + 1;
340 struct fuse_req *req;
341
342 if (len > FUSE_SYMLINK_MAX)
343 return -ENAMETOOLONG;
344
345 req = fuse_get_request(fc);
346 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700347 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700348
349 req->in.h.opcode = FUSE_SYMLINK;
350 req->in.numargs = 2;
351 req->in.args[0].size = entry->d_name.len + 1;
352 req->in.args[0].value = entry->d_name.name;
353 req->in.args[1].size = len;
354 req->in.args[1].value = link;
355 return create_new_entry(fc, req, dir, entry, S_IFLNK);
356}
357
358static int fuse_unlink(struct inode *dir, struct dentry *entry)
359{
360 int err;
361 struct fuse_conn *fc = get_fuse_conn(dir);
362 struct fuse_req *req = fuse_get_request(fc);
363 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700364 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700365
366 req->in.h.opcode = FUSE_UNLINK;
367 req->in.h.nodeid = get_node_id(dir);
368 req->inode = dir;
369 req->in.numargs = 1;
370 req->in.args[0].size = entry->d_name.len + 1;
371 req->in.args[0].value = entry->d_name.name;
372 request_send(fc, req);
373 err = req->out.h.error;
374 fuse_put_request(fc, req);
375 if (!err) {
376 struct inode *inode = entry->d_inode;
377
378 /* Set nlink to zero so the inode can be cleared, if
379 the inode does have more links this will be
380 discovered at the next lookup/getattr */
381 inode->i_nlink = 0;
382 fuse_invalidate_attr(inode);
383 fuse_invalidate_attr(dir);
384 } else if (err == -EINTR)
385 fuse_invalidate_entry(entry);
386 return err;
387}
388
389static int fuse_rmdir(struct inode *dir, struct dentry *entry)
390{
391 int err;
392 struct fuse_conn *fc = get_fuse_conn(dir);
393 struct fuse_req *req = fuse_get_request(fc);
394 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700395 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700396
397 req->in.h.opcode = FUSE_RMDIR;
398 req->in.h.nodeid = get_node_id(dir);
399 req->inode = dir;
400 req->in.numargs = 1;
401 req->in.args[0].size = entry->d_name.len + 1;
402 req->in.args[0].value = entry->d_name.name;
403 request_send(fc, req);
404 err = req->out.h.error;
405 fuse_put_request(fc, req);
406 if (!err) {
407 entry->d_inode->i_nlink = 0;
408 fuse_invalidate_attr(dir);
409 } else if (err == -EINTR)
410 fuse_invalidate_entry(entry);
411 return err;
412}
413
414static int fuse_rename(struct inode *olddir, struct dentry *oldent,
415 struct inode *newdir, struct dentry *newent)
416{
417 int err;
418 struct fuse_rename_in inarg;
419 struct fuse_conn *fc = get_fuse_conn(olddir);
420 struct fuse_req *req = fuse_get_request(fc);
421 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700422 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700423
424 memset(&inarg, 0, sizeof(inarg));
425 inarg.newdir = get_node_id(newdir);
426 req->in.h.opcode = FUSE_RENAME;
427 req->in.h.nodeid = get_node_id(olddir);
428 req->inode = olddir;
429 req->inode2 = newdir;
430 req->in.numargs = 3;
431 req->in.args[0].size = sizeof(inarg);
432 req->in.args[0].value = &inarg;
433 req->in.args[1].size = oldent->d_name.len + 1;
434 req->in.args[1].value = oldent->d_name.name;
435 req->in.args[2].size = newent->d_name.len + 1;
436 req->in.args[2].value = newent->d_name.name;
437 request_send(fc, req);
438 err = req->out.h.error;
439 fuse_put_request(fc, req);
440 if (!err) {
441 fuse_invalidate_attr(olddir);
442 if (olddir != newdir)
443 fuse_invalidate_attr(newdir);
444 } else if (err == -EINTR) {
445 /* If request was interrupted, DEITY only knows if the
446 rename actually took place. If the invalidation
447 fails (e.g. some process has CWD under the renamed
448 directory), then there can be inconsistency between
449 the dcache and the real filesystem. Tough luck. */
450 fuse_invalidate_entry(oldent);
451 if (newent->d_inode)
452 fuse_invalidate_entry(newent);
453 }
454
455 return err;
456}
457
458static int fuse_link(struct dentry *entry, struct inode *newdir,
459 struct dentry *newent)
460{
461 int err;
462 struct fuse_link_in inarg;
463 struct inode *inode = entry->d_inode;
464 struct fuse_conn *fc = get_fuse_conn(inode);
465 struct fuse_req *req = fuse_get_request(fc);
466 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700467 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700468
469 memset(&inarg, 0, sizeof(inarg));
470 inarg.oldnodeid = get_node_id(inode);
471 req->in.h.opcode = FUSE_LINK;
472 req->inode2 = inode;
473 req->in.numargs = 2;
474 req->in.args[0].size = sizeof(inarg);
475 req->in.args[0].value = &inarg;
476 req->in.args[1].size = newent->d_name.len + 1;
477 req->in.args[1].value = newent->d_name.name;
478 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
479 /* Contrary to "normal" filesystems it can happen that link
480 makes two "logical" inodes point to the same "physical"
481 inode. We invalidate the attributes of the old one, so it
482 will reflect changes in the backing inode (link count,
483 etc.)
484 */
485 if (!err || err == -EINTR)
486 fuse_invalidate_attr(inode);
487 return err;
488}
489
Miklos Szeredie5e55582005-09-09 13:10:28 -0700490int fuse_do_getattr(struct inode *inode)
491{
492 int err;
493 struct fuse_attr_out arg;
494 struct fuse_conn *fc = get_fuse_conn(inode);
495 struct fuse_req *req = fuse_get_request(fc);
496 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700497 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700498
499 req->in.h.opcode = FUSE_GETATTR;
500 req->in.h.nodeid = get_node_id(inode);
501 req->inode = inode;
502 req->out.numargs = 1;
503 req->out.args[0].size = sizeof(arg);
504 req->out.args[0].value = &arg;
505 request_send(fc, req);
506 err = req->out.h.error;
507 fuse_put_request(fc, req);
508 if (!err) {
509 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
510 make_bad_inode(inode);
511 err = -EIO;
512 } else {
513 struct fuse_inode *fi = get_fuse_inode(inode);
514 fuse_change_attributes(inode, &arg.attr);
515 fi->i_time = time_to_jiffies(arg.attr_valid,
516 arg.attr_valid_nsec);
517 }
518 }
519 return err;
520}
521
Miklos Szeredi87729a52005-09-09 13:10:34 -0700522/*
523 * Calling into a user-controlled filesystem gives the filesystem
524 * daemon ptrace-like capabilities over the requester process. This
525 * means, that the filesystem daemon is able to record the exact
526 * filesystem operations performed, and can also control the behavior
527 * of the requester process in otherwise impossible ways. For example
528 * it can delay the operation for arbitrary length of time allowing
529 * DoS against the requester.
530 *
531 * For this reason only those processes can call into the filesystem,
532 * for which the owner of the mount has ptrace privilege. This
533 * excludes processes started by other users, suid or sgid processes.
534 */
535static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
536{
537 if (fc->flags & FUSE_ALLOW_OTHER)
538 return 1;
539
540 if (task->euid == fc->user_id &&
541 task->suid == fc->user_id &&
542 task->uid == fc->user_id &&
543 task->egid == fc->group_id &&
544 task->sgid == fc->group_id &&
545 task->gid == fc->group_id)
546 return 1;
547
548 return 0;
549}
550
Miklos Szeredie5e55582005-09-09 13:10:28 -0700551static int fuse_revalidate(struct dentry *entry)
552{
553 struct inode *inode = entry->d_inode;
554 struct fuse_inode *fi = get_fuse_inode(inode);
555 struct fuse_conn *fc = get_fuse_conn(inode);
556
Miklos Szeredi87729a52005-09-09 13:10:34 -0700557 if (!fuse_allow_task(fc, current))
558 return -EACCES;
559 if (get_node_id(inode) != FUSE_ROOT_ID &&
560 time_before_eq(jiffies, fi->i_time))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700561 return 0;
562
563 return fuse_do_getattr(inode);
564}
565
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800566static int fuse_access(struct inode *inode, int mask)
567{
568 struct fuse_conn *fc = get_fuse_conn(inode);
569 struct fuse_req *req;
570 struct fuse_access_in inarg;
571 int err;
572
573 if (fc->no_access)
574 return 0;
575
576 req = fuse_get_request(fc);
577 if (!req)
578 return -EINTR;
579
580 memset(&inarg, 0, sizeof(inarg));
581 inarg.mask = mask;
582 req->in.h.opcode = FUSE_ACCESS;
583 req->in.h.nodeid = get_node_id(inode);
584 req->inode = inode;
585 req->in.numargs = 1;
586 req->in.args[0].size = sizeof(inarg);
587 req->in.args[0].value = &inarg;
588 request_send(fc, req);
589 err = req->out.h.error;
590 fuse_put_request(fc, req);
591 if (err == -ENOSYS) {
592 fc->no_access = 1;
593 err = 0;
594 }
595 return err;
596}
597
Miklos Szeredie5e55582005-09-09 13:10:28 -0700598static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
599{
600 struct fuse_conn *fc = get_fuse_conn(inode);
601
Miklos Szeredi87729a52005-09-09 13:10:34 -0700602 if (!fuse_allow_task(fc, current))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700603 return -EACCES;
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700604 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
605 int err = generic_permission(inode, mask, NULL);
606
607 /* If permission is denied, try to refresh file
608 attributes. This is also needed, because the root
609 node will at first have no permissions */
610 if (err == -EACCES) {
611 err = fuse_do_getattr(inode);
612 if (!err)
613 err = generic_permission(inode, mask, NULL);
614 }
615
616 /* FIXME: Need some mechanism to revoke permissions:
617 currently if the filesystem suddenly changes the
618 file mode, we will not be informed about it, and
619 continue to allow access to the file/directory.
620
621 This is actually not so grave, since the user can
622 simply keep access to the file/directory anyway by
623 keeping it open... */
624
625 return err;
626 } else {
Miklos Szeredie5e55582005-09-09 13:10:28 -0700627 int mode = inode->i_mode;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700628 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
629 return -EACCES;
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800630
631 if (nd && (nd->flags & LOOKUP_ACCESS))
632 return fuse_access(inode, mask);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700633 return 0;
634 }
635}
636
637static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
638 void *dstbuf, filldir_t filldir)
639{
640 while (nbytes >= FUSE_NAME_OFFSET) {
641 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
642 size_t reclen = FUSE_DIRENT_SIZE(dirent);
643 int over;
644 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
645 return -EIO;
646 if (reclen > nbytes)
647 break;
648
649 over = filldir(dstbuf, dirent->name, dirent->namelen,
650 file->f_pos, dirent->ino, dirent->type);
651 if (over)
652 break;
653
654 buf += reclen;
655 nbytes -= reclen;
656 file->f_pos = dirent->off;
657 }
658
659 return 0;
660}
661
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700662static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
663 struct inode *inode, loff_t pos,
664 size_t count)
Miklos Szeredie5e55582005-09-09 13:10:28 -0700665{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700666 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700667}
668
669static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
670{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700671 int err;
672 size_t nbytes;
673 struct page *page;
674 struct inode *inode = file->f_dentry->d_inode;
675 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700676 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700677 if (!req)
678 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700679
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700680 page = alloc_page(GFP_KERNEL);
681 if (!page) {
682 fuse_put_request(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700683 return -ENOMEM;
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700684 }
685 req->num_pages = 1;
686 req->pages[0] = page;
687 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
688 err = req->out.h.error;
689 fuse_put_request(fc, req);
690 if (!err)
691 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
692 filldir);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700693
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700694 __free_page(page);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700695 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700696 return err;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700697}
698
699static char *read_link(struct dentry *dentry)
700{
701 struct inode *inode = dentry->d_inode;
702 struct fuse_conn *fc = get_fuse_conn(inode);
703 struct fuse_req *req = fuse_get_request(fc);
704 char *link;
705
706 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700707 return ERR_PTR(-EINTR);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700708
709 link = (char *) __get_free_page(GFP_KERNEL);
710 if (!link) {
711 link = ERR_PTR(-ENOMEM);
712 goto out;
713 }
714 req->in.h.opcode = FUSE_READLINK;
715 req->in.h.nodeid = get_node_id(inode);
716 req->inode = inode;
717 req->out.argvar = 1;
718 req->out.numargs = 1;
719 req->out.args[0].size = PAGE_SIZE - 1;
720 req->out.args[0].value = link;
721 request_send(fc, req);
722 if (req->out.h.error) {
723 free_page((unsigned long) link);
724 link = ERR_PTR(req->out.h.error);
725 } else
726 link[req->out.args[0].size] = '\0';
727 out:
728 fuse_put_request(fc, req);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700729 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700730 return link;
731}
732
733static void free_link(char *link)
734{
735 if (!IS_ERR(link))
736 free_page((unsigned long) link);
737}
738
739static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
740{
741 nd_set_link(nd, read_link(dentry));
742 return NULL;
743}
744
745static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
746{
747 free_link(nd_get_link(nd));
748}
749
750static int fuse_dir_open(struct inode *inode, struct file *file)
751{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700752 return fuse_open_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700753}
754
755static int fuse_dir_release(struct inode *inode, struct file *file)
756{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700757 return fuse_release_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700758}
759
Miklos Szeredi82547982005-09-09 13:10:38 -0700760static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
761{
762 /* nfsd can call this with no file */
763 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
764}
765
Miklos Szeredibefc6492005-11-07 00:59:52 -0800766static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700767{
768 unsigned ivalid = iattr->ia_valid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700769
770 if (ivalid & ATTR_MODE)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800771 arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700772 if (ivalid & ATTR_UID)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800773 arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700774 if (ivalid & ATTR_GID)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800775 arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700776 if (ivalid & ATTR_SIZE)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800777 arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700778 /* You can only _set_ these together (they may change by themselves) */
779 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredibefc6492005-11-07 00:59:52 -0800780 arg->valid |= FATTR_ATIME | FATTR_MTIME;
781 arg->atime = iattr->ia_atime.tv_sec;
782 arg->mtime = iattr->ia_mtime.tv_sec;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700783 }
Miklos Szeredibefc6492005-11-07 00:59:52 -0800784 if (ivalid & ATTR_FILE) {
785 struct fuse_file *ff = iattr->ia_file->private_data;
786 arg->valid |= FATTR_FH;
787 arg->fh = ff->fh;
788 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700789}
790
791static int fuse_setattr(struct dentry *entry, struct iattr *attr)
792{
793 struct inode *inode = entry->d_inode;
794 struct fuse_conn *fc = get_fuse_conn(inode);
795 struct fuse_inode *fi = get_fuse_inode(inode);
796 struct fuse_req *req;
797 struct fuse_setattr_in inarg;
798 struct fuse_attr_out outarg;
799 int err;
800 int is_truncate = 0;
801
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700802 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
803 err = inode_change_ok(inode, attr);
804 if (err)
805 return err;
806 }
807
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700808 if (attr->ia_valid & ATTR_SIZE) {
809 unsigned long limit;
810 is_truncate = 1;
811 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
812 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
813 send_sig(SIGXFSZ, current, 0);
814 return -EFBIG;
815 }
816 }
817
818 req = fuse_get_request(fc);
819 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700820 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700821
822 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredibefc6492005-11-07 00:59:52 -0800823 iattr_to_fattr(attr, &inarg);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700824 req->in.h.opcode = FUSE_SETATTR;
825 req->in.h.nodeid = get_node_id(inode);
826 req->inode = inode;
827 req->in.numargs = 1;
828 req->in.args[0].size = sizeof(inarg);
829 req->in.args[0].value = &inarg;
830 req->out.numargs = 1;
831 req->out.args[0].size = sizeof(outarg);
832 req->out.args[0].value = &outarg;
833 request_send(fc, req);
834 err = req->out.h.error;
835 fuse_put_request(fc, req);
836 if (!err) {
837 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
838 make_bad_inode(inode);
839 err = -EIO;
840 } else {
841 if (is_truncate) {
842 loff_t origsize = i_size_read(inode);
843 i_size_write(inode, outarg.attr.size);
844 if (origsize > outarg.attr.size)
845 vmtruncate(inode, outarg.attr.size);
846 }
847 fuse_change_attributes(inode, &outarg.attr);
848 fi->i_time = time_to_jiffies(outarg.attr_valid,
849 outarg.attr_valid_nsec);
850 }
851 } else if (err == -EINTR)
852 fuse_invalidate_attr(inode);
853
854 return err;
855}
856
Miklos Szeredie5e55582005-09-09 13:10:28 -0700857static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
858 struct kstat *stat)
859{
860 struct inode *inode = entry->d_inode;
861 int err = fuse_revalidate(entry);
862 if (!err)
863 generic_fillattr(inode, stat);
864
865 return err;
866}
867
868static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
869 struct nameidata *nd)
870{
871 struct inode *inode;
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800872 int err;
873
874 err = fuse_lookup_iget(dir, entry, &inode);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700875 if (err)
876 return ERR_PTR(err);
877 if (inode && S_ISDIR(inode->i_mode)) {
878 /* Don't allow creating an alias to a directory */
879 struct dentry *alias = d_find_alias(inode);
Miklos Szeredif12ec442005-10-30 15:02:25 -0800880 if (alias) {
Miklos Szeredie5e55582005-09-09 13:10:28 -0700881 dput(alias);
882 iput(inode);
883 return ERR_PTR(-EIO);
884 }
885 }
Miklos Szeredif12ec442005-10-30 15:02:25 -0800886 d_add(entry, inode);
887 return NULL;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700888}
889
Miklos Szeredi92a87802005-09-09 13:10:31 -0700890static int fuse_setxattr(struct dentry *entry, const char *name,
891 const void *value, size_t size, int flags)
892{
893 struct inode *inode = entry->d_inode;
894 struct fuse_conn *fc = get_fuse_conn(inode);
895 struct fuse_req *req;
896 struct fuse_setxattr_in inarg;
897 int err;
898
899 if (size > FUSE_XATTR_SIZE_MAX)
900 return -E2BIG;
901
902 if (fc->no_setxattr)
903 return -EOPNOTSUPP;
904
905 req = fuse_get_request(fc);
906 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700907 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700908
909 memset(&inarg, 0, sizeof(inarg));
910 inarg.size = size;
911 inarg.flags = flags;
912 req->in.h.opcode = FUSE_SETXATTR;
913 req->in.h.nodeid = get_node_id(inode);
914 req->inode = inode;
915 req->in.numargs = 3;
916 req->in.args[0].size = sizeof(inarg);
917 req->in.args[0].value = &inarg;
918 req->in.args[1].size = strlen(name) + 1;
919 req->in.args[1].value = name;
920 req->in.args[2].size = size;
921 req->in.args[2].value = value;
922 request_send(fc, req);
923 err = req->out.h.error;
924 fuse_put_request(fc, req);
925 if (err == -ENOSYS) {
926 fc->no_setxattr = 1;
927 err = -EOPNOTSUPP;
928 }
929 return err;
930}
931
932static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
933 void *value, size_t size)
934{
935 struct inode *inode = entry->d_inode;
936 struct fuse_conn *fc = get_fuse_conn(inode);
937 struct fuse_req *req;
938 struct fuse_getxattr_in inarg;
939 struct fuse_getxattr_out outarg;
940 ssize_t ret;
941
942 if (fc->no_getxattr)
943 return -EOPNOTSUPP;
944
945 req = fuse_get_request(fc);
946 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700947 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700948
949 memset(&inarg, 0, sizeof(inarg));
950 inarg.size = size;
951 req->in.h.opcode = FUSE_GETXATTR;
952 req->in.h.nodeid = get_node_id(inode);
953 req->inode = inode;
954 req->in.numargs = 2;
955 req->in.args[0].size = sizeof(inarg);
956 req->in.args[0].value = &inarg;
957 req->in.args[1].size = strlen(name) + 1;
958 req->in.args[1].value = name;
959 /* This is really two different operations rolled into one */
960 req->out.numargs = 1;
961 if (size) {
962 req->out.argvar = 1;
963 req->out.args[0].size = size;
964 req->out.args[0].value = value;
965 } else {
966 req->out.args[0].size = sizeof(outarg);
967 req->out.args[0].value = &outarg;
968 }
969 request_send(fc, req);
970 ret = req->out.h.error;
971 if (!ret)
972 ret = size ? req->out.args[0].size : outarg.size;
973 else {
974 if (ret == -ENOSYS) {
975 fc->no_getxattr = 1;
976 ret = -EOPNOTSUPP;
977 }
978 }
979 fuse_put_request(fc, req);
980 return ret;
981}
982
983static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
984{
985 struct inode *inode = entry->d_inode;
986 struct fuse_conn *fc = get_fuse_conn(inode);
987 struct fuse_req *req;
988 struct fuse_getxattr_in inarg;
989 struct fuse_getxattr_out outarg;
990 ssize_t ret;
991
992 if (fc->no_listxattr)
993 return -EOPNOTSUPP;
994
995 req = fuse_get_request(fc);
996 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700997 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700998
999 memset(&inarg, 0, sizeof(inarg));
1000 inarg.size = size;
1001 req->in.h.opcode = FUSE_LISTXATTR;
1002 req->in.h.nodeid = get_node_id(inode);
1003 req->inode = inode;
1004 req->in.numargs = 1;
1005 req->in.args[0].size = sizeof(inarg);
1006 req->in.args[0].value = &inarg;
1007 /* This is really two different operations rolled into one */
1008 req->out.numargs = 1;
1009 if (size) {
1010 req->out.argvar = 1;
1011 req->out.args[0].size = size;
1012 req->out.args[0].value = list;
1013 } else {
1014 req->out.args[0].size = sizeof(outarg);
1015 req->out.args[0].value = &outarg;
1016 }
1017 request_send(fc, req);
1018 ret = req->out.h.error;
1019 if (!ret)
1020 ret = size ? req->out.args[0].size : outarg.size;
1021 else {
1022 if (ret == -ENOSYS) {
1023 fc->no_listxattr = 1;
1024 ret = -EOPNOTSUPP;
1025 }
1026 }
1027 fuse_put_request(fc, req);
1028 return ret;
1029}
1030
1031static int fuse_removexattr(struct dentry *entry, const char *name)
1032{
1033 struct inode *inode = entry->d_inode;
1034 struct fuse_conn *fc = get_fuse_conn(inode);
1035 struct fuse_req *req;
1036 int err;
1037
1038 if (fc->no_removexattr)
1039 return -EOPNOTSUPP;
1040
1041 req = fuse_get_request(fc);
1042 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -07001043 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -07001044
1045 req->in.h.opcode = FUSE_REMOVEXATTR;
1046 req->in.h.nodeid = get_node_id(inode);
1047 req->inode = inode;
1048 req->in.numargs = 1;
1049 req->in.args[0].size = strlen(name) + 1;
1050 req->in.args[0].value = name;
1051 request_send(fc, req);
1052 err = req->out.h.error;
1053 fuse_put_request(fc, req);
1054 if (err == -ENOSYS) {
1055 fc->no_removexattr = 1;
1056 err = -EOPNOTSUPP;
1057 }
1058 return err;
1059}
1060
Miklos Szeredie5e55582005-09-09 13:10:28 -07001061static struct inode_operations fuse_dir_inode_operations = {
1062 .lookup = fuse_lookup,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001063 .mkdir = fuse_mkdir,
1064 .symlink = fuse_symlink,
1065 .unlink = fuse_unlink,
1066 .rmdir = fuse_rmdir,
1067 .rename = fuse_rename,
1068 .link = fuse_link,
1069 .setattr = fuse_setattr,
1070 .create = fuse_create,
1071 .mknod = fuse_mknod,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001072 .permission = fuse_permission,
1073 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001074 .setxattr = fuse_setxattr,
1075 .getxattr = fuse_getxattr,
1076 .listxattr = fuse_listxattr,
1077 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001078};
1079
1080static struct file_operations fuse_dir_operations = {
Miklos Szeredib6aeade2005-09-09 13:10:30 -07001081 .llseek = generic_file_llseek,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001082 .read = generic_read_dir,
1083 .readdir = fuse_readdir,
1084 .open = fuse_dir_open,
1085 .release = fuse_dir_release,
Miklos Szeredi82547982005-09-09 13:10:38 -07001086 .fsync = fuse_dir_fsync,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001087};
1088
1089static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001090 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001091 .permission = fuse_permission,
1092 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001093 .setxattr = fuse_setxattr,
1094 .getxattr = fuse_getxattr,
1095 .listxattr = fuse_listxattr,
1096 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001097};
1098
1099static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001100 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001101 .follow_link = fuse_follow_link,
1102 .put_link = fuse_put_link,
1103 .readlink = generic_readlink,
1104 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001105 .setxattr = fuse_setxattr,
1106 .getxattr = fuse_getxattr,
1107 .listxattr = fuse_listxattr,
1108 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001109};
1110
1111void fuse_init_common(struct inode *inode)
1112{
1113 inode->i_op = &fuse_common_inode_operations;
1114}
1115
1116void fuse_init_dir(struct inode *inode)
1117{
1118 inode->i_op = &fuse_dir_inode_operations;
1119 inode->i_fop = &fuse_dir_operations;
1120}
1121
1122void fuse_init_symlink(struct inode *inode)
1123{
1124 inode->i_op = &fuse_symlink_inode_operations;
1125}