/[fuse_dbi]/fuse/trunk/kernel/dir.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /fuse/trunk/kernel/dir.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5 - (show annotations)
Wed Aug 4 11:40:49 2004 UTC (19 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 28678 byte(s)
copy CVS to trunk

1 /*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2004 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/slab.h>
13 #include <linux/file.h>
14
15 static struct inode_operations fuse_dir_inode_operations;
16 static struct inode_operations fuse_file_inode_operations;
17 static struct inode_operations fuse_symlink_inode_operations;
18
19 static struct file_operations fuse_dir_operations;
20
21 static struct dentry_operations fuse_dentry_operations;
22
23 #ifndef KERNEL_2_6
24 #define new_decode_dev(x) (x)
25 #define new_encode_dev(x) (x)
26 #endif
27
28 static void change_attributes(struct inode *inode, struct fuse_attr *attr)
29 {
30 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) {
31 #ifdef KERNEL_2_6
32 invalidate_inode_pages(inode->i_mapping);
33 #else
34 invalidate_inode_pages(inode);
35 #endif
36 }
37
38 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
39 inode->i_nlink = attr->nlink;
40 inode->i_uid = attr->uid;
41 inode->i_gid = attr->gid;
42 i_size_write(inode, attr->size);
43 inode->i_blksize = PAGE_CACHE_SIZE;
44 inode->i_blocks = attr->blocks;
45 #ifdef KERNEL_2_6
46 inode->i_atime.tv_sec = attr->atime;
47 inode->i_atime.tv_nsec = attr->atimensec;
48 inode->i_mtime.tv_sec = attr->mtime;
49 inode->i_mtime.tv_nsec = attr->mtimensec;
50 inode->i_ctime.tv_sec = attr->ctime;
51 inode->i_ctime.tv_nsec = attr->ctimensec;
52 #else
53 inode->i_atime = attr->atime;
54 inode->i_mtime = attr->mtime;
55 inode->i_ctime = attr->ctime;
56 #endif
57 }
58
59 static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
60 {
61 inode->i_mode = attr->mode & S_IFMT;
62 i_size_write(inode, attr->size);
63 if (S_ISREG(inode->i_mode)) {
64 inode->i_op = &fuse_file_inode_operations;
65 fuse_init_file_inode(inode);
66 }
67 else if (S_ISDIR(inode->i_mode)) {
68 inode->i_op = &fuse_dir_inode_operations;
69 inode->i_fop = &fuse_dir_operations;
70 }
71 else if (S_ISLNK(inode->i_mode)) {
72 inode->i_op = &fuse_symlink_inode_operations;
73 }
74 else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
75 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)){
76 inode->i_op = &fuse_file_inode_operations;
77 init_special_inode(inode, inode->i_mode,
78 new_decode_dev(attr->rdev));
79 } else
80 printk("fuse_init_inode: bad file type: %o\n", inode->i_mode);
81 }
82
83 struct inode *fuse_iget(struct super_block *sb, ino_t ino, int generation,
84 struct fuse_attr *attr, int version)
85 {
86 struct inode *inode;
87
88 inode = iget(sb, ino);
89 if (inode) {
90 if (!INO_FI(inode)) {
91 struct fuse_inode *fi = fuse_inode_alloc();
92 if (!fi) {
93 iput(inode);
94 inode = NULL;
95 goto out;
96 }
97 INO_FI(inode) = fi;
98 inode->i_generation = generation;
99 fuse_init_inode(inode, attr);
100 } else if (inode->i_generation != generation)
101 printk("fuse_iget: bad generation for ino %lu\n", ino);
102
103 change_attributes(inode, attr);
104 inode->i_version = version;
105 }
106 out:
107
108 return inode;
109 }
110
111 static int fuse_send_lookup(struct fuse_conn *fc, struct fuse_req *req,
112 struct inode *dir, struct dentry *entry,
113 struct fuse_entry_out *outarg, int *version)
114 {
115 req->in.h.opcode = FUSE_LOOKUP;
116 req->in.h.ino = dir->i_ino;
117 req->in.numargs = 1;
118 req->in.args[0].size = entry->d_name.len + 1;
119 req->in.args[0].value = entry->d_name.name;
120 req->out.numargs = 1;
121 req->out.args[0].size = sizeof(struct fuse_entry_out);
122 req->out.args[0].value = outarg;
123 request_send(fc, req);
124 *version = req->out.h.unique;
125 return req->out.h.error;
126 }
127
128 static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
129 struct fuse_entry_out *outarg, int *version)
130 {
131 struct fuse_conn *fc = INO_FC(dir);
132 struct fuse_req *req;
133 int err;
134
135 if (entry->d_name.len > FUSE_NAME_MAX)
136 return -ENAMETOOLONG;
137 req = fuse_get_request(fc);
138 if (!req)
139 return -ERESTARTSYS;
140
141 err = fuse_send_lookup(fc, req, dir, entry, outarg, version);
142 fuse_put_request(fc, req);
143 return err;
144 }
145
146 static inline unsigned long time_to_jiffies(unsigned long sec,
147 unsigned long nsec)
148 {
149 /* prevent wrapping of jiffies */
150 if (sec + 1 >= LONG_MAX / HZ)
151 return 0;
152
153 return jiffies + sec * HZ + nsec / (1000000000 / HZ);
154 }
155
156 static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
157 struct inode **inodep)
158 {
159 struct fuse_conn *fc = INO_FC(dir);
160 int err;
161 struct fuse_entry_out outarg;
162 int version;
163 struct inode *inode = NULL;
164 struct fuse_req *req;
165
166 if (entry->d_name.len > FUSE_NAME_MAX)
167 return -ENAMETOOLONG;
168 req = fuse_get_request(fc);
169 if (!req)
170 return -ERESTARTSYS;
171
172 err = fuse_send_lookup(fc, req, dir, entry, &outarg, &version);
173 if (!err) {
174 inode = fuse_iget(dir->i_sb, outarg.ino, outarg.generation,
175 &outarg.attr, version);
176 if (!inode) {
177 fuse_send_forget(fc, req, outarg.ino, version);
178 return -ENOMEM;
179 }
180 }
181 fuse_put_request(fc, req);
182 if (err && err != -ENOENT)
183 return err;
184
185 if (inode) {
186 struct fuse_inode *fi = INO_FI(inode);
187 entry->d_time = time_to_jiffies(outarg.entry_valid,
188 outarg.entry_valid_nsec);
189 fi->i_time = time_to_jiffies(outarg.attr_valid,
190 outarg.attr_valid_nsec);
191 }
192
193 entry->d_op = &fuse_dentry_operations;
194 *inodep = inode;
195 return 0;
196 }
197
198 static void fuse_invalidate_attr(struct inode *inode)
199 {
200 struct fuse_inode *fi = INO_FI(inode);
201 fi->i_time = jiffies - 1;
202 }
203
204 static int lookup_new_entry(struct fuse_conn *fc, struct fuse_req *req,
205 struct inode *dir, struct dentry *entry,
206 struct fuse_entry_out *outarg, int version,
207 int mode)
208 {
209 struct inode *inode;
210 struct fuse_inode *fi;
211 inode = fuse_iget(dir->i_sb, outarg->ino, outarg->generation,
212 &outarg->attr, version);
213 if (!inode) {
214 fuse_send_forget(fc, req, outarg->ino, version);
215 return -ENOMEM;
216 }
217 fuse_put_request(fc, req);
218
219 /* Don't allow userspace to do really stupid things... */
220 if ((inode->i_mode ^ mode) & S_IFMT) {
221 iput(inode);
222 printk("fuse_mknod: inode has wrong type\n");
223 return -EINVAL;
224 }
225
226 entry->d_time = time_to_jiffies(outarg->entry_valid,
227 outarg->entry_valid_nsec);
228
229 fi = INO_FI(inode);
230 fi->i_time = time_to_jiffies(outarg->attr_valid,
231 outarg->attr_valid_nsec);
232
233 d_instantiate(entry, inode);
234 fuse_invalidate_attr(dir);
235 return 0;
236 }
237
238
239 static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
240 dev_t rdev)
241 {
242 struct fuse_conn *fc = INO_FC(dir);
243 struct fuse_req *req = fuse_get_request(fc);
244 struct fuse_mknod_in inarg;
245 struct fuse_entry_out outarg;
246 int err;
247
248 if (!req)
249 return -ERESTARTSYS;
250
251 memset(&inarg, 0, sizeof(inarg));
252 inarg.mode = mode;
253 inarg.rdev = new_encode_dev(rdev);
254 req->in.h.opcode = FUSE_MKNOD;
255 req->in.h.ino = dir->i_ino;
256 req->in.numargs = 2;
257 req->in.args[0].size = sizeof(inarg);
258 req->in.args[0].value = &inarg;
259 req->in.args[1].size = entry->d_name.len + 1;
260 req->in.args[1].value = entry->d_name.name;
261 req->out.numargs = 1;
262 req->out.args[0].size = sizeof(outarg);
263 req->out.args[0].value = &outarg;
264 request_send(fc, req);
265 err = req->out.h.error;
266 if (!err)
267 err = lookup_new_entry(fc, req, dir, entry, &outarg,
268 req->out.h.unique, mode);
269 else
270 fuse_put_request(fc, req);
271 return err;
272 }
273
274 static int _fuse_create(struct inode *dir, struct dentry *entry, int mode)
275 {
276 return _fuse_mknod(dir, entry, mode, 0);
277 }
278
279
280 static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
281 {
282 struct fuse_conn *fc = INO_FC(dir);
283 struct fuse_req *req = fuse_get_request(fc);
284 struct fuse_mkdir_in inarg;
285 struct fuse_entry_out outarg;
286 int err;
287
288 if (!req)
289 return -ERESTARTSYS;
290
291 memset(&inarg, 0, sizeof(inarg));
292 inarg.mode = mode;
293 req->in.h.opcode = FUSE_MKDIR;
294 req->in.h.ino = dir->i_ino;
295 req->in.numargs = 2;
296 req->in.args[0].size = sizeof(inarg);
297 req->in.args[0].value = &inarg;
298 req->in.args[1].size = entry->d_name.len + 1;
299 req->in.args[1].value = entry->d_name.name;
300 req->out.numargs = 1;
301 req->out.args[0].size = sizeof(outarg);
302 req->out.args[0].value = &outarg;
303 request_send(fc, req);
304 err = req->out.h.error;
305 if (!err)
306 err = lookup_new_entry(fc, req, dir, entry, &outarg,
307 req->out.h.unique, S_IFDIR);
308 else
309 fuse_put_request(fc, req);
310 return err;
311 }
312
313 static int fuse_symlink(struct inode *dir, struct dentry *entry,
314 const char *link)
315 {
316 struct fuse_conn *fc = INO_FC(dir);
317 struct fuse_req *req;
318 struct fuse_entry_out outarg;
319 unsigned int len = strlen(link) + 1;
320 int err;
321
322 if (len > FUSE_SYMLINK_MAX)
323 return -ENAMETOOLONG;
324
325 req = fuse_get_request(fc);
326 if (!req)
327 return -ERESTARTSYS;
328
329 req->in.h.opcode = FUSE_SYMLINK;
330 req->in.h.ino = dir->i_ino;
331 req->in.numargs = 2;
332 req->in.args[0].size = entry->d_name.len + 1;
333 req->in.args[0].value = entry->d_name.name;
334 req->in.args[1].size = len;
335 req->in.args[1].value = link;
336 req->out.numargs = 1;
337 req->out.args[0].size = sizeof(outarg);
338 req->out.args[0].value = &outarg;
339 request_send(fc, req);
340 err = req->out.h.error;
341 if (!err)
342 err = lookup_new_entry(fc, req, dir, entry, &outarg,
343 req->out.h.unique, S_IFLNK);
344 else
345 fuse_put_request(fc, req);
346 return err;
347 }
348
349 static int fuse_unlink(struct inode *dir, struct dentry *entry)
350 {
351 struct fuse_conn *fc = INO_FC(dir);
352 struct fuse_req *req = fuse_get_request(fc);
353 int err;
354
355 if (!req)
356 return -ERESTARTSYS;
357
358 req->in.h.opcode = FUSE_UNLINK;
359 req->in.h.ino = dir->i_ino;
360 req->in.numargs = 1;
361 req->in.args[0].size = entry->d_name.len + 1;
362 req->in.args[0].value = entry->d_name.name;
363 request_send(fc, req);
364 err = req->out.h.error;
365 if (!err) {
366 struct inode *inode = entry->d_inode;
367
368 /* Set nlink to zero so the inode can be cleared, if
369 the inode does have more links this will be
370 discovered at the next lookup/getattr */
371 inode->i_nlink = 0;
372 fuse_invalidate_attr(inode);
373 fuse_invalidate_attr(dir);
374 }
375 fuse_put_request(fc, req);
376 return err;
377 }
378
379 static int fuse_rmdir(struct inode *dir, struct dentry *entry)
380 {
381 struct fuse_conn *fc = INO_FC(dir);
382 struct fuse_req *req = fuse_get_request(fc);
383 int err;
384
385 if (!req)
386 return -ERESTARTSYS;
387
388 req->in.h.opcode = FUSE_RMDIR;
389 req->in.h.ino = dir->i_ino;
390 req->in.numargs = 1;
391 req->in.args[0].size = entry->d_name.len + 1;
392 req->in.args[0].value = entry->d_name.name;
393 request_send(fc, req);
394 err = req->out.h.error;
395 if (!err) {
396 entry->d_inode->i_nlink = 0;
397 fuse_invalidate_attr(dir);
398 }
399 fuse_put_request(fc, req);
400 return err;
401 }
402
403 static int fuse_rename(struct inode *olddir, struct dentry *oldent,
404 struct inode *newdir, struct dentry *newent)
405 {
406 struct fuse_conn *fc = INO_FC(olddir);
407 struct fuse_req *req = fuse_get_request(fc);
408 struct fuse_rename_in inarg;
409 int err;
410
411 if (!req)
412 return -ERESTARTSYS;
413
414 memset(&inarg, 0, sizeof(inarg));
415 inarg.newdir = newdir->i_ino;
416 req->in.h.opcode = FUSE_RENAME;
417 req->in.h.ino = olddir->i_ino;
418 req->in.numargs = 3;
419 req->in.args[0].size = sizeof(inarg);
420 req->in.args[0].value = &inarg;
421 req->in.args[1].size = oldent->d_name.len + 1;
422 req->in.args[1].value = oldent->d_name.name;
423 req->in.args[2].size = newent->d_name.len + 1;
424 req->in.args[2].value = newent->d_name.name;
425 request_send(fc, req);
426 err = req->out.h.error;
427 fuse_put_request(fc, req);
428 if (!err) {
429 fuse_invalidate_attr(olddir);
430 if (olddir != newdir)
431 fuse_invalidate_attr(newdir);
432 }
433 return err;
434 }
435
436 static int fuse_link(struct dentry *entry, struct inode *newdir,
437 struct dentry *newent)
438 {
439 struct inode *inode = entry->d_inode;
440 struct fuse_conn *fc = INO_FC(inode);
441 struct fuse_req *req = fuse_get_request(fc);
442 struct fuse_link_in inarg;
443 struct fuse_entry_out outarg;
444 int err;
445
446 if (!req)
447 return -ERESTARTSYS;
448
449 memset(&inarg, 0, sizeof(inarg));
450 inarg.newdir = newdir->i_ino;
451 req->in.h.opcode = FUSE_LINK;
452 req->in.h.ino = inode->i_ino;
453 req->in.numargs = 2;
454 req->in.args[0].size = sizeof(inarg);
455 req->in.args[0].value = &inarg;
456 req->in.args[1].size = newent->d_name.len + 1;
457 req->in.args[1].value = newent->d_name.name;
458 req->out.numargs = 1;
459 req->out.args[0].size = sizeof(outarg);
460 req->out.args[0].value = &outarg;
461 request_send(fc, req);
462 err = req->out.h.error;
463 if (!err) {
464 /* Invalidate old entry, so attributes are refreshed */
465 d_invalidate(entry);
466 err = lookup_new_entry(fc, req, newdir, newent, &outarg,
467 req->out.h.unique, inode->i_mode);
468 } else
469 fuse_put_request(fc, req);
470 return err;
471 }
472
473 int fuse_do_getattr(struct inode *inode)
474 {
475 struct fuse_inode *fi = INO_FI(inode);
476 struct fuse_conn *fc = INO_FC(inode);
477 struct fuse_req *req = fuse_get_request(fc);
478 struct fuse_attr_out arg;
479 int err;
480
481 if (!req)
482 return -ERESTARTSYS;
483
484 req->in.h.opcode = FUSE_GETATTR;
485 req->in.h.ino = inode->i_ino;
486 req->out.numargs = 1;
487 req->out.args[0].size = sizeof(arg);
488 req->out.args[0].value = &arg;
489 request_send(fc, req);
490 err = req->out.h.error;
491 if (!err) {
492 change_attributes(inode, &arg.attr);
493 fi->i_time = time_to_jiffies(arg.attr_valid,
494 arg.attr_valid_nsec);
495 }
496 fuse_put_request(fc, req);
497 return err;
498 }
499
500 static int fuse_revalidate(struct dentry *entry)
501 {
502 struct inode *inode = entry->d_inode;
503 struct fuse_inode *fi = INO_FI(inode);
504 struct fuse_conn *fc = INO_FC(inode);
505
506 if (inode->i_ino == FUSE_ROOT_INO) {
507 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
508 current->fsuid != fc->uid)
509 return -EACCES;
510 } else if (!fi->i_time || time_before_eq(jiffies, fi->i_time))
511 return 0;
512
513 return fuse_do_getattr(inode);
514 }
515
516 static int _fuse_permission(struct inode *inode, int mask)
517 {
518 struct fuse_conn *fc = INO_FC(inode);
519
520 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid)
521 return -EACCES;
522 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
523 int err = vfs_permission(inode, mask);
524
525 /* If permission is denied, try to refresh file
526 attributes. This is also needed, because the root
527 node will at first have no permissions */
528
529 if (err == -EACCES) {
530 err = fuse_do_getattr(inode);
531 if (!err)
532 err = vfs_permission(inode, mask);
533 }
534
535 /* FIXME: Need some mechanism to revoke permissions:
536 currently if the filesystem suddenly changes the
537 file mode, we will not be informed abot that, and
538 continue to allow access to the file/directory.
539
540 This is actually not so grave, since the user can
541 simply keep access to the file/directory anyway by
542 keeping it open... */
543
544 return err;
545 } else
546 return 0;
547 }
548
549 static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
550 void *dstbuf, filldir_t filldir)
551 {
552 while (nbytes >= FUSE_NAME_OFFSET) {
553 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
554 size_t reclen = FUSE_DIRENT_SIZE(dirent);
555 int over;
556 if (dirent->namelen > NAME_MAX) {
557 printk("fuse_readdir: name too long\n");
558 return -EPROTO;
559 }
560 if (reclen > nbytes)
561 break;
562
563 over = filldir(dstbuf, dirent->name, dirent->namelen,
564 file->f_pos, dirent->ino, dirent->type);
565 if (over)
566 break;
567
568 buf += reclen;
569 file->f_pos += reclen;
570 nbytes -= reclen;
571 }
572
573 return 0;
574 }
575
576 static int fuse_checkdir(struct file *cfile, struct file *file)
577 {
578 struct inode *inode;
579 if (!cfile) {
580 printk("fuse_getdir: invalid file\n");
581 return -EPROTO;
582 }
583 inode = cfile->f_dentry->d_inode;
584 if (!S_ISREG(inode->i_mode)) {
585 printk("fuse_getdir: not a regular file\n");
586 fput(cfile);
587 return -EPROTO;
588 }
589
590 file->private_data = cfile;
591 return 0;
592 }
593
594 static int fuse_getdir(struct file *file)
595 {
596 struct inode *inode = file->f_dentry->d_inode;
597 struct fuse_conn *fc = INO_FC(inode);
598 struct fuse_req *req = fuse_get_request(fc);
599 struct fuse_getdir_out_i outarg;
600 int err;
601
602 if (!req)
603 return -ERESTARTSYS;
604
605 req->in.h.opcode = FUSE_GETDIR;
606 req->in.h.ino = inode->i_ino;
607 req->out.numargs = 1;
608 req->out.args[0].size = sizeof(struct fuse_getdir_out);
609 req->out.args[0].value = &outarg;
610 request_send(fc, req);
611 err = req->out.h.error;
612 if (!err)
613 err = fuse_checkdir(outarg.file, file);
614 fuse_put_request(fc, req);
615 return err;
616 }
617
618 #define DIR_BUFSIZE 2048
619 static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
620 {
621 struct file *cfile = file->private_data;
622 char *buf;
623 int ret;
624
625 if (!cfile) {
626 ret = fuse_getdir(file);
627 if (ret)
628 return ret;
629
630 cfile = file->private_data;
631 }
632
633 buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
634 if (!buf)
635 return -ENOMEM;
636
637 ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
638 if (ret < 0)
639 printk("fuse_readdir: failed to read container file\n");
640 else
641 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
642
643 kfree(buf);
644 return ret;
645 }
646
647 static char *read_link(struct dentry *dentry)
648 {
649 struct inode *inode = dentry->d_inode;
650 struct fuse_conn *fc = INO_FC(inode);
651 struct fuse_req *req = fuse_get_request(fc);
652 char *link;
653
654 if (!req)
655 return ERR_PTR(-ERESTARTSYS);
656
657 link = (char *) __get_free_page(GFP_KERNEL);
658 if (!link) {
659 link = ERR_PTR(-ENOMEM);
660 goto out;
661 }
662 req->in.h.opcode = FUSE_READLINK;
663 req->in.h.ino = inode->i_ino;
664 req->out.argvar = 1;
665 req->out.numargs = 1;
666 req->out.args[0].size = PAGE_SIZE - 1;
667 req->out.args[0].value = link;
668 request_send(fc, req);
669 if (req->out.h.error) {
670 free_page((unsigned long) link);
671 link = ERR_PTR(req->out.h.error);
672 } else
673 link[req->out.args[0].size] = '\0';
674 out:
675 fuse_put_request(fc, req);
676 return link;
677 }
678
679 static void free_link(char *link)
680 {
681 if (!IS_ERR(link))
682 free_page((unsigned long) link);
683 }
684
685 static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
686 {
687 int ret;
688 char *link;
689
690 link = read_link(dentry);
691 ret = vfs_readlink(dentry, buffer, buflen, link);
692 free_link(link);
693 return ret;
694 }
695
696 static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
697 {
698 int ret;
699 char *link;
700
701 link = read_link(dentry);
702 ret = vfs_follow_link(nd, link);
703 free_link(link);
704 return ret;
705 }
706
707 static int fuse_dir_open(struct inode *inode, struct file *file)
708 {
709 file->private_data = NULL;
710 return 0;
711 }
712
713 static int fuse_dir_release(struct inode *inode, struct file *file)
714 {
715 struct file *cfile = file->private_data;
716
717 if (cfile)
718 fput(cfile);
719
720 return 0;
721 }
722
723 static unsigned int iattr_to_fattr(struct iattr *iattr,
724 struct fuse_attr *fattr)
725 {
726 unsigned int ivalid = iattr->ia_valid;
727 unsigned int fvalid = 0;
728
729 memset(fattr, 0, sizeof(*fattr));
730
731 if (ivalid & ATTR_MODE)
732 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
733 if (ivalid & ATTR_UID)
734 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
735 if (ivalid & ATTR_GID)
736 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
737 if (ivalid & ATTR_SIZE)
738 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
739 /* You can only _set_ these together (they may change by themselves) */
740 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
741 fvalid |= FATTR_ATIME | FATTR_MTIME;
742 #ifdef KERNEL_2_6
743 fattr->atime = iattr->ia_atime.tv_sec;
744 fattr->mtime = iattr->ia_mtime.tv_sec;
745 #else
746 fattr->atime = iattr->ia_atime;
747 fattr->mtime = iattr->ia_mtime;
748 #endif
749 }
750
751 return fvalid;
752 }
753
754 static int fuse_setattr(struct dentry *entry, struct iattr *attr)
755 {
756 struct inode *inode = entry->d_inode;
757 struct fuse_conn *fc = INO_FC(inode);
758 struct fuse_inode *fi = INO_FI(inode);
759 struct fuse_req *req;
760 struct fuse_setattr_in inarg;
761 struct fuse_attr_out outarg;
762 int err;
763 int is_truncate = 0;
764
765 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
766 err = inode_change_ok(inode, attr);
767 if (err)
768 return err;
769 }
770
771 if (attr->ia_valid & ATTR_SIZE) {
772 unsigned long limit;
773 is_truncate = 1;
774
775 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
776 if (limit != RLIM_INFINITY && attr->ia_size > limit) {
777 send_sig(SIGXFSZ, current, 0);
778 return -EFBIG;
779 }
780 //fuse_sync_inode(inode);
781 }
782
783 req = fuse_get_request(fc);
784 if (!req)
785 return -ERESTARTSYS;
786
787 if (is_truncate)
788 down_write(&fi->write_sem);
789
790 memset(&inarg, 0, sizeof(inarg));
791 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
792 req->in.h.opcode = FUSE_SETATTR;
793 req->in.h.ino = inode->i_ino;
794 req->in.numargs = 1;
795 req->in.args[0].size = sizeof(inarg);
796 req->in.args[0].value = &inarg;
797 req->out.numargs = 1;
798 req->out.args[0].size = sizeof(outarg);
799 req->out.args[0].value = &outarg;
800 request_send(fc, req);
801 err = req->out.h.error;
802 fuse_put_request(fc, req);
803
804 if (!err) {
805 if (is_truncate) {
806 loff_t origsize = i_size_read(inode);
807 i_size_write(inode, outarg.attr.size);
808 up_write(&fi->write_sem);
809 if (origsize > outarg.attr.size)
810 vmtruncate(inode, outarg.attr.size);
811 }
812 change_attributes(inode, &outarg.attr);
813 fi->i_time = time_to_jiffies(outarg.attr_valid,
814 outarg.attr_valid_nsec);
815 } else if (is_truncate)
816 up_write(&fi->write_sem);
817
818 return err;
819 }
820
821 static int _fuse_dentry_revalidate(struct dentry *entry)
822 {
823 if (!entry->d_inode)
824 return 0;
825 else if (entry->d_time && time_after(jiffies, entry->d_time)) {
826 struct inode *inode = entry->d_inode;
827 struct fuse_inode *fi = INO_FI(inode);
828 struct fuse_entry_out outarg;
829 int version;
830 int ret;
831
832 ret = fuse_do_lookup(entry->d_parent->d_inode, entry, &outarg,
833 &version);
834 if (ret)
835 return 0;
836
837 if (outarg.ino != inode->i_ino)
838 return 0;
839
840 change_attributes(inode, &outarg.attr);
841 inode->i_version = version;
842 entry->d_time = time_to_jiffies(outarg.entry_valid,
843 outarg.entry_valid_nsec);
844 fi->i_time = time_to_jiffies(outarg.attr_valid,
845 outarg.attr_valid_nsec);
846 }
847 return 1;
848 }
849
850 #ifdef KERNEL_2_6
851
852 #define fuse_mknod _fuse_mknod
853
854 static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
855 struct kstat *stat)
856 {
857 struct inode *inode = entry->d_inode;
858 int err = fuse_revalidate(entry);
859 if (!err)
860 generic_fillattr(inode, stat);
861
862 return err;
863 }
864
865 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
866 struct nameidata *nd)
867 {
868 struct inode *inode;
869 int err = fuse_lookup_iget(dir, entry, &inode);
870 if (err)
871 return ERR_PTR(err);
872 return d_splice_alias(inode, entry);
873 }
874
875 static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
876 struct nameidata *nd)
877 {
878 return _fuse_create(dir, entry, mode);
879 }
880
881 static int fuse_permission(struct inode *inode, int mask,
882 struct nameidata *nd)
883 {
884 return _fuse_permission(inode, mask);
885 }
886
887 static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
888 {
889 return _fuse_dentry_revalidate(entry);
890 }
891
892 #else /* KERNEL_2_6 */
893
894 #define fuse_create _fuse_create
895 #define fuse_permission _fuse_permission
896
897 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
898 {
899 struct inode *inode;
900 struct dentry *alias;
901
902 int err = fuse_lookup_iget(dir, entry, &inode);
903 if (err)
904 return ERR_PTR(err);
905
906 if (inode && S_ISDIR(inode->i_mode) &&
907 (alias = d_find_alias(inode)) != NULL) {
908 dput(alias);
909 iput(inode);
910 printk("fuse: cannot assign an existing directory\n");
911 return ERR_PTR(-EPROTO);
912 }
913
914 d_add(entry, inode);
915 return NULL;
916 }
917
918 static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
919 int rdev)
920 {
921 return _fuse_mknod(dir, entry, mode, rdev);
922 }
923
924 static int fuse_dentry_revalidate(struct dentry *entry, int flags)
925 {
926 return _fuse_dentry_revalidate(entry);
927 }
928 #endif /* KERNEL_2_6 */
929
930 #ifdef HAVE_KERNEL_XATTR
931
932 #ifdef KERNEL_2_6
933 static int fuse_setxattr(struct dentry *entry, const char *name,
934 const void *value, size_t size, int flags)
935 #else
936 static int fuse_setxattr(struct dentry *entry, const char *name,
937 void *value, size_t size, int flags)
938 #endif
939 {
940 struct inode *inode = entry->d_inode;
941 struct fuse_conn *fc = INO_FC(inode);
942 struct fuse_req *req;
943 struct fuse_setxattr_in inarg;
944 int err;
945
946 if (size > FUSE_XATTR_SIZE_MAX)
947 return -E2BIG;
948
949 if (fc->no_setxattr)
950 return -EOPNOTSUPP;
951
952 req = fuse_get_request(fc);
953 if (!req)
954 return -ERESTARTSYS;
955
956 memset(&inarg, 0, sizeof(inarg));
957 inarg.size = size;
958 inarg.flags = flags;
959 req->in.h.opcode = FUSE_SETXATTR;
960 req->in.h.ino = inode->i_ino;
961 req->in.numargs = 3;
962 req->in.args[0].size = sizeof(inarg);
963 req->in.args[0].value = &inarg;
964 req->in.args[1].size = strlen(name) + 1;
965 req->in.args[1].value = name;
966 req->in.args[2].size = size;
967 req->in.args[2].value = value;
968 request_send(fc, req);
969 err = req->out.h.error;
970 if (err == -ENOSYS) {
971 fc->no_setxattr = 1;
972 err = -EOPNOTSUPP;
973 }
974 fuse_put_request(fc, req);
975 return err;
976 }
977
978 static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
979 void *value, size_t size)
980 {
981 struct inode *inode = entry->d_inode;
982 struct fuse_conn *fc = INO_FC(inode);
983 struct fuse_req *req;
984 struct fuse_getxattr_in inarg;
985 struct fuse_getxattr_out outarg;
986 ssize_t ret;
987
988 if (fc->no_getxattr)
989 return -EOPNOTSUPP;
990
991 req = fuse_get_request(fc);
992 if (!req)
993 return -ERESTARTSYS;
994
995 memset(&inarg, 0, sizeof(inarg));
996 inarg.size = size;
997 req->in.h.opcode = FUSE_GETXATTR;
998 req->in.h.ino = inode->i_ino;
999 req->in.numargs = 2;
1000 req->in.args[0].size = sizeof(inarg);
1001 req->in.args[0].value = &inarg;
1002 req->in.args[1].size = strlen(name) + 1;
1003 req->in.args[1].value = name;
1004 /* This is really two different operations rolled into one */
1005 req->out.numargs = 1;
1006 if (size) {
1007 req->out.argvar = 1;
1008 req->out.args[0].size = size;
1009 req->out.args[0].value = value;
1010 } else {
1011 req->out.args[0].size = sizeof(outarg);
1012 req->out.args[0].value = &outarg;
1013 }
1014 request_send(fc, req);
1015 ret = req->out.h.error;
1016 if (!ret)
1017 ret = size ? req->out.args[0].size : outarg.size;
1018 else {
1019 if (ret == -ENOSYS) {
1020 fc->no_getxattr = 1;
1021 ret = -EOPNOTSUPP;
1022 }
1023 }
1024 fuse_put_request(fc, req);
1025 return ret;
1026 }
1027
1028 static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1029 {
1030 struct inode *inode = entry->d_inode;
1031 struct fuse_conn *fc = INO_FC(inode);
1032 struct fuse_req *req;
1033 struct fuse_getxattr_in inarg;
1034 struct fuse_getxattr_out outarg;
1035 ssize_t ret;
1036
1037 if (fc->no_listxattr)
1038 return -EOPNOTSUPP;
1039
1040 req = fuse_get_request(fc);
1041 if (!req)
1042 return -ERESTARTSYS;
1043
1044 memset(&inarg, 0, sizeof(inarg));
1045 inarg.size = size;
1046 req->in.h.opcode = FUSE_LISTXATTR;
1047 req->in.h.ino = inode->i_ino;
1048 req->in.numargs = 1;
1049 req->in.args[0].size = sizeof(inarg);
1050 req->in.args[0].value = &inarg;
1051 /* This is really two different operations rolled into one */
1052 req->out.numargs = 1;
1053 if (size) {
1054 req->out.argvar = 1;
1055 req->out.args[0].size = size;
1056 req->out.args[0].value = list;
1057 } else {
1058 req->out.args[0].size = sizeof(outarg);
1059 req->out.args[0].value = &outarg;
1060 }
1061 request_send(fc, req);
1062 ret = req->out.h.error;
1063 if (!ret)
1064 ret = size ? req->out.args[0].size : outarg.size;
1065 else {
1066 if (ret == -ENOSYS) {
1067 fc->no_listxattr = 1;
1068 ret = -EOPNOTSUPP;
1069 }
1070 }
1071 fuse_put_request(fc, req);
1072 return ret;
1073 }
1074
1075 static int fuse_removexattr(struct dentry *entry, const char *name)
1076 {
1077 struct inode *inode = entry->d_inode;
1078 struct fuse_conn *fc = INO_FC(inode);
1079 struct fuse_req *req;
1080 int err;
1081
1082 if (fc->no_removexattr)
1083 return -EOPNOTSUPP;
1084
1085 req = fuse_get_request(fc);
1086 if (!req)
1087 return -ERESTARTSYS;
1088
1089 req->in.h.opcode = FUSE_REMOVEXATTR;
1090 req->in.h.ino = inode->i_ino;
1091 req->in.numargs = 1;
1092 req->in.args[0].size = strlen(name) + 1;
1093 req->in.args[0].value = name;
1094 request_send(fc, req);
1095 err = req->out.h.error;
1096 if (err == -ENOSYS) {
1097 fc->no_removexattr = 1;
1098 err = -EOPNOTSUPP;
1099 }
1100 fuse_put_request(fc, req);
1101 return err;
1102 }
1103
1104 #endif
1105
1106 static struct inode_operations fuse_dir_inode_operations =
1107 {
1108 .lookup = fuse_lookup,
1109 .create = fuse_create,
1110 .mknod = fuse_mknod,
1111 .mkdir = fuse_mkdir,
1112 .symlink = fuse_symlink,
1113 .unlink = fuse_unlink,
1114 .rmdir = fuse_rmdir,
1115 .rename = fuse_rename,
1116 .link = fuse_link,
1117 .setattr = fuse_setattr,
1118 .permission = fuse_permission,
1119 #ifdef KERNEL_2_6
1120 .getattr = fuse_getattr,
1121 #else
1122 .revalidate = fuse_revalidate,
1123 #endif
1124 #ifdef HAVE_KERNEL_XATTR
1125 .setxattr = fuse_setxattr,
1126 .getxattr = fuse_getxattr,
1127 .listxattr = fuse_listxattr,
1128 .removexattr = fuse_removexattr,
1129 #endif
1130 };
1131
1132 static struct file_operations fuse_dir_operations = {
1133 .read = generic_read_dir,
1134 .readdir = fuse_readdir,
1135 .open = fuse_dir_open,
1136 .release = fuse_dir_release,
1137 };
1138
1139 static struct inode_operations fuse_file_inode_operations = {
1140 .setattr = fuse_setattr,
1141 .permission = fuse_permission,
1142 #ifdef KERNEL_2_6
1143 .getattr = fuse_getattr,
1144 #else
1145 .revalidate = fuse_revalidate,
1146 #endif
1147 #ifdef HAVE_KERNEL_XATTR
1148 .setxattr = fuse_setxattr,
1149 .getxattr = fuse_getxattr,
1150 .listxattr = fuse_listxattr,
1151 .removexattr = fuse_removexattr,
1152 #endif
1153 };
1154
1155 static struct inode_operations fuse_symlink_inode_operations =
1156 {
1157 .setattr = fuse_setattr,
1158 .readlink = fuse_readlink,
1159 .follow_link = fuse_follow_link,
1160 #ifdef KERNEL_2_6
1161 .getattr = fuse_getattr,
1162 #else
1163 .revalidate = fuse_revalidate,
1164 #endif
1165 #ifdef HAVE_KERNEL_XATTR
1166 .setxattr = fuse_setxattr,
1167 .getxattr = fuse_getxattr,
1168 .listxattr = fuse_listxattr,
1169 .removexattr = fuse_removexattr,
1170 #endif
1171 };
1172
1173 static struct dentry_operations fuse_dentry_operations = {
1174 .d_revalidate = fuse_dentry_revalidate,
1175 };
1176
1177 /*
1178 * Local Variables:
1179 * indent-tabs-mode: t
1180 * c-basic-offset: 8
1181 * End:
1182 */

  ViewVC Help
Powered by ViewVC 1.1.26