/[fuse_dbi]/fuse/cvs/lib/fuse.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/cvs/lib/fuse.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations)
Wed Aug 4 11:36:44 2004 UTC (19 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 45280 byte(s)
import current CVS of fuse

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 LGPL.
6 See the file COPYING.LIB
7 */
8
9 #include <config.h>
10 #include "fuse_i.h"
11 #include <linux/fuse.h>
12
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <limits.h>
17 #include <errno.h>
18 #include <sys/param.h>
19
20 #define FUSE_MAX_PATH 4096
21 #define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
22
23 #define ENTRY_REVALIDATE_TIME 1 /* sec */
24 #define ATTR_REVALIDATE_TIME 1 /* sec */
25
26 static const char *opname(enum fuse_opcode opcode)
27 {
28 switch (opcode) {
29 case FUSE_LOOKUP: return "LOOKUP";
30 case FUSE_FORGET: return "FORGET";
31 case FUSE_GETATTR: return "GETATTR";
32 case FUSE_SETATTR: return "SETATTR";
33 case FUSE_READLINK: return "READLINK";
34 case FUSE_SYMLINK: return "SYMLINK";
35 case FUSE_GETDIR: return "GETDIR";
36 case FUSE_MKNOD: return "MKNOD";
37 case FUSE_MKDIR: return "MKDIR";
38 case FUSE_UNLINK: return "UNLINK";
39 case FUSE_RMDIR: return "RMDIR";
40 case FUSE_RENAME: return "RENAME";
41 case FUSE_LINK: return "LINK";
42 case FUSE_OPEN: return "OPEN";
43 case FUSE_READ: return "READ";
44 case FUSE_WRITE: return "WRITE";
45 case FUSE_STATFS: return "STATFS";
46 case FUSE_FLUSH: return "FLUSH";
47 case FUSE_RELEASE: return "RELEASE";
48 case FUSE_FSYNC: return "FSYNC";
49 case FUSE_SETXATTR: return "SETXATTR";
50 case FUSE_GETXATTR: return "GETXATTR";
51 case FUSE_LISTXATTR: return "LISTXATTR";
52 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
53 default: return "???";
54 }
55 }
56
57
58 static inline void dec_avail(struct fuse *f)
59 {
60 pthread_mutex_lock(&f->lock);
61 f->numavail --;
62 pthread_mutex_unlock(&f->lock);
63 }
64
65 static struct node *__get_node(struct fuse *f, fino_t ino)
66 {
67 size_t hash = ino % f->ino_table_size;
68 struct node *node;
69
70 for (node = f->ino_table[hash]; node != NULL; node = node->ino_next)
71 if (node->ino == ino)
72 return node;
73
74 return NULL;
75 }
76
77 static struct node *get_node(struct fuse *f, fino_t ino)
78 {
79 struct node *node = __get_node(f, ino);
80 if (node != NULL)
81 return node;
82
83 fprintf(stderr, "fuse internal error: inode %lu not found\n", ino);
84 abort();
85 }
86
87 static void hash_ino(struct fuse *f, struct node *node)
88 {
89 size_t hash = node->ino % f->ino_table_size;
90 node->ino_next = f->ino_table[hash];
91 f->ino_table[hash] = node;
92 }
93
94 static void unhash_ino(struct fuse *f, struct node *node)
95 {
96 size_t hash = node->ino % f->ino_table_size;
97 struct node **nodep = &f->ino_table[hash];
98
99 for (; *nodep != NULL; nodep = &(*nodep)->ino_next)
100 if (*nodep == node) {
101 *nodep = node->ino_next;
102 return;
103 }
104 }
105
106 static fino_t next_ino(struct fuse *f)
107 {
108 do {
109 f->ctr++;
110 if (!f->ctr)
111 f->generation ++;
112 } while (f->ctr == 0 || __get_node(f, f->ctr) != NULL);
113 return f->ctr;
114 }
115
116 static void free_node(struct node *node)
117 {
118 free(node->name);
119 free(node);
120 }
121
122 static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name)
123 {
124 unsigned int hash = *name;
125
126 if (hash)
127 for (name += 1; *name != '\0'; name++)
128 hash = (hash << 5) - hash + *name;
129
130 return (hash + parent) % f->name_table_size;
131 }
132
133 static struct node *__lookup_node(struct fuse *f, fino_t parent,
134 const char *name)
135 {
136 size_t hash = name_hash(f, parent, name);
137 struct node *node;
138
139 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
140 if (node->parent == parent && strcmp(node->name, name) == 0)
141 return node;
142
143 return NULL;
144 }
145
146 static struct node *lookup_node(struct fuse *f, fino_t parent,
147 const char *name)
148 {
149 struct node *node;
150
151 pthread_mutex_lock(&f->lock);
152 node = __lookup_node(f, parent, name);
153 pthread_mutex_unlock(&f->lock);
154 if (node != NULL)
155 return node;
156
157 fprintf(stderr, "fuse internal error: node %lu/%s not found\n", parent,
158 name);
159 abort();
160 }
161
162 static void hash_name(struct fuse *f, struct node *node, fino_t parent,
163 const char *name)
164 {
165 size_t hash = name_hash(f, parent, name);
166 node->parent = parent;
167 node->name = strdup(name);
168 node->name_next = f->name_table[hash];
169 f->name_table[hash] = node;
170 }
171
172 static void unhash_name(struct fuse *f, struct node *node)
173 {
174 if (node->name != NULL) {
175 size_t hash = name_hash(f, node->parent, node->name);
176 struct node **nodep = &f->name_table[hash];
177
178 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
179 if (*nodep == node) {
180 *nodep = node->name_next;
181 node->name_next = NULL;
182 free(node->name);
183 node->name = NULL;
184 node->parent = 0;
185 return;
186 }
187 fprintf(stderr, "fuse internal error: unable to unhash node: %lu\n",
188 node->ino);
189 abort();
190 }
191 }
192
193 static struct node *find_node(struct fuse *f, fino_t parent, char *name,
194 struct fuse_attr *attr, int version)
195 {
196 struct node *node;
197 int mode = attr->mode & S_IFMT;
198 int rdev = 0;
199
200 if (S_ISCHR(mode) || S_ISBLK(mode))
201 rdev = attr->rdev;
202
203 pthread_mutex_lock(&f->lock);
204 node = __lookup_node(f, parent, name);
205 if (node != NULL) {
206 if (node->mode == mode && node->rdev == rdev)
207 goto out;
208
209 unhash_name(f, node);
210 }
211
212 node = (struct node *) calloc(1, sizeof(struct node));
213 node->mode = mode;
214 node->rdev = rdev;
215 node->open_count = 0;
216 node->is_hidden = 0;
217 node->ino = next_ino(f);
218 node->generation = f->generation;
219 hash_ino(f, node);
220 hash_name(f, node, parent, name);
221
222 out:
223 node->version = version;
224 pthread_mutex_unlock(&f->lock);
225 return node;
226 }
227
228 static int path_lookup(struct fuse *f, const char *path, fino_t *inop)
229 {
230 fino_t ino;
231 int err;
232 char *s;
233 char *name;
234 char *tmp = strdup(path);
235 if (!tmp)
236 return -ENOMEM;
237
238 pthread_mutex_lock(&f->lock);
239 ino = FUSE_ROOT_INO;
240 err = 0;
241 for (s = tmp; (name = strsep(&s, "/")) != NULL; ) {
242 if (name[0]) {
243 struct node *node = __lookup_node(f, ino, name);
244 if (node == NULL) {
245 err = -ENOENT;
246 break;
247 }
248 ino = node->ino;
249 }
250 }
251 pthread_mutex_unlock(&f->lock);
252 free(tmp);
253 if (!err)
254 *inop = ino;
255
256 return err;
257 }
258
259 static char *add_name(char *buf, char *s, const char *name)
260 {
261 size_t len = strlen(name);
262 s -= len;
263 if (s <= buf) {
264 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
265 return NULL;
266 }
267 strncpy(s, name, len);
268 s--;
269 *s = '/';
270
271 return s;
272 }
273
274 static char *get_path_name(struct fuse *f, fino_t ino, const char *name)
275 {
276 char buf[FUSE_MAX_PATH];
277 char *s = buf + FUSE_MAX_PATH - 1;
278 struct node *node;
279
280 *s = '\0';
281
282 if (name != NULL) {
283 s = add_name(buf, s, name);
284 if (s == NULL)
285 return NULL;
286 }
287
288 pthread_mutex_lock(&f->lock);
289 for (node = get_node(f, ino); node->ino != FUSE_ROOT_INO;
290 node = get_node(f, node->parent)) {
291 if (node->name == NULL) {
292 s = NULL;
293 break;
294 }
295
296 s = add_name(buf, s, node->name);
297 if (s == NULL)
298 break;
299 }
300 pthread_mutex_unlock(&f->lock);
301
302 if (s == NULL)
303 return NULL;
304 else if (*s == '\0')
305 return strdup("/");
306 else
307 return strdup(s);
308 }
309
310 static char *get_path(struct fuse *f, fino_t ino)
311 {
312 return get_path_name(f, ino, NULL);
313 }
314
315 static void destroy_node(struct fuse *f, fino_t ino, int version)
316 {
317 struct node *node;
318
319 pthread_mutex_lock(&f->lock);
320 node = get_node(f, ino);
321 if (node->version == version && ino != FUSE_ROOT_INO) {
322 unhash_name(f, node);
323 unhash_ino(f, node);
324 free_node(node);
325 }
326 pthread_mutex_unlock(&f->lock);
327
328 }
329
330 static void remove_node(struct fuse *f, fino_t dir, const char *name)
331 {
332 struct node *node;
333
334 pthread_mutex_lock(&f->lock);
335 node = __lookup_node(f, dir, name);
336 if (node == NULL) {
337 fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n",
338 dir, name);
339 abort();
340 }
341 unhash_name(f, node);
342 pthread_mutex_unlock(&f->lock);
343 }
344
345 static int rename_node(struct fuse *f, fino_t olddir, const char *oldname,
346 fino_t newdir, const char *newname, int hide)
347 {
348 struct node *node;
349 struct node *newnode;
350 int err = 0;
351
352 pthread_mutex_lock(&f->lock);
353 node = __lookup_node(f, olddir, oldname);
354 newnode = __lookup_node(f, newdir, newname);
355 if (node == NULL) {
356 fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n",
357 olddir, oldname);
358 abort();
359 }
360
361 if (newnode != NULL) {
362 if (hide) {
363 fprintf(stderr, "fuse: hidden file got created during hiding\n");
364 err = -1;
365 goto out;
366 }
367 unhash_name(f, newnode);
368 }
369
370 unhash_name(f, node);
371 hash_name(f, node, newdir, newname);
372 if (hide)
373 node->is_hidden = 1;
374
375 out:
376 pthread_mutex_unlock(&f->lock);
377 return err;
378 }
379
380 static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
381 {
382 attr->mode = stbuf->st_mode;
383 attr->nlink = stbuf->st_nlink;
384 attr->uid = stbuf->st_uid;
385 attr->gid = stbuf->st_gid;
386 attr->rdev = stbuf->st_rdev;
387 attr->size = stbuf->st_size;
388 attr->blocks = stbuf->st_blocks;
389 attr->atime = stbuf->st_atime;
390 attr->mtime = stbuf->st_mtime;
391 attr->ctime = stbuf->st_ctime;
392 #ifdef HAVE_STRUCT_STAT_ST_ATIM
393 attr->atimensec = stbuf->st_atim.tv_nsec;
394 attr->mtimensec = stbuf->st_mtim.tv_nsec;
395 attr->ctimensec = stbuf->st_ctim.tv_nsec;
396 #endif
397 }
398
399 static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
400 {
401 struct fuse_dirent dirent;
402 size_t reclen;
403 size_t res;
404
405 dirent.ino = (unsigned long) -1;
406 dirent.namelen = strlen(name);
407 strncpy(dirent.name, name, sizeof(dirent.name));
408 dirent.type = type;
409 reclen = FUSE_DIRENT_SIZE(&dirent);
410 res = fwrite(&dirent, reclen, 1, dh->fp);
411 if (res == 0) {
412 perror("fuse: writing directory file");
413 return -EIO;
414 }
415 return 0;
416 }
417
418 static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize,
419 int locked)
420 {
421 int res;
422
423 if ((f->flags & FUSE_DEBUG)) {
424 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
425 printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
426 out->error, strerror(-out->error), outsize);
427 fflush(stdout);
428 }
429
430 /* This needs to be done before the reply, otherwise the scheduler
431 could play tricks with us, and only let the counter be increased
432 long after the operation is done */
433 if (!locked)
434 pthread_mutex_lock(&f->lock);
435 f->numavail ++;
436 if (!locked)
437 pthread_mutex_unlock(&f->lock);
438
439 res = write(f->fd, outbuf, outsize);
440 if (res == -1) {
441 /* ENOENT means the operation was interrupted */
442 if (!f->exited && errno != ENOENT)
443 perror("fuse: writing device");
444 return -errno;
445 }
446 return 0;
447 }
448
449 static int __send_reply(struct fuse *f, struct fuse_in_header *in, int error,
450 void *arg, size_t argsize, int locked)
451 {
452 int res;
453 char *outbuf;
454 size_t outsize;
455 struct fuse_out_header *out;
456
457 if (error <= -1000 || error > 0) {
458 fprintf(stderr, "fuse: bad error value: %i\n", error);
459 error = -ERANGE;
460 }
461
462 if (error)
463 argsize = 0;
464
465 outsize = sizeof(struct fuse_out_header) + argsize;
466 outbuf = (char *) malloc(outsize);
467 out = (struct fuse_out_header *) outbuf;
468 memset(out, 0, sizeof(struct fuse_out_header));
469 out->unique = in->unique;
470 out->error = error;
471 if (argsize != 0)
472 memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
473
474 res = send_reply_raw(f, outbuf, outsize, locked);
475 free(outbuf);
476
477 return res;
478 }
479
480 static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
481 void *arg, size_t argsize)
482 {
483 return __send_reply(f, in, error, arg, argsize, 0);
484 }
485
486 static int is_open(struct fuse *f, fino_t dir, const char *name)
487 {
488 struct node *node;
489 int isopen = 0;
490 pthread_mutex_lock(&f->lock);
491 node = __lookup_node(f, dir, name);
492 if (node && node->open_count > 0)
493 isopen = 1;
494 pthread_mutex_unlock(&f->lock);
495 return isopen;
496 }
497
498 static char *hidden_name(struct fuse *f, fino_t dir, const char *oldname,
499 char *newname, size_t bufsize)
500 {
501 struct stat buf;
502 struct node *node;
503 struct node *newnode;
504 char *newpath;
505 int res;
506 int failctr = 10;
507
508 if (!f->op.getattr)
509 return NULL;
510
511 do {
512 node = lookup_node(f, dir, oldname);
513 pthread_mutex_lock(&f->lock);
514 do {
515 f->hidectr ++;
516 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
517 (unsigned int) node->ino, f->hidectr);
518 newnode = __lookup_node(f, dir, newname);
519 } while(newnode);
520 pthread_mutex_unlock(&f->lock);
521
522 newpath = get_path_name(f, dir, newname);
523 if (!newpath)
524 break;
525
526 res = f->op.getattr(newpath, &buf);
527 if (res != 0)
528 break;
529 free(newpath);
530 newpath = NULL;
531 } while(--failctr);
532
533 return newpath;
534 }
535
536 static int hide_node(struct fuse *f, const char *oldpath, fino_t dir,
537 const char *oldname)
538 {
539 char newname[64];
540 char *newpath;
541 int err = -1;
542
543 if (!f->op.rename || !f->op.unlink)
544 return -EBUSY;
545
546 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
547 if (newpath) {
548 err = f->op.rename(oldpath, newpath);
549 if (!err)
550 err = rename_node(f, dir, oldname, dir, newname, 1);
551 free(newpath);
552 }
553 if (err)
554 return -EBUSY;
555
556 return 0;
557 }
558
559 static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
560 const char *path, struct fuse_entry_out *arg)
561 {
562 int res;
563 struct stat buf;
564
565 res = f->op.getattr(path, &buf);
566 if (res == 0) {
567 struct node *node;
568
569 memset(arg, 0, sizeof(struct fuse_entry_out));
570 convert_stat(&buf, &arg->attr);
571 node = find_node(f, ino, name, &arg->attr, version);
572 arg->ino = node->ino;
573 arg->generation = node->generation;
574 arg->entry_valid = ENTRY_REVALIDATE_TIME;
575 arg->entry_valid_nsec = 0;
576 arg->attr_valid = ATTR_REVALIDATE_TIME;
577 arg->attr_valid_nsec = 0;
578 if (f->flags & FUSE_DEBUG) {
579 printf(" INO: %li\n", arg->ino);
580 fflush(stdout);
581 }
582 }
583 return res;
584 }
585
586 static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
587 {
588 int res;
589 int res2;
590 char *path;
591 struct fuse_entry_out arg;
592
593 res = -ENOENT;
594 path = get_path_name(f, in->ino, name);
595 if (path != NULL) {
596 if (f->flags & FUSE_DEBUG) {
597 printf("LOOKUP %s\n", path);
598 fflush(stdout);
599 }
600 res = -ENOSYS;
601 if (f->op.getattr)
602 res = lookup_path(f, in->ino, in->unique, name, path, &arg);
603 free(path);
604 }
605 res2 = send_reply(f, in, res, &arg, sizeof(arg));
606 if (res == 0 && res2 == -ENOENT)
607 destroy_node(f, arg.ino, in->unique);
608 }
609
610 static void do_forget(struct fuse *f, struct fuse_in_header *in,
611 struct fuse_forget_in *arg)
612 {
613 if (f->flags & FUSE_DEBUG) {
614 printf("FORGET %li/%i\n", in->ino, arg->version);
615 fflush(stdout);
616 }
617 destroy_node(f, in->ino, arg->version);
618 }
619
620 static void do_getattr(struct fuse *f, struct fuse_in_header *in)
621 {
622 int res;
623 char *path;
624 struct stat buf;
625 struct fuse_attr_out arg;
626
627 res = -ENOENT;
628 path = get_path(f, in->ino);
629 if (path != NULL) {
630 res = -ENOSYS;
631 if (f->op.getattr)
632 res = f->op.getattr(path, &buf);
633 free(path);
634 }
635
636 if (res == 0) {
637 memset(&arg, 0, sizeof(struct fuse_attr_out));
638 arg.attr_valid = ATTR_REVALIDATE_TIME;
639 arg.attr_valid_nsec = 0;
640 convert_stat(&buf, &arg.attr);
641 }
642
643 send_reply(f, in, res, &arg, sizeof(arg));
644 }
645
646 static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
647 {
648 int res;
649
650 res = -ENOSYS;
651 if (f->op.chmod)
652 res = f->op.chmod(path, attr->mode);
653
654 return res;
655 }
656
657 static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
658 int valid)
659 {
660 int res;
661 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
662 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
663
664 res = -ENOSYS;
665 if (f->op.chown)
666 res = f->op.chown(path, uid, gid);
667
668 return res;
669 }
670
671 static int do_truncate(struct fuse *f, const char *path,
672 struct fuse_attr *attr)
673 {
674 int res;
675
676 res = -ENOSYS;
677 if (f->op.truncate)
678 res = f->op.truncate(path, attr->size);
679
680 return res;
681 }
682
683 static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
684 {
685 int res;
686 struct utimbuf buf;
687 buf.actime = attr->atime;
688 buf.modtime = attr->mtime;
689 res = -ENOSYS;
690 if (f->op.utime)
691 res = f->op.utime(path, &buf);
692
693 return res;
694 }
695
696 static void do_setattr(struct fuse *f, struct fuse_in_header *in,
697 struct fuse_setattr_in *arg)
698 {
699 int res;
700 char *path;
701 int valid = arg->valid;
702 struct fuse_attr *attr = &arg->attr;
703 struct fuse_attr_out outarg;
704
705 res = -ENOENT;
706 path = get_path(f, in->ino);
707 if (path != NULL) {
708 res = -ENOSYS;
709 if (f->op.getattr) {
710 res = 0;
711 if (!res && (valid & FATTR_MODE))
712 res = do_chmod(f, path, attr);
713 if (!res && (valid & (FATTR_UID | FATTR_GID)))
714 res = do_chown(f, path, attr, valid);
715 if (!res && (valid & FATTR_SIZE))
716 res = do_truncate(f, path, attr);
717 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
718 (FATTR_ATIME | FATTR_MTIME))
719 res = do_utime(f, path, attr);
720 if (!res) {
721 struct stat buf;
722 res = f->op.getattr(path, &buf);
723 if (!res) {
724 memset(&outarg, 0, sizeof(struct fuse_attr_out));
725 outarg.attr_valid = ATTR_REVALIDATE_TIME;
726 outarg.attr_valid_nsec = 0;
727 convert_stat(&buf, &outarg.attr);
728 }
729 }
730 }
731 free(path);
732 }
733 send_reply(f, in, res, &outarg, sizeof(outarg));
734 }
735
736 static void do_readlink(struct fuse *f, struct fuse_in_header *in)
737 {
738 int res;
739 char link[PATH_MAX + 1];
740 char *path;
741
742 res = -ENOENT;
743 path = get_path(f, in->ino);
744 if (path != NULL) {
745 res = -ENOSYS;
746 if (f->op.readlink)
747 res = f->op.readlink(path, link, sizeof(link));
748 free(path);
749 }
750 link[PATH_MAX] = '\0';
751 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
752 }
753
754 static void do_getdir(struct fuse *f, struct fuse_in_header *in)
755 {
756 int res;
757 struct fuse_getdir_out arg;
758 struct fuse_dirhandle dh;
759 char *path;
760
761 dh.fuse = f;
762 dh.fp = tmpfile();
763 dh.dir = in->ino;
764 res = -ENOENT;
765 path = get_path(f, in->ino);
766 if (path != NULL) {
767 res = -ENOSYS;
768 if (f->op.getdir)
769 res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir);
770 free(path);
771 }
772 fflush(dh.fp);
773
774 memset(&arg, 0, sizeof(struct fuse_getdir_out));
775 arg.fd = fileno(dh.fp);
776 send_reply(f, in, res, &arg, sizeof(arg));
777 fclose(dh.fp);
778 }
779
780 static void do_mknod(struct fuse *f, struct fuse_in_header *in,
781 struct fuse_mknod_in *inarg)
782 {
783 int res;
784 int res2;
785 char *path;
786 char *name = PARAM(inarg);
787 struct fuse_entry_out outarg;
788
789 res = -ENOENT;
790 path = get_path_name(f, in->ino, name);
791 if (path != NULL) {
792 if (f->flags & FUSE_DEBUG) {
793 printf("MKNOD %s\n", path);
794 fflush(stdout);
795 }
796 res = -ENOSYS;
797 if (f->op.mknod && f->op.getattr) {
798 res = f->op.mknod(path, inarg->mode, inarg->rdev);
799 if (res == 0)
800 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
801 }
802 free(path);
803 }
804 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
805 if (res == 0 && res2 == -ENOENT)
806 destroy_node(f, outarg.ino, in->unique);
807 }
808
809 static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
810 struct fuse_mkdir_in *inarg)
811 {
812 int res;
813 int res2;
814 char *path;
815 char *name = PARAM(inarg);
816 struct fuse_entry_out outarg;
817
818 res = -ENOENT;
819 path = get_path_name(f, in->ino, name);
820 if (path != NULL) {
821 if (f->flags & FUSE_DEBUG) {
822 printf("MKDIR %s\n", path);
823 fflush(stdout);
824 }
825 res = -ENOSYS;
826 if (f->op.mkdir && f->op.getattr) {
827 res = f->op.mkdir(path, inarg->mode);
828 if (res == 0)
829 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
830 }
831 free(path);
832 }
833 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
834 if (res == 0 && res2 == -ENOENT)
835 destroy_node(f, outarg.ino, in->unique);
836 }
837
838 static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
839 {
840 int res;
841 char *path;
842
843 res = -ENOENT;
844 path = get_path_name(f, in->ino, name);
845 if (path != NULL) {
846 if (f->flags & FUSE_DEBUG) {
847 printf("UNLINK %s\n", path);
848 fflush(stdout);
849 }
850 res = -ENOSYS;
851 if (f->op.unlink) {
852 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->ino, name))
853 res = hide_node(f, path, in->ino, name);
854 else {
855 res = f->op.unlink(path);
856 if (res == 0)
857 remove_node(f, in->ino, name);
858 }
859 }
860 free(path);
861 }
862 send_reply(f, in, res, NULL, 0);
863 }
864
865 static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
866 {
867 int res;
868 char *path;
869
870 res = -ENOENT;
871 path = get_path_name(f, in->ino, name);
872 if (path != NULL) {
873 if (f->flags & FUSE_DEBUG) {
874 printf("RMDIR %s\n", path);
875 fflush(stdout);
876 }
877 res = -ENOSYS;
878 if (f->op.rmdir) {
879 res = f->op.rmdir(path);
880 if (res == 0)
881 remove_node(f, in->ino, name);
882 }
883 free(path);
884 }
885 send_reply(f, in, res, NULL, 0);
886 }
887
888 static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
889 char *link)
890 {
891 int res;
892 int res2;
893 char *path;
894 struct fuse_entry_out outarg;
895
896 res = -ENOENT;
897 path = get_path_name(f, in->ino, name);
898 if (path != NULL) {
899 if (f->flags & FUSE_DEBUG) {
900 printf("SYMLINK %s\n", path);
901 fflush(stdout);
902 }
903 res = -ENOSYS;
904 if (f->op.symlink && f->op.getattr) {
905 res = f->op.symlink(link, path);
906 if (res == 0)
907 res = lookup_path(f, in->ino, in->unique, name, path, &outarg);
908 }
909 free(path);
910 }
911 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
912 if (res == 0 && res2 == -ENOENT)
913 destroy_node(f, outarg.ino, in->unique);
914
915 }
916
917 static void do_rename(struct fuse *f, struct fuse_in_header *in,
918 struct fuse_rename_in *inarg)
919 {
920 int res;
921 fino_t olddir = in->ino;
922 fino_t newdir = inarg->newdir;
923 char *oldname = PARAM(inarg);
924 char *newname = oldname + strlen(oldname) + 1;
925 char *oldpath;
926 char *newpath;
927
928 res = -ENOENT;
929 oldpath = get_path_name(f, olddir, oldname);
930 if (oldpath != NULL) {
931 newpath = get_path_name(f, newdir, newname);
932 if (newpath != NULL) {
933 if (f->flags & FUSE_DEBUG) {
934 printf("RENAME %s -> %s\n", oldpath, newpath);
935 fflush(stdout);
936 }
937 res = -ENOSYS;
938 if (f->op.rename) {
939 res = 0;
940 if (!(f->flags & FUSE_HARD_REMOVE) &&
941 is_open(f, newdir, newname))
942 res = hide_node(f, newpath, newdir, newname);
943 if (res == 0) {
944 res = f->op.rename(oldpath, newpath);
945 if (res == 0)
946 rename_node(f, olddir, oldname, newdir, newname, 0);
947 }
948 }
949 free(newpath);
950 }
951 free(oldpath);
952 }
953 send_reply(f, in, res, NULL, 0);
954 }
955
956 static void do_link(struct fuse *f, struct fuse_in_header *in,
957 struct fuse_link_in *arg)
958 {
959 int res;
960 int res2;
961 char *oldpath;
962 char *newpath;
963 char *name = PARAM(arg);
964 struct fuse_entry_out outarg;
965
966 res = -ENOENT;
967 oldpath = get_path(f, in->ino);
968 if (oldpath != NULL) {
969 newpath = get_path_name(f, arg->newdir, name);
970 if (newpath != NULL) {
971 if (f->flags & FUSE_DEBUG) {
972 printf("LINK %s\n", newpath);
973 fflush(stdout);
974 }
975 res = -ENOSYS;
976 if (f->op.link && f->op.getattr) {
977 res = f->op.link(oldpath, newpath);
978 if (res == 0)
979 res = lookup_path(f, arg->newdir, in->unique, name,
980 newpath, &outarg);
981 }
982 free(newpath);
983 }
984 free(oldpath);
985 }
986 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
987 if (res == 0 && res2 == -ENOENT)
988 destroy_node(f, outarg.ino, in->unique);
989 }
990
991 static void do_open(struct fuse *f, struct fuse_in_header *in,
992 struct fuse_open_in *arg)
993 {
994 int res;
995 char *path;
996 struct fuse_open_out outarg;
997
998 res = -ENOENT;
999 path = get_path(f, in->ino);
1000 if (path != NULL) {
1001 res = -ENOSYS;
1002 if (f->op.open)
1003 res = f->op.open(path, arg->flags);
1004 }
1005 if (res == 0) {
1006 int res2;
1007
1008 /* If the request is interrupted the lock must be held until
1009 the cancellation is finished. Otherwise there could be
1010 races with rename/unlink, against which the kernel can't
1011 protect */
1012 pthread_mutex_lock(&f->lock);
1013 f->fh_ctr ++;
1014 outarg.fh = f->fh_ctr;
1015 if (f->flags & FUSE_DEBUG) {
1016 printf("OPEN[%u] flags: 0x%x\n", outarg.fh, arg->flags);
1017 fflush(stdout);
1018 }
1019
1020 res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1);
1021 if(res2 == -ENOENT) {
1022 /* The open syscall was interrupted, so it must be cancelled */
1023 if(f->op.release)
1024 f->op.release(path, arg->flags);
1025 } else
1026 get_node(f, in->ino)->open_count ++;
1027 pthread_mutex_unlock(&f->lock);
1028
1029 } else
1030 send_reply(f, in, res, NULL, 0);
1031
1032 if (path)
1033 free(path);
1034 }
1035
1036 static void do_flush(struct fuse *f, struct fuse_in_header *in,
1037 struct fuse_flush_in *arg)
1038 {
1039 char *path;
1040 int res;
1041
1042 res = -ENOENT;
1043 path = get_path(f, in->ino);
1044 if (path != NULL) {
1045 if (f->flags & FUSE_DEBUG) {
1046 printf("FLUSH[%u]\n", arg->fh);
1047 fflush(stdout);
1048 }
1049 res = -ENOSYS;
1050 if (f->op.flush)
1051 res = f->op.flush(path);
1052 free(path);
1053 }
1054 send_reply(f, in, res, NULL, 0);
1055 }
1056
1057 static void do_release(struct fuse *f, struct fuse_in_header *in,
1058 struct fuse_release_in *arg)
1059 {
1060 struct node *node;
1061 char *path;
1062
1063 pthread_mutex_lock(&f->lock);
1064 node = get_node(f, in->ino);
1065 --node->open_count;
1066 pthread_mutex_unlock(&f->lock);
1067
1068 path = get_path(f, in->ino);
1069 if (path != NULL) {
1070 if (f->flags & FUSE_DEBUG) {
1071 printf("RELEASE[%u]\n", arg->fh);
1072 fflush(stdout);
1073 }
1074 if (f->op.release)
1075 f->op.release(path, arg->flags);
1076
1077 if(node->is_hidden && node->open_count == 0)
1078 /* can now clean up this hidden file */
1079 f->op.unlink(path);
1080
1081 free(path);
1082 }
1083 send_reply(f, in, 0, NULL, 0);
1084 }
1085
1086 static void do_read(struct fuse *f, struct fuse_in_header *in,
1087 struct fuse_read_in *arg)
1088 {
1089 int res;
1090 char *path;
1091 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
1092 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1093 char *buf = outbuf + sizeof(struct fuse_out_header);
1094 size_t size;
1095 size_t outsize;
1096
1097 res = -ENOENT;
1098 path = get_path(f, in->ino);
1099 if (path != NULL) {
1100 if (f->flags & FUSE_DEBUG) {
1101 printf("READ[%u] %u bytes from %llu\n", arg->fh, arg->size,
1102 arg->offset);
1103 fflush(stdout);
1104 }
1105
1106 res = -ENOSYS;
1107 if (f->op.read)
1108 res = f->op.read(path, buf, arg->size, arg->offset);
1109 free(path);
1110 }
1111
1112 size = 0;
1113 if (res >= 0) {
1114 size = res;
1115 res = 0;
1116 if (f->flags & FUSE_DEBUG) {
1117 printf(" READ[%u] %u bytes\n", arg->fh, size);
1118 fflush(stdout);
1119 }
1120 }
1121 memset(out, 0, sizeof(struct fuse_out_header));
1122 out->unique = in->unique;
1123 out->error = res;
1124 outsize = sizeof(struct fuse_out_header) + size;
1125
1126 send_reply_raw(f, outbuf, outsize, 0);
1127 free(outbuf);
1128 }
1129
1130 static void do_write(struct fuse *f, struct fuse_in_header *in,
1131 struct fuse_write_in *arg)
1132 {
1133 int res;
1134 char *path;
1135 struct fuse_write_out outarg;
1136
1137 res = -ENOENT;
1138 path = get_path(f, in->ino);
1139 if (path != NULL) {
1140 if (f->flags & FUSE_DEBUG) {
1141 printf("WRITE%s[%u] %u bytes to %llu\n",
1142 arg->writepage ? "PAGE" : "", arg->fh, arg->size,
1143 arg->offset);
1144 fflush(stdout);
1145 }
1146
1147 res = -ENOSYS;
1148 if (f->op.write)
1149 res = f->op.write(path, PARAM(arg), arg->size, arg->offset);
1150 free(path);
1151 }
1152
1153 if (res >= 0) {
1154 outarg.size = res;
1155 res = 0;
1156 }
1157
1158 send_reply(f, in, res, &outarg, sizeof(outarg));
1159 }
1160
1161 static int default_statfs(struct statfs *buf)
1162 {
1163 buf->f_namelen = 255;
1164 buf->f_bsize = 512;
1165 return 0;
1166 }
1167
1168 static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
1169 {
1170 kstatfs->bsize = statfs->f_bsize;
1171 kstatfs->blocks = statfs->f_blocks;
1172 kstatfs->bfree = statfs->f_bfree;
1173 kstatfs->bavail = statfs->f_bavail;
1174 kstatfs->files = statfs->f_files;
1175 kstatfs->ffree = statfs->f_ffree;
1176 kstatfs->namelen = statfs->f_namelen;
1177 }
1178
1179 static void do_statfs(struct fuse *f, struct fuse_in_header *in)
1180 {
1181 int res;
1182 struct fuse_statfs_out arg;
1183 struct statfs buf;
1184
1185 memset(&buf, 0, sizeof(struct statfs));
1186 if (f->op.statfs)
1187 res = f->op.statfs("/", &buf);
1188 else
1189 res = default_statfs(&buf);
1190
1191 if (res == 0)
1192 convert_statfs(&buf, &arg.st);
1193
1194 send_reply(f, in, res, &arg, sizeof(arg));
1195 }
1196
1197 static void do_fsync(struct fuse *f, struct fuse_in_header *in,
1198 struct fuse_fsync_in *inarg)
1199 {
1200 int res;
1201 char *path;
1202
1203 res = -ENOENT;
1204 path = get_path(f, in->ino);
1205 if (path != NULL) {
1206 if (f->flags & FUSE_DEBUG) {
1207 printf("FSYNC[%u]\n", inarg->fh);
1208 fflush(stdout);
1209 }
1210 res = -ENOSYS;
1211 if (f->op.fsync)
1212 res = f->op.fsync(path, inarg->datasync);
1213 free(path);
1214 }
1215 send_reply(f, in, res, NULL, 0);
1216 }
1217
1218 static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
1219 struct fuse_setxattr_in *arg)
1220 {
1221 int res;
1222 char *path;
1223 char *name = PARAM(arg);
1224 unsigned char *value = name + strlen(name) + 1;
1225
1226 res = -ENOENT;
1227 path = get_path(f, in->ino);
1228 if (path != NULL) {
1229 res = -ENOSYS;
1230 if (f->op.setxattr)
1231 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
1232 free(path);
1233 }
1234 send_reply(f, in, res, NULL, 0);
1235 }
1236
1237 static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
1238 const char *name, char *value, size_t size)
1239 {
1240 int res;
1241 char *path;
1242
1243 res = -ENOENT;
1244 path = get_path(f, in->ino);
1245 if (path != NULL) {
1246 res = -ENOSYS;
1247 if (f->op.getxattr)
1248 res = f->op.getxattr(path, name, value, size);
1249 free(path);
1250 }
1251 return res;
1252 }
1253
1254 static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
1255 const char *name, size_t size)
1256 {
1257 int res;
1258 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1259 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1260 char *value = outbuf + sizeof(struct fuse_out_header);
1261
1262 res = common_getxattr(f, in, name, value, size);
1263 size = 0;
1264 if (res > 0) {
1265 size = res;
1266 res = 0;
1267 }
1268 memset(out, 0, sizeof(struct fuse_out_header));
1269 out->unique = in->unique;
1270 out->error = res;
1271
1272 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1273 free(outbuf);
1274 }
1275
1276 static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
1277 const char *name)
1278 {
1279 int res;
1280 struct fuse_getxattr_out arg;
1281
1282 res = common_getxattr(f, in, name, NULL, 0);
1283 if (res >= 0) {
1284 arg.size = res;
1285 res = 0;
1286 }
1287 send_reply(f, in, res, &arg, sizeof(arg));
1288 }
1289
1290 static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
1291 struct fuse_getxattr_in *arg)
1292 {
1293 char *name = PARAM(arg);
1294
1295 if (arg->size)
1296 do_getxattr_read(f, in, name, arg->size);
1297 else
1298 do_getxattr_size(f, in, name);
1299 }
1300
1301 static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
1302 char *list, size_t size)
1303 {
1304 int res;
1305 char *path;
1306
1307 res = -ENOENT;
1308 path = get_path(f, in->ino);
1309 if (path != NULL) {
1310 res = -ENOSYS;
1311 if (f->op.listxattr)
1312 res = f->op.listxattr(path, list, size);
1313 free(path);
1314 }
1315 return res;
1316 }
1317
1318 static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
1319 size_t size)
1320 {
1321 int res;
1322 char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
1323 struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
1324 char *list = outbuf + sizeof(struct fuse_out_header);
1325
1326 res = common_listxattr(f, in, list, size);
1327 size = 0;
1328 if (res > 0) {
1329 size = res;
1330 res = 0;
1331 }
1332 memset(out, 0, sizeof(struct fuse_out_header));
1333 out->unique = in->unique;
1334 out->error = res;
1335
1336 send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
1337 free(outbuf);
1338 }
1339
1340 static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
1341 {
1342 int res;
1343 struct fuse_getxattr_out arg;
1344
1345 res = common_listxattr(f, in, NULL, 0);
1346 if (res >= 0) {
1347 arg.size = res;
1348 res = 0;
1349 }
1350 send_reply(f, in, res, &arg, sizeof(arg));
1351 }
1352
1353 static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
1354 struct fuse_getxattr_in *arg)
1355 {
1356 if (arg->size)
1357 do_listxattr_read(f, in, arg->size);
1358 else
1359 do_listxattr_size(f, in);
1360 }
1361
1362 static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
1363 char *name)
1364 {
1365 int res;
1366 char *path;
1367
1368 res = -ENOENT;
1369 path = get_path(f, in->ino);
1370 if (path != NULL) {
1371 res = -ENOSYS;
1372 if (f->op.removexattr)
1373 res = f->op.removexattr(path, name);
1374 free(path);
1375 }
1376 send_reply(f, in, res, NULL, 0);
1377 }
1378
1379
1380 static void free_cmd(struct fuse_cmd *cmd)
1381 {
1382 free(cmd->buf);
1383 free(cmd);
1384 }
1385
1386 void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
1387 {
1388 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1389 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
1390 size_t argsize;
1391 struct fuse_context *ctx = fuse_get_context(f);
1392
1393 dec_avail(f);
1394
1395 if ((f->flags & FUSE_DEBUG)) {
1396 printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
1397 in->unique, opname(in->opcode), in->opcode, in->ino,
1398 cmd->buflen);
1399 fflush(stdout);
1400 }
1401
1402 ctx->uid = in->uid;
1403 ctx->gid = in->gid;
1404
1405 argsize = cmd->buflen - sizeof(struct fuse_in_header);
1406
1407 switch (in->opcode) {
1408 case FUSE_LOOKUP:
1409 do_lookup(f, in, (char *) inarg);
1410 break;
1411
1412 case FUSE_GETATTR:
1413 do_getattr(f, in);
1414 break;
1415
1416 case FUSE_SETATTR:
1417 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1418 break;
1419
1420 case FUSE_READLINK:
1421 do_readlink(f, in);
1422 break;
1423
1424 case FUSE_GETDIR:
1425 do_getdir(f, in);
1426 break;
1427
1428 case FUSE_MKNOD:
1429 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1430 break;
1431
1432 case FUSE_MKDIR:
1433 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1434 break;
1435
1436 case FUSE_UNLINK:
1437 do_unlink(f, in, (char *) inarg);
1438 break;
1439
1440 case FUSE_RMDIR:
1441 do_rmdir(f, in, (char *) inarg);
1442 break;
1443
1444 case FUSE_SYMLINK:
1445 do_symlink(f, in, (char *) inarg,
1446 ((char *) inarg) + strlen((char *) inarg) + 1);
1447 break;
1448
1449 case FUSE_RENAME:
1450 do_rename(f, in, (struct fuse_rename_in *) inarg);
1451 break;
1452
1453 case FUSE_LINK:
1454 do_link(f, in, (struct fuse_link_in *) inarg);
1455 break;
1456
1457 case FUSE_OPEN:
1458 do_open(f, in, (struct fuse_open_in *) inarg);
1459 break;
1460
1461 case FUSE_FLUSH:
1462 do_flush(f, in, (struct fuse_flush_in *) inarg);
1463 break;
1464
1465 case FUSE_RELEASE:
1466 do_release(f, in, (struct fuse_release_in *) inarg);
1467 break;
1468
1469 case FUSE_READ:
1470 do_read(f, in, (struct fuse_read_in *) inarg);
1471 break;
1472
1473 case FUSE_WRITE:
1474 do_write(f, in, (struct fuse_write_in *) inarg);
1475 break;
1476
1477 case FUSE_STATFS:
1478 do_statfs(f, in);
1479 break;
1480
1481 case FUSE_FSYNC:
1482 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1483 break;
1484
1485 case FUSE_SETXATTR:
1486 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1487 break;
1488
1489 case FUSE_GETXATTR:
1490 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
1491 break;
1492
1493 case FUSE_LISTXATTR:
1494 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
1495 break;
1496
1497 case FUSE_REMOVEXATTR:
1498 do_removexattr(f, in, (char *) inarg);
1499 break;
1500
1501 default:
1502 send_reply(f, in, -ENOSYS, NULL, 0);
1503 }
1504
1505 free_cmd(cmd);
1506 }
1507
1508 int __fuse_exited(struct fuse* f)
1509 {
1510 return f->exited;
1511 }
1512
1513 struct fuse_cmd *__fuse_read_cmd(struct fuse *f)
1514 {
1515 ssize_t res;
1516 struct fuse_cmd *cmd;
1517 struct fuse_in_header *in;
1518 void *inarg;
1519
1520 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1521 cmd->buf = (char *) malloc(FUSE_MAX_IN);
1522 in = (struct fuse_in_header *) cmd->buf;
1523 inarg = cmd->buf + sizeof(struct fuse_in_header);
1524
1525 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1526 if (res == -1) {
1527 free_cmd(cmd);
1528 if (__fuse_exited(f) || errno == EINTR)
1529 return NULL;
1530
1531 /* ENODEV means we got unmounted, so we silenty return failure */
1532 if (errno != ENODEV) {
1533 /* BAD... This will happen again */
1534 perror("fuse: reading device");
1535 }
1536
1537 fuse_exit(f);
1538 return NULL;
1539 }
1540 if ((size_t) res < sizeof(struct fuse_in_header)) {
1541 free_cmd(cmd);
1542 /* Cannot happen */
1543 fprintf(stderr, "short read on fuse device\n");
1544 fuse_exit(f);
1545 return NULL;
1546 }
1547 cmd->buflen = res;
1548
1549 /* Forget is special, it can be done without messing with threads. */
1550 if (in->opcode == FUSE_FORGET) {
1551 do_forget(f, in, (struct fuse_forget_in *) inarg);
1552 free_cmd(cmd);
1553 return NULL;
1554 }
1555
1556 return cmd;
1557 }
1558
1559 void fuse_loop(struct fuse *f)
1560 {
1561 if (f == NULL)
1562 return;
1563
1564 while (1) {
1565 struct fuse_cmd *cmd;
1566
1567 if (__fuse_exited(f))
1568 return;
1569
1570 cmd = __fuse_read_cmd(f);
1571 if (cmd == NULL)
1572 continue;
1573
1574 __fuse_process_cmd(f, cmd);
1575 }
1576 }
1577
1578 int fuse_invalidate(struct fuse *f, const char *path)
1579 {
1580 int res;
1581 int err;
1582 fino_t ino;
1583 struct fuse_user_header h;
1584
1585 err = path_lookup(f, path, &ino);
1586 if (err) {
1587 if (err == -ENOENT)
1588 return 0;
1589 else
1590 return err;
1591 }
1592
1593 memset(&h, 0, sizeof(struct fuse_user_header));
1594 h.opcode = FUSE_INVALIDATE;
1595 h.ino = ino;
1596
1597 if ((f->flags & FUSE_DEBUG)) {
1598 printf("INVALIDATE ino: %li\n", ino);
1599 fflush(stdout);
1600 }
1601
1602 res = write(f->fd, &h, sizeof(struct fuse_user_header));
1603 if (res == -1) {
1604 if (errno != ENOENT) {
1605 perror("fuse: writing device");
1606 return -errno;
1607 }
1608 }
1609 return 0;
1610 }
1611
1612 void fuse_exit(struct fuse *f)
1613 {
1614 f->exited = 1;
1615 }
1616
1617 struct fuse_context *fuse_get_context(struct fuse *f)
1618 {
1619 if (f->getcontext)
1620 return f->getcontext(f);
1621 else
1622 return &f->context;
1623 }
1624
1625 static int check_version(struct fuse *f)
1626 {
1627 int res;
1628 FILE *vf = fopen(FUSE_VERSION_FILE, "r");
1629 if (vf == NULL) {
1630 fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
1631 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1632 return -1;
1633 }
1634 res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
1635 fclose(vf);
1636 if (res != 2) {
1637 fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE);
1638 return -1;
1639 }
1640 if (f->majorver != FUSE_KERNEL_VERSION) {
1641 fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
1642 FUSE_KERNEL_VERSION);
1643 return -1;
1644 }
1645 if (f->minorver < FUSE_KERNEL_MINOR_VERSION) {
1646 fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i",
1647 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1648 return -1;
1649 }
1650
1651 return 0;
1652 }
1653
1654
1655 int fuse_is_lib_option(const char *opt)
1656 {
1657 if (strcmp(opt, "debug") == 0 ||
1658 strcmp(opt, "hard_remove") == 0)
1659 return 1;
1660 else
1661 return 0;
1662 }
1663
1664 static void parse_lib_opts(struct fuse *f, const char *opts)
1665 {
1666 if (opts) {
1667 char *xopts = strdup(opts);
1668 char *s = xopts;
1669 char *opt;
1670
1671 while((opt = strsep(&s, ","))) {
1672 if (strcmp(opt, "debug") == 0)
1673 f->flags |= FUSE_DEBUG;
1674 else if (strcmp(opt, "hard_remove") == 0)
1675 f->flags |= FUSE_HARD_REMOVE;
1676 else
1677 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1678 }
1679 free(xopts);
1680 }
1681 }
1682
1683 struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
1684 {
1685 struct fuse *f;
1686 struct node *root;
1687
1688 f = (struct fuse *) calloc(1, sizeof(struct fuse));
1689
1690 if (check_version(f) == -1) {
1691 free(f);
1692 return NULL;
1693 }
1694
1695 parse_lib_opts(f, opts);
1696 f->fd = fd;
1697 f->ctr = 0;
1698 f->generation = 0;
1699 /* FIXME: Dynamic hash table */
1700 f->name_table_size = 14057;
1701 f->name_table = (struct node **)
1702 calloc(1, sizeof(struct node *) * f->name_table_size);
1703 f->ino_table_size = 14057;
1704 f->ino_table = (struct node **)
1705 calloc(1, sizeof(struct node *) * f->ino_table_size);
1706 pthread_mutex_init(&f->lock, NULL);
1707 f->numworker = 0;
1708 f->numavail = 0;
1709 f->op = *op;
1710 f->getcontext = NULL;
1711 f->context.uid = 0;
1712 f->context.gid = 0;
1713 f->exited = 0;
1714
1715 root = (struct node *) calloc(1, sizeof(struct node));
1716 root->mode = 0;
1717 root->rdev = 0;
1718 root->name = strdup("/");
1719 root->parent = 0;
1720 root->ino = FUSE_ROOT_INO;
1721 root->generation = 0;
1722 hash_ino(f, root);
1723
1724 return f;
1725 }
1726
1727 void fuse_destroy(struct fuse *f)
1728 {
1729 size_t i;
1730 for (i = 0; i < f->ino_table_size; i++) {
1731 struct node *node;
1732
1733 for (node = f->ino_table[i]; node != NULL; node = node->ino_next) {
1734 if (node->is_hidden) {
1735 char *path = get_path(f, node->ino);
1736 if (path)
1737 f->op.unlink(path);
1738 }
1739 }
1740 }
1741 for (i = 0; i < f->ino_table_size; i++) {
1742 struct node *node;
1743 struct node *next;
1744
1745 for (node = f->ino_table[i]; node != NULL; node = next) {
1746 next = node->ino_next;
1747 free_node(node);
1748 }
1749 }
1750 free(f->ino_table);
1751 free(f->name_table);
1752 pthread_mutex_destroy(&f->lock);
1753 free(f);
1754 }

  ViewVC Help
Powered by ViewVC 1.1.26