blob: 3a47247a889e3ec107daec6b77f47af0eec00591 [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
Miklos Szeredif007d5c2005-11-28 13:44:16 -080077static int dir_alias(struct inode *inode)
78{
79 if (S_ISDIR(inode->i_mode)) {
80 /* Don't allow creating an alias to a directory */
81 struct dentry *alias = d_find_alias(inode);
82 if (alias) {
83 dput(alias);
84 return 1;
85 }
86 }
87 return 0;
88}
89
Miklos Szeredie5e55582005-09-09 13:10:28 -070090static struct dentry_operations fuse_dentry_operations = {
91 .d_revalidate = fuse_dentry_revalidate,
92};
93
94static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
95 struct inode **inodep)
96{
97 int err;
Miklos Szeredie5e55582005-09-09 13:10:28 -070098 struct fuse_entry_out outarg;
99 struct inode *inode = NULL;
100 struct fuse_conn *fc = get_fuse_conn(dir);
101 struct fuse_req *req;
102
103 if (entry->d_name.len > FUSE_NAME_MAX)
104 return -ENAMETOOLONG;
105
106 req = fuse_get_request(fc);
107 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700108 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700109
110 fuse_lookup_init(req, dir, entry, &outarg);
111 request_send(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700112 err = req->out.h.error;
Miklos Szerediee4e5272005-09-27 21:45:21 -0700113 if (!err && (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID))
114 err = -EIO;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700115 if (!err) {
116 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700117 &outarg.attr);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700118 if (!inode) {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700119 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700120 return -ENOMEM;
121 }
122 }
123 fuse_put_request(fc, req);
124 if (err && err != -ENOENT)
125 return err;
126
127 if (inode) {
128 struct fuse_inode *fi = get_fuse_inode(inode);
129 entry->d_time = time_to_jiffies(outarg.entry_valid,
130 outarg.entry_valid_nsec);
131 fi->i_time = time_to_jiffies(outarg.attr_valid,
132 outarg.attr_valid_nsec);
133 }
134
135 entry->d_op = &fuse_dentry_operations;
136 *inodep = inode;
137 return 0;
138}
139
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700140void fuse_invalidate_attr(struct inode *inode)
141{
142 get_fuse_inode(inode)->i_time = jiffies - 1;
143}
144
145static void fuse_invalidate_entry(struct dentry *entry)
146{
147 d_invalidate(entry);
148 entry->d_time = jiffies - 1;
149}
150
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800151static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
152 struct nameidata *nd)
153{
154 int err;
155 struct inode *inode;
156 struct fuse_conn *fc = get_fuse_conn(dir);
157 struct fuse_req *req;
158 struct fuse_open_in inarg;
159 struct fuse_open_out outopen;
160 struct fuse_entry_out outentry;
161 struct fuse_inode *fi;
162 struct fuse_file *ff;
163 struct file *file;
164 int flags = nd->intent.open.flags - 1;
165
166 err = -ENOSYS;
167 if (fc->no_create)
168 goto out;
169
170 err = -ENAMETOOLONG;
171 if (entry->d_name.len > FUSE_NAME_MAX)
172 goto out;
173
174 err = -EINTR;
175 req = fuse_get_request(fc);
176 if (!req)
177 goto out;
178
179 ff = fuse_file_alloc();
180 if (!ff)
181 goto out_put_request;
182
183 flags &= ~O_NOCTTY;
184 memset(&inarg, 0, sizeof(inarg));
185 inarg.flags = flags;
186 inarg.mode = mode;
187 req->in.h.opcode = FUSE_CREATE;
188 req->in.h.nodeid = get_node_id(dir);
189 req->inode = dir;
190 req->in.numargs = 2;
191 req->in.args[0].size = sizeof(inarg);
192 req->in.args[0].value = &inarg;
193 req->in.args[1].size = entry->d_name.len + 1;
194 req->in.args[1].value = entry->d_name.name;
195 req->out.numargs = 2;
196 req->out.args[0].size = sizeof(outentry);
197 req->out.args[0].value = &outentry;
198 req->out.args[1].size = sizeof(outopen);
199 req->out.args[1].value = &outopen;
200 request_send(fc, req);
201 err = req->out.h.error;
202 if (err) {
203 if (err == -ENOSYS)
204 fc->no_create = 1;
205 goto out_free_ff;
206 }
207
208 err = -EIO;
209 if (!S_ISREG(outentry.attr.mode))
210 goto out_free_ff;
211
212 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
213 &outentry.attr);
214 err = -ENOMEM;
215 if (!inode) {
216 flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
217 ff->fh = outopen.fh;
218 fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
219 goto out_put_request;
220 }
221 fuse_put_request(fc, req);
222 entry->d_time = time_to_jiffies(outentry.entry_valid,
223 outentry.entry_valid_nsec);
224 fi = get_fuse_inode(inode);
225 fi->i_time = time_to_jiffies(outentry.attr_valid,
226 outentry.attr_valid_nsec);
227
228 d_instantiate(entry, inode);
229 file = lookup_instantiate_filp(nd, entry, generic_file_open);
230 if (IS_ERR(file)) {
231 ff->fh = outopen.fh;
232 fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
233 return PTR_ERR(file);
234 }
235 fuse_finish_open(inode, file, ff, &outopen);
236 return 0;
237
238 out_free_ff:
239 fuse_file_free(ff);
240 out_put_request:
241 fuse_put_request(fc, req);
242 out:
243 return err;
244}
245
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700246static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
247 struct inode *dir, struct dentry *entry,
248 int mode)
249{
250 struct fuse_entry_out outarg;
251 struct inode *inode;
252 struct fuse_inode *fi;
253 int err;
254
255 req->in.h.nodeid = get_node_id(dir);
256 req->inode = dir;
257 req->out.numargs = 1;
258 req->out.args[0].size = sizeof(outarg);
259 req->out.args[0].value = &outarg;
260 request_send(fc, req);
261 err = req->out.h.error;
262 if (err) {
263 fuse_put_request(fc, req);
264 return err;
265 }
Miklos Szerediee4e5272005-09-27 21:45:21 -0700266 if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) {
267 fuse_put_request(fc, req);
268 return -EIO;
269 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700270 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
271 &outarg.attr);
272 if (!inode) {
273 fuse_send_forget(fc, req, outarg.nodeid, 1);
274 return -ENOMEM;
275 }
276 fuse_put_request(fc, req);
277
278 /* Don't allow userspace to do really stupid things... */
Miklos Szeredif007d5c2005-11-28 13:44:16 -0800279 if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700280 iput(inode);
281 return -EIO;
282 }
283
284 entry->d_time = time_to_jiffies(outarg.entry_valid,
285 outarg.entry_valid_nsec);
286
287 fi = get_fuse_inode(inode);
288 fi->i_time = time_to_jiffies(outarg.attr_valid,
289 outarg.attr_valid_nsec);
290
291 d_instantiate(entry, inode);
292 fuse_invalidate_attr(dir);
293 return 0;
294}
295
296static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
297 dev_t rdev)
298{
299 struct fuse_mknod_in inarg;
300 struct fuse_conn *fc = get_fuse_conn(dir);
301 struct fuse_req *req = fuse_get_request(fc);
302 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700303 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700304
305 memset(&inarg, 0, sizeof(inarg));
306 inarg.mode = mode;
307 inarg.rdev = new_encode_dev(rdev);
308 req->in.h.opcode = FUSE_MKNOD;
309 req->in.numargs = 2;
310 req->in.args[0].size = sizeof(inarg);
311 req->in.args[0].value = &inarg;
312 req->in.args[1].size = entry->d_name.len + 1;
313 req->in.args[1].value = entry->d_name.name;
314 return create_new_entry(fc, req, dir, entry, mode);
315}
316
317static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
318 struct nameidata *nd)
319{
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800320 if (nd && (nd->flags & LOOKUP_CREATE)) {
321 int err = fuse_create_open(dir, entry, mode, nd);
322 if (err != -ENOSYS)
323 return err;
324 /* Fall back on mknod */
325 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700326 return fuse_mknod(dir, entry, mode, 0);
327}
328
329static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
330{
331 struct fuse_mkdir_in inarg;
332 struct fuse_conn *fc = get_fuse_conn(dir);
333 struct fuse_req *req = fuse_get_request(fc);
334 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700335 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700336
337 memset(&inarg, 0, sizeof(inarg));
338 inarg.mode = mode;
339 req->in.h.opcode = FUSE_MKDIR;
340 req->in.numargs = 2;
341 req->in.args[0].size = sizeof(inarg);
342 req->in.args[0].value = &inarg;
343 req->in.args[1].size = entry->d_name.len + 1;
344 req->in.args[1].value = entry->d_name.name;
345 return create_new_entry(fc, req, dir, entry, S_IFDIR);
346}
347
348static int fuse_symlink(struct inode *dir, struct dentry *entry,
349 const char *link)
350{
351 struct fuse_conn *fc = get_fuse_conn(dir);
352 unsigned len = strlen(link) + 1;
353 struct fuse_req *req;
354
355 if (len > FUSE_SYMLINK_MAX)
356 return -ENAMETOOLONG;
357
358 req = fuse_get_request(fc);
359 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700360 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700361
362 req->in.h.opcode = FUSE_SYMLINK;
363 req->in.numargs = 2;
364 req->in.args[0].size = entry->d_name.len + 1;
365 req->in.args[0].value = entry->d_name.name;
366 req->in.args[1].size = len;
367 req->in.args[1].value = link;
368 return create_new_entry(fc, req, dir, entry, S_IFLNK);
369}
370
371static int fuse_unlink(struct inode *dir, struct dentry *entry)
372{
373 int err;
374 struct fuse_conn *fc = get_fuse_conn(dir);
375 struct fuse_req *req = fuse_get_request(fc);
376 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700377 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700378
379 req->in.h.opcode = FUSE_UNLINK;
380 req->in.h.nodeid = get_node_id(dir);
381 req->inode = dir;
382 req->in.numargs = 1;
383 req->in.args[0].size = entry->d_name.len + 1;
384 req->in.args[0].value = entry->d_name.name;
385 request_send(fc, req);
386 err = req->out.h.error;
387 fuse_put_request(fc, req);
388 if (!err) {
389 struct inode *inode = entry->d_inode;
390
391 /* Set nlink to zero so the inode can be cleared, if
392 the inode does have more links this will be
393 discovered at the next lookup/getattr */
394 inode->i_nlink = 0;
395 fuse_invalidate_attr(inode);
396 fuse_invalidate_attr(dir);
397 } else if (err == -EINTR)
398 fuse_invalidate_entry(entry);
399 return err;
400}
401
402static int fuse_rmdir(struct inode *dir, struct dentry *entry)
403{
404 int err;
405 struct fuse_conn *fc = get_fuse_conn(dir);
406 struct fuse_req *req = fuse_get_request(fc);
407 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700408 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700409
410 req->in.h.opcode = FUSE_RMDIR;
411 req->in.h.nodeid = get_node_id(dir);
412 req->inode = dir;
413 req->in.numargs = 1;
414 req->in.args[0].size = entry->d_name.len + 1;
415 req->in.args[0].value = entry->d_name.name;
416 request_send(fc, req);
417 err = req->out.h.error;
418 fuse_put_request(fc, req);
419 if (!err) {
420 entry->d_inode->i_nlink = 0;
421 fuse_invalidate_attr(dir);
422 } else if (err == -EINTR)
423 fuse_invalidate_entry(entry);
424 return err;
425}
426
427static int fuse_rename(struct inode *olddir, struct dentry *oldent,
428 struct inode *newdir, struct dentry *newent)
429{
430 int err;
431 struct fuse_rename_in inarg;
432 struct fuse_conn *fc = get_fuse_conn(olddir);
433 struct fuse_req *req = fuse_get_request(fc);
434 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700435 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700436
437 memset(&inarg, 0, sizeof(inarg));
438 inarg.newdir = get_node_id(newdir);
439 req->in.h.opcode = FUSE_RENAME;
440 req->in.h.nodeid = get_node_id(olddir);
441 req->inode = olddir;
442 req->inode2 = newdir;
443 req->in.numargs = 3;
444 req->in.args[0].size = sizeof(inarg);
445 req->in.args[0].value = &inarg;
446 req->in.args[1].size = oldent->d_name.len + 1;
447 req->in.args[1].value = oldent->d_name.name;
448 req->in.args[2].size = newent->d_name.len + 1;
449 req->in.args[2].value = newent->d_name.name;
450 request_send(fc, req);
451 err = req->out.h.error;
452 fuse_put_request(fc, req);
453 if (!err) {
454 fuse_invalidate_attr(olddir);
455 if (olddir != newdir)
456 fuse_invalidate_attr(newdir);
457 } else if (err == -EINTR) {
458 /* If request was interrupted, DEITY only knows if the
459 rename actually took place. If the invalidation
460 fails (e.g. some process has CWD under the renamed
461 directory), then there can be inconsistency between
462 the dcache and the real filesystem. Tough luck. */
463 fuse_invalidate_entry(oldent);
464 if (newent->d_inode)
465 fuse_invalidate_entry(newent);
466 }
467
468 return err;
469}
470
471static int fuse_link(struct dentry *entry, struct inode *newdir,
472 struct dentry *newent)
473{
474 int err;
475 struct fuse_link_in inarg;
476 struct inode *inode = entry->d_inode;
477 struct fuse_conn *fc = get_fuse_conn(inode);
478 struct fuse_req *req = fuse_get_request(fc);
479 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700480 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700481
482 memset(&inarg, 0, sizeof(inarg));
483 inarg.oldnodeid = get_node_id(inode);
484 req->in.h.opcode = FUSE_LINK;
485 req->inode2 = inode;
486 req->in.numargs = 2;
487 req->in.args[0].size = sizeof(inarg);
488 req->in.args[0].value = &inarg;
489 req->in.args[1].size = newent->d_name.len + 1;
490 req->in.args[1].value = newent->d_name.name;
491 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
492 /* Contrary to "normal" filesystems it can happen that link
493 makes two "logical" inodes point to the same "physical"
494 inode. We invalidate the attributes of the old one, so it
495 will reflect changes in the backing inode (link count,
496 etc.)
497 */
498 if (!err || err == -EINTR)
499 fuse_invalidate_attr(inode);
500 return err;
501}
502
Miklos Szeredie5e55582005-09-09 13:10:28 -0700503int fuse_do_getattr(struct inode *inode)
504{
505 int err;
506 struct fuse_attr_out arg;
507 struct fuse_conn *fc = get_fuse_conn(inode);
508 struct fuse_req *req = fuse_get_request(fc);
509 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700510 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700511
512 req->in.h.opcode = FUSE_GETATTR;
513 req->in.h.nodeid = get_node_id(inode);
514 req->inode = inode;
515 req->out.numargs = 1;
516 req->out.args[0].size = sizeof(arg);
517 req->out.args[0].value = &arg;
518 request_send(fc, req);
519 err = req->out.h.error;
520 fuse_put_request(fc, req);
521 if (!err) {
522 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
523 make_bad_inode(inode);
524 err = -EIO;
525 } else {
526 struct fuse_inode *fi = get_fuse_inode(inode);
527 fuse_change_attributes(inode, &arg.attr);
528 fi->i_time = time_to_jiffies(arg.attr_valid,
529 arg.attr_valid_nsec);
530 }
531 }
532 return err;
533}
534
Miklos Szeredi87729a52005-09-09 13:10:34 -0700535/*
536 * Calling into a user-controlled filesystem gives the filesystem
537 * daemon ptrace-like capabilities over the requester process. This
538 * means, that the filesystem daemon is able to record the exact
539 * filesystem operations performed, and can also control the behavior
540 * of the requester process in otherwise impossible ways. For example
541 * it can delay the operation for arbitrary length of time allowing
542 * DoS against the requester.
543 *
544 * For this reason only those processes can call into the filesystem,
545 * for which the owner of the mount has ptrace privilege. This
546 * excludes processes started by other users, suid or sgid processes.
547 */
548static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
549{
550 if (fc->flags & FUSE_ALLOW_OTHER)
551 return 1;
552
553 if (task->euid == fc->user_id &&
554 task->suid == fc->user_id &&
555 task->uid == fc->user_id &&
556 task->egid == fc->group_id &&
557 task->sgid == fc->group_id &&
558 task->gid == fc->group_id)
559 return 1;
560
561 return 0;
562}
563
Miklos Szeredie5e55582005-09-09 13:10:28 -0700564static int fuse_revalidate(struct dentry *entry)
565{
566 struct inode *inode = entry->d_inode;
567 struct fuse_inode *fi = get_fuse_inode(inode);
568 struct fuse_conn *fc = get_fuse_conn(inode);
569
Miklos Szeredi87729a52005-09-09 13:10:34 -0700570 if (!fuse_allow_task(fc, current))
571 return -EACCES;
572 if (get_node_id(inode) != FUSE_ROOT_ID &&
573 time_before_eq(jiffies, fi->i_time))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700574 return 0;
575
576 return fuse_do_getattr(inode);
577}
578
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800579static int fuse_access(struct inode *inode, int mask)
580{
581 struct fuse_conn *fc = get_fuse_conn(inode);
582 struct fuse_req *req;
583 struct fuse_access_in inarg;
584 int err;
585
586 if (fc->no_access)
587 return 0;
588
589 req = fuse_get_request(fc);
590 if (!req)
591 return -EINTR;
592
593 memset(&inarg, 0, sizeof(inarg));
594 inarg.mask = mask;
595 req->in.h.opcode = FUSE_ACCESS;
596 req->in.h.nodeid = get_node_id(inode);
597 req->inode = inode;
598 req->in.numargs = 1;
599 req->in.args[0].size = sizeof(inarg);
600 req->in.args[0].value = &inarg;
601 request_send(fc, req);
602 err = req->out.h.error;
603 fuse_put_request(fc, req);
604 if (err == -ENOSYS) {
605 fc->no_access = 1;
606 err = 0;
607 }
608 return err;
609}
610
Miklos Szeredie5e55582005-09-09 13:10:28 -0700611static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
612{
613 struct fuse_conn *fc = get_fuse_conn(inode);
614
Miklos Szeredi87729a52005-09-09 13:10:34 -0700615 if (!fuse_allow_task(fc, current))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700616 return -EACCES;
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700617 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
618 int err = generic_permission(inode, mask, NULL);
619
620 /* If permission is denied, try to refresh file
621 attributes. This is also needed, because the root
622 node will at first have no permissions */
623 if (err == -EACCES) {
624 err = fuse_do_getattr(inode);
625 if (!err)
626 err = generic_permission(inode, mask, NULL);
627 }
628
629 /* FIXME: Need some mechanism to revoke permissions:
630 currently if the filesystem suddenly changes the
631 file mode, we will not be informed about it, and
632 continue to allow access to the file/directory.
633
634 This is actually not so grave, since the user can
635 simply keep access to the file/directory anyway by
636 keeping it open... */
637
638 return err;
639 } else {
Miklos Szeredie5e55582005-09-09 13:10:28 -0700640 int mode = inode->i_mode;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700641 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
642 return -EACCES;
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800643
644 if (nd && (nd->flags & LOOKUP_ACCESS))
645 return fuse_access(inode, mask);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700646 return 0;
647 }
648}
649
650static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
651 void *dstbuf, filldir_t filldir)
652{
653 while (nbytes >= FUSE_NAME_OFFSET) {
654 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
655 size_t reclen = FUSE_DIRENT_SIZE(dirent);
656 int over;
657 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
658 return -EIO;
659 if (reclen > nbytes)
660 break;
661
662 over = filldir(dstbuf, dirent->name, dirent->namelen,
663 file->f_pos, dirent->ino, dirent->type);
664 if (over)
665 break;
666
667 buf += reclen;
668 nbytes -= reclen;
669 file->f_pos = dirent->off;
670 }
671
672 return 0;
673}
674
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700675static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
676 struct inode *inode, loff_t pos,
677 size_t count)
Miklos Szeredie5e55582005-09-09 13:10:28 -0700678{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700679 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700680}
681
682static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
683{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700684 int err;
685 size_t nbytes;
686 struct page *page;
687 struct inode *inode = file->f_dentry->d_inode;
688 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700689 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700690 if (!req)
691 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700692
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700693 page = alloc_page(GFP_KERNEL);
694 if (!page) {
695 fuse_put_request(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700696 return -ENOMEM;
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700697 }
698 req->num_pages = 1;
699 req->pages[0] = page;
700 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
701 err = req->out.h.error;
702 fuse_put_request(fc, req);
703 if (!err)
704 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
705 filldir);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700706
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700707 __free_page(page);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700708 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700709 return err;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700710}
711
712static char *read_link(struct dentry *dentry)
713{
714 struct inode *inode = dentry->d_inode;
715 struct fuse_conn *fc = get_fuse_conn(inode);
716 struct fuse_req *req = fuse_get_request(fc);
717 char *link;
718
719 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700720 return ERR_PTR(-EINTR);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700721
722 link = (char *) __get_free_page(GFP_KERNEL);
723 if (!link) {
724 link = ERR_PTR(-ENOMEM);
725 goto out;
726 }
727 req->in.h.opcode = FUSE_READLINK;
728 req->in.h.nodeid = get_node_id(inode);
729 req->inode = inode;
730 req->out.argvar = 1;
731 req->out.numargs = 1;
732 req->out.args[0].size = PAGE_SIZE - 1;
733 req->out.args[0].value = link;
734 request_send(fc, req);
735 if (req->out.h.error) {
736 free_page((unsigned long) link);
737 link = ERR_PTR(req->out.h.error);
738 } else
739 link[req->out.args[0].size] = '\0';
740 out:
741 fuse_put_request(fc, req);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700742 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700743 return link;
744}
745
746static void free_link(char *link)
747{
748 if (!IS_ERR(link))
749 free_page((unsigned long) link);
750}
751
752static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
753{
754 nd_set_link(nd, read_link(dentry));
755 return NULL;
756}
757
758static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
759{
760 free_link(nd_get_link(nd));
761}
762
763static int fuse_dir_open(struct inode *inode, struct file *file)
764{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700765 return fuse_open_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700766}
767
768static int fuse_dir_release(struct inode *inode, struct file *file)
769{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700770 return fuse_release_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700771}
772
Miklos Szeredi82547982005-09-09 13:10:38 -0700773static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
774{
775 /* nfsd can call this with no file */
776 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
777}
778
Miklos Szeredibefc6492005-11-07 00:59:52 -0800779static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700780{
781 unsigned ivalid = iattr->ia_valid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700782
783 if (ivalid & ATTR_MODE)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800784 arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700785 if (ivalid & ATTR_UID)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800786 arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700787 if (ivalid & ATTR_GID)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800788 arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700789 if (ivalid & ATTR_SIZE)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800790 arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700791 /* You can only _set_ these together (they may change by themselves) */
792 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredibefc6492005-11-07 00:59:52 -0800793 arg->valid |= FATTR_ATIME | FATTR_MTIME;
794 arg->atime = iattr->ia_atime.tv_sec;
795 arg->mtime = iattr->ia_mtime.tv_sec;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700796 }
Miklos Szeredibefc6492005-11-07 00:59:52 -0800797 if (ivalid & ATTR_FILE) {
798 struct fuse_file *ff = iattr->ia_file->private_data;
799 arg->valid |= FATTR_FH;
800 arg->fh = ff->fh;
801 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700802}
803
804static int fuse_setattr(struct dentry *entry, struct iattr *attr)
805{
806 struct inode *inode = entry->d_inode;
807 struct fuse_conn *fc = get_fuse_conn(inode);
808 struct fuse_inode *fi = get_fuse_inode(inode);
809 struct fuse_req *req;
810 struct fuse_setattr_in inarg;
811 struct fuse_attr_out outarg;
812 int err;
813 int is_truncate = 0;
814
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700815 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
816 err = inode_change_ok(inode, attr);
817 if (err)
818 return err;
819 }
820
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700821 if (attr->ia_valid & ATTR_SIZE) {
822 unsigned long limit;
823 is_truncate = 1;
824 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
825 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
826 send_sig(SIGXFSZ, current, 0);
827 return -EFBIG;
828 }
829 }
830
831 req = fuse_get_request(fc);
832 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700833 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700834
835 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredibefc6492005-11-07 00:59:52 -0800836 iattr_to_fattr(attr, &inarg);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700837 req->in.h.opcode = FUSE_SETATTR;
838 req->in.h.nodeid = get_node_id(inode);
839 req->inode = inode;
840 req->in.numargs = 1;
841 req->in.args[0].size = sizeof(inarg);
842 req->in.args[0].value = &inarg;
843 req->out.numargs = 1;
844 req->out.args[0].size = sizeof(outarg);
845 req->out.args[0].value = &outarg;
846 request_send(fc, req);
847 err = req->out.h.error;
848 fuse_put_request(fc, req);
849 if (!err) {
850 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
851 make_bad_inode(inode);
852 err = -EIO;
853 } else {
854 if (is_truncate) {
855 loff_t origsize = i_size_read(inode);
856 i_size_write(inode, outarg.attr.size);
857 if (origsize > outarg.attr.size)
858 vmtruncate(inode, outarg.attr.size);
859 }
860 fuse_change_attributes(inode, &outarg.attr);
861 fi->i_time = time_to_jiffies(outarg.attr_valid,
862 outarg.attr_valid_nsec);
863 }
864 } else if (err == -EINTR)
865 fuse_invalidate_attr(inode);
866
867 return err;
868}
869
Miklos Szeredie5e55582005-09-09 13:10:28 -0700870static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
871 struct kstat *stat)
872{
873 struct inode *inode = entry->d_inode;
874 int err = fuse_revalidate(entry);
875 if (!err)
876 generic_fillattr(inode, stat);
877
878 return err;
879}
880
881static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
882 struct nameidata *nd)
883{
884 struct inode *inode;
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800885 int err;
886
887 err = fuse_lookup_iget(dir, entry, &inode);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700888 if (err)
889 return ERR_PTR(err);
Miklos Szeredif007d5c2005-11-28 13:44:16 -0800890 if (inode && dir_alias(inode)) {
891 iput(inode);
892 return ERR_PTR(-EIO);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700893 }
Miklos Szeredif12ec442005-10-30 15:02:25 -0800894 d_add(entry, inode);
895 return NULL;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700896}
897
Miklos Szeredi92a87802005-09-09 13:10:31 -0700898static int fuse_setxattr(struct dentry *entry, const char *name,
899 const void *value, size_t size, int flags)
900{
901 struct inode *inode = entry->d_inode;
902 struct fuse_conn *fc = get_fuse_conn(inode);
903 struct fuse_req *req;
904 struct fuse_setxattr_in inarg;
905 int err;
906
907 if (size > FUSE_XATTR_SIZE_MAX)
908 return -E2BIG;
909
910 if (fc->no_setxattr)
911 return -EOPNOTSUPP;
912
913 req = fuse_get_request(fc);
914 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700915 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700916
917 memset(&inarg, 0, sizeof(inarg));
918 inarg.size = size;
919 inarg.flags = flags;
920 req->in.h.opcode = FUSE_SETXATTR;
921 req->in.h.nodeid = get_node_id(inode);
922 req->inode = inode;
923 req->in.numargs = 3;
924 req->in.args[0].size = sizeof(inarg);
925 req->in.args[0].value = &inarg;
926 req->in.args[1].size = strlen(name) + 1;
927 req->in.args[1].value = name;
928 req->in.args[2].size = size;
929 req->in.args[2].value = value;
930 request_send(fc, req);
931 err = req->out.h.error;
932 fuse_put_request(fc, req);
933 if (err == -ENOSYS) {
934 fc->no_setxattr = 1;
935 err = -EOPNOTSUPP;
936 }
937 return err;
938}
939
940static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
941 void *value, size_t size)
942{
943 struct inode *inode = entry->d_inode;
944 struct fuse_conn *fc = get_fuse_conn(inode);
945 struct fuse_req *req;
946 struct fuse_getxattr_in inarg;
947 struct fuse_getxattr_out outarg;
948 ssize_t ret;
949
950 if (fc->no_getxattr)
951 return -EOPNOTSUPP;
952
953 req = fuse_get_request(fc);
954 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700955 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700956
957 memset(&inarg, 0, sizeof(inarg));
958 inarg.size = size;
959 req->in.h.opcode = FUSE_GETXATTR;
960 req->in.h.nodeid = get_node_id(inode);
961 req->inode = inode;
962 req->in.numargs = 2;
963 req->in.args[0].size = sizeof(inarg);
964 req->in.args[0].value = &inarg;
965 req->in.args[1].size = strlen(name) + 1;
966 req->in.args[1].value = name;
967 /* This is really two different operations rolled into one */
968 req->out.numargs = 1;
969 if (size) {
970 req->out.argvar = 1;
971 req->out.args[0].size = size;
972 req->out.args[0].value = value;
973 } else {
974 req->out.args[0].size = sizeof(outarg);
975 req->out.args[0].value = &outarg;
976 }
977 request_send(fc, req);
978 ret = req->out.h.error;
979 if (!ret)
980 ret = size ? req->out.args[0].size : outarg.size;
981 else {
982 if (ret == -ENOSYS) {
983 fc->no_getxattr = 1;
984 ret = -EOPNOTSUPP;
985 }
986 }
987 fuse_put_request(fc, req);
988 return ret;
989}
990
991static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
992{
993 struct inode *inode = entry->d_inode;
994 struct fuse_conn *fc = get_fuse_conn(inode);
995 struct fuse_req *req;
996 struct fuse_getxattr_in inarg;
997 struct fuse_getxattr_out outarg;
998 ssize_t ret;
999
1000 if (fc->no_listxattr)
1001 return -EOPNOTSUPP;
1002
1003 req = fuse_get_request(fc);
1004 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -07001005 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -07001006
1007 memset(&inarg, 0, sizeof(inarg));
1008 inarg.size = size;
1009 req->in.h.opcode = FUSE_LISTXATTR;
1010 req->in.h.nodeid = get_node_id(inode);
1011 req->inode = inode;
1012 req->in.numargs = 1;
1013 req->in.args[0].size = sizeof(inarg);
1014 req->in.args[0].value = &inarg;
1015 /* This is really two different operations rolled into one */
1016 req->out.numargs = 1;
1017 if (size) {
1018 req->out.argvar = 1;
1019 req->out.args[0].size = size;
1020 req->out.args[0].value = list;
1021 } else {
1022 req->out.args[0].size = sizeof(outarg);
1023 req->out.args[0].value = &outarg;
1024 }
1025 request_send(fc, req);
1026 ret = req->out.h.error;
1027 if (!ret)
1028 ret = size ? req->out.args[0].size : outarg.size;
1029 else {
1030 if (ret == -ENOSYS) {
1031 fc->no_listxattr = 1;
1032 ret = -EOPNOTSUPP;
1033 }
1034 }
1035 fuse_put_request(fc, req);
1036 return ret;
1037}
1038
1039static int fuse_removexattr(struct dentry *entry, const char *name)
1040{
1041 struct inode *inode = entry->d_inode;
1042 struct fuse_conn *fc = get_fuse_conn(inode);
1043 struct fuse_req *req;
1044 int err;
1045
1046 if (fc->no_removexattr)
1047 return -EOPNOTSUPP;
1048
1049 req = fuse_get_request(fc);
1050 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -07001051 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -07001052
1053 req->in.h.opcode = FUSE_REMOVEXATTR;
1054 req->in.h.nodeid = get_node_id(inode);
1055 req->inode = inode;
1056 req->in.numargs = 1;
1057 req->in.args[0].size = strlen(name) + 1;
1058 req->in.args[0].value = name;
1059 request_send(fc, req);
1060 err = req->out.h.error;
1061 fuse_put_request(fc, req);
1062 if (err == -ENOSYS) {
1063 fc->no_removexattr = 1;
1064 err = -EOPNOTSUPP;
1065 }
1066 return err;
1067}
1068
Miklos Szeredie5e55582005-09-09 13:10:28 -07001069static struct inode_operations fuse_dir_inode_operations = {
1070 .lookup = fuse_lookup,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001071 .mkdir = fuse_mkdir,
1072 .symlink = fuse_symlink,
1073 .unlink = fuse_unlink,
1074 .rmdir = fuse_rmdir,
1075 .rename = fuse_rename,
1076 .link = fuse_link,
1077 .setattr = fuse_setattr,
1078 .create = fuse_create,
1079 .mknod = fuse_mknod,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001080 .permission = fuse_permission,
1081 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001082 .setxattr = fuse_setxattr,
1083 .getxattr = fuse_getxattr,
1084 .listxattr = fuse_listxattr,
1085 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001086};
1087
1088static struct file_operations fuse_dir_operations = {
Miklos Szeredib6aeade2005-09-09 13:10:30 -07001089 .llseek = generic_file_llseek,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001090 .read = generic_read_dir,
1091 .readdir = fuse_readdir,
1092 .open = fuse_dir_open,
1093 .release = fuse_dir_release,
Miklos Szeredi82547982005-09-09 13:10:38 -07001094 .fsync = fuse_dir_fsync,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001095};
1096
1097static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001098 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001099 .permission = fuse_permission,
1100 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001101 .setxattr = fuse_setxattr,
1102 .getxattr = fuse_getxattr,
1103 .listxattr = fuse_listxattr,
1104 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001105};
1106
1107static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001108 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001109 .follow_link = fuse_follow_link,
1110 .put_link = fuse_put_link,
1111 .readlink = generic_readlink,
1112 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001113 .setxattr = fuse_setxattr,
1114 .getxattr = fuse_getxattr,
1115 .listxattr = fuse_listxattr,
1116 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001117};
1118
1119void fuse_init_common(struct inode *inode)
1120{
1121 inode->i_op = &fuse_common_inode_operations;
1122}
1123
1124void fuse_init_dir(struct inode *inode)
1125{
1126 inode->i_op = &fuse_dir_inode_operations;
1127 inode->i_fop = &fuse_dir_operations;
1128}
1129
1130void fuse_init_symlink(struct inode *inode)
1131{
1132 inode->i_op = &fuse_symlink_inode_operations;
1133}