1 /*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB
7 */
8
9 #ifdef __SOLARIS__
10 /* For pthread_rwlock_t */
11 #define _GNU_SOURCE
12 #endif /* __SOLARIS__ */
13
14 #include "config.h"
15 #include "fuse_i.h"
16 #include "fuse_lowlevel.h"
17 #include "fuse_opt.h"
18 #include "fuse_misc.h"
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stddef.h>
24 #include <unistd.h>
25 #include <time.h>
26 #include <fcntl.h>
27 #include <limits.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <dlfcn.h>
31 #include <assert.h>
32 #include <sys/param.h>
33 #include <sys/uio.h>
34 #include <sys/time.h>
35
36 #ifdef __SOLARIS__
37 #define FUSE_MAX_PATH 4096
38 #endif /* __SOLARIS__ */
39
40 #define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
41
42 #define FUSE_UNKNOWN_INO 0xffffffff
43 #define OFFSET_MAX 0x7fffffffffffffffLL
44
45 struct fuse_config {
46 unsigned int uid;
47 unsigned int gid;
48 unsigned int umask;
49 double entry_timeout;
50 double negative_timeout;
51 double attr_timeout;
52 double ac_attr_timeout;
53 int ac_attr_timeout_set;
54 int debug;
55 int hard_remove;
56 int use_ino;
57 int readdir_ino;
58 int set_mode;
59 int set_uid;
60 int set_gid;
61 int direct_io;
62 int kernel_cache;
63 int intr;
64 int intr_signal;
65 int help;
66 #ifdef __SOLARIS__
67 int auto_cache;
68 char *modules;
69 #endif /* __SOLARIS__ */
70 };
71
72 struct fuse_fs {
73 struct fuse_operations op;
74 void *user_data;
75 #ifdef __SOLARIS__
76 struct fuse_module *m;
77 #endif /* __SOLARIS__ */
78 };
79
80 #ifdef __SOLARIS__
81 struct fusemod_so {
82 void *handle;
83 int ctr;
84 };
85 #endif /* __SOLARIS__ */
86
87 struct fuse {
88 struct fuse_session *se;
89 struct node **name_table;
90 size_t name_table_size;
91 struct node **id_table;
92 size_t id_table_size;
93 fuse_ino_t ctr;
94 unsigned int generation;
95 unsigned int hidectr;
96 pthread_mutex_t lock;
97 pthread_rwlock_t tree_lock;
98 struct fuse_config conf;
99 int intr_installed;
100 struct fuse_fs *fs;
101 };
102
103 struct lock {
104 int type;
105 off_t start;
106 off_t end;
107 pid_t pid;
108 uint64_t owner;
109 struct lock *next;
110 };
111
112 struct node {
113 struct node *name_next;
114 struct node *id_next;
115 fuse_ino_t nodeid;
116 unsigned int generation;
117 int refctr;
118 struct node *parent;
119 char *name;
120 uint64_t nlookup;
121 int open_count;
122 int is_hidden;
123 #ifdef __SOLARIS__
124 struct timespec stat_updated;
125 struct timespec mtime;
126 off_t size;
127 int cache_valid;
128 #endif /* __SOLARIS__ */
129 struct lock *locks;
130 };
131
132 struct fuse_dh {
133 pthread_mutex_t lock;
134 struct fuse *fuse;
135 fuse_req_t req;
136 char *contents;
137 unsigned len;
138 unsigned size;
139 unsigned needlen;
140 int filled;
141 uint64_t fh;
142 int error;
143 fuse_ino_t nodeid;
144 };
145
146 struct fuse_context_i {
147 struct fuse_context ctx;
148 fuse_req_t req;
149 };
150
151 static pthread_key_t fuse_context_key;
152 static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
153 static int fuse_context_ref;
154
155 #ifdef __SOLARIS__
156
157 static struct fusemod_so *fuse_current_so;
158 static struct fuse_module *fuse_modules;
159
fuse_load_so_name(const char * soname)160 static int fuse_load_so_name(const char *soname)
161 {
162 struct fusemod_so *so;
163
164 so = calloc(1, sizeof(struct fusemod_so));
165 if (!so) {
166 fprintf(stderr, "fuse: memory allocation failed\n");
167 return -1;
168 }
169
170 fuse_current_so = so;
171 so->handle = dlopen(soname, RTLD_NOW);
172 fuse_current_so = NULL;
173 if (!so->handle) {
174 fprintf(stderr, "fuse: %s\n", dlerror());
175 goto err;
176 }
177 if (!so->ctr) {
178 fprintf(stderr, "fuse: %s did not register any modules", soname);
179 goto err;
180 }
181 return 0;
182
183 err:
184 if (so->handle)
185 dlclose(so->handle);
186 free(so);
187 return -1;
188 }
189
fuse_load_so_module(const char * module)190 static int fuse_load_so_module(const char *module)
191 {
192 int res;
193 char *soname = malloc(strlen(module) + 64);
194 if (!soname) {
195 fprintf(stderr, "fuse: memory allocation failed\n");
196 return -1;
197 }
198 sprintf(soname, "libfusemod_%s.so", module);
199 res = fuse_load_so_name(soname);
200 free(soname);
201 return res;
202 }
203
fuse_find_module(const char * module)204 static struct fuse_module *fuse_find_module(const char *module)
205 {
206 struct fuse_module *m;
207 for (m = fuse_modules; m; m = m->next) {
208 if (strcmp(module, m->name) == 0) {
209 m->ctr++;
210 break;
211 }
212 }
213 return m;
214 }
215
fuse_get_module(const char * module)216 static struct fuse_module *fuse_get_module(const char *module)
217 {
218 struct fuse_module *m;
219
220 pthread_mutex_lock(&fuse_context_lock);
221 m = fuse_find_module(module);
222 if (!m) {
223 int err = fuse_load_so_module(module);
224 if (!err)
225 m = fuse_find_module(module);
226 }
227 pthread_mutex_unlock(&fuse_context_lock);
228 return m;
229 }
230
fuse_put_module(struct fuse_module * m)231 static void fuse_put_module(struct fuse_module *m)
232 {
233 pthread_mutex_lock(&fuse_context_lock);
234 assert(m->ctr > 0);
235 m->ctr--;
236 if (!m->ctr && m->so) {
237 struct fusemod_so *so = m->so;
238 assert(so->ctr > 0);
239 so->ctr--;
240 if (!so->ctr) {
241 struct fuse_module **mp;
242 for (mp = &fuse_modules; *mp;) {
243 if ((*mp)->so == so)
244 *mp = (*mp)->next;
245 else
246 mp = &(*mp)->next;
247 }
248 dlclose(so->handle);
249 free(so);
250 }
251 }
252 pthread_mutex_unlock(&fuse_context_lock);
253 }
254 #endif /* __SOLARIS__ */
255
get_node_nocheck(struct fuse * f,fuse_ino_t nodeid)256 static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
257 {
258 size_t hash = nodeid % f->id_table_size;
259 struct node *node;
260
261 for (node = f->id_table[hash]; node != NULL; node = node->id_next)
262 if (node->nodeid == nodeid)
263 return node;
264
265 return NULL;
266 }
267
get_node(struct fuse * f,fuse_ino_t nodeid)268 static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
269 {
270 struct node *node = get_node_nocheck(f, nodeid);
271 if (!node) {
272 fprintf(stderr, "fuse internal error: node %llu not found\n",
273 (unsigned long long) nodeid);
274 abort();
275 }
276 return node;
277 }
278
free_node(struct node * node)279 static void free_node(struct node *node)
280 {
281 free(node->name);
282 free(node);
283 }
284
unhash_id(struct fuse * f,struct node * node)285 static void unhash_id(struct fuse *f, struct node *node)
286 {
287 size_t hash = node->nodeid % f->id_table_size;
288 struct node **nodep = &f->id_table[hash];
289
290 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
291 if (*nodep == node) {
292 *nodep = node->id_next;
293 return;
294 }
295 }
296
hash_id(struct fuse * f,struct node * node)297 static void hash_id(struct fuse *f, struct node *node)
298 {
299 size_t hash = node->nodeid % f->id_table_size;
300 node->id_next = f->id_table[hash];
301 f->id_table[hash] = node;
302 }
303
name_hash(struct fuse * f,fuse_ino_t parent,const char * name)304 static unsigned int name_hash(struct fuse *f, fuse_ino_t parent,
305 const char *name)
306 {
307 unsigned int hash = *name;
308
309 if (hash)
310 for (name += 1; *name != '\0'; name++)
311 hash = (hash << 5) - hash + *name;
312
313 return (hash + parent) % f->name_table_size;
314 }
315
316 static void unref_node(struct fuse *f, struct node *node);
317
unhash_name(struct fuse * f,struct node * node)318 static void unhash_name(struct fuse *f, struct node *node)
319 {
320 if (node->name) {
321 size_t hash = name_hash(f, node->parent->nodeid, node->name);
322 struct node **nodep = &f->name_table[hash];
323
324 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
325 if (*nodep == node) {
326 *nodep = node->name_next;
327 node->name_next = NULL;
328 unref_node(f, node->parent);
329 free(node->name);
330 node->name = NULL;
331 node->parent = NULL;
332 return;
333 }
334 fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n",
335 (unsigned long long) node->nodeid);
336 abort();
337 }
338 }
339
hash_name(struct fuse * f,struct node * node,fuse_ino_t parentid,const char * name)340 static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid,
341 const char *name)
342 {
343 size_t hash = name_hash(f, parentid, name);
344 struct node *parent = get_node(f, parentid);
345 node->name = strdup(name);
346 if (node->name == NULL)
347 return -1;
348
349 parent->refctr ++;
350 node->parent = parent;
351 node->name_next = f->name_table[hash];
352 f->name_table[hash] = node;
353 return 0;
354 }
355
delete_node(struct fuse * f,struct node * node)356 static void delete_node(struct fuse *f, struct node *node)
357 {
358 if (f->conf.debug)
359 fprintf(stderr, "delete: %llu\n", (unsigned long long) node->nodeid);
360
361 assert(!node->name);
362 unhash_id(f, node);
363 free_node(node);
364 }
365
unref_node(struct fuse * f,struct node * node)366 static void unref_node(struct fuse *f, struct node *node)
367 {
368 assert(node->refctr > 0);
369 node->refctr --;
370 if (!node->refctr)
371 delete_node(f, node);
372 }
373
next_id(struct fuse * f)374 static fuse_ino_t next_id(struct fuse *f)
375 {
376 do {
377 f->ctr = (f->ctr + 1) & 0xffffffff;
378 if (!f->ctr)
379 f->generation ++;
380 } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO ||
381 get_node_nocheck(f, f->ctr) != NULL);
382 return f->ctr;
383 }
384
lookup_node(struct fuse * f,fuse_ino_t parent,const char * name)385 static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
386 const char *name)
387 {
388 size_t hash = name_hash(f, parent, name);
389 struct node *node;
390
391 for (node = f->name_table[hash]; node != NULL; node = node->name_next)
392 if (node->parent->nodeid == parent && strcmp(node->name, name) == 0)
393 return node;
394
395 return NULL;
396 }
397
find_node(struct fuse * f,fuse_ino_t parent,const char * name)398 static struct node *find_node(struct fuse *f, fuse_ino_t parent,
399 const char *name)
400 {
401 struct node *node;
402
403 pthread_mutex_lock(&f->lock);
404 node = lookup_node(f, parent, name);
405 if (node == NULL) {
406 node = (struct node *) calloc(1, sizeof(struct node));
407 if (node == NULL)
408 goto out_err;
409
410 node->refctr = 1;
411 node->nodeid = next_id(f);
412 node->open_count = 0;
413 node->is_hidden = 0;
414 node->generation = f->generation;
415 if (hash_name(f, node, parent, name) == -1) {
416 free(node);
417 node = NULL;
418 goto out_err;
419 }
420 hash_id(f, node);
421 }
422 node->nlookup ++;
423 out_err:
424 pthread_mutex_unlock(&f->lock);
425 return node;
426 }
427
428 #ifndef __SOLARIS__
add_name(char ** buf,unsigned * bufsize,char * s,const char * name)429 static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name)
430 #else /* __SOLARIS__ */
431 static char *add_name(char *buf, char *s, const char *name)
432 #endif /* __SOLARIS__ */
433 {
434 size_t len = strlen(name);
435
436 #ifndef __SOLARIS__
437 if (s - len <= *buf) {
438 unsigned pathlen = *bufsize - (s - *buf);
439 unsigned newbufsize = *bufsize;
440 char *newbuf;
441
442 while (newbufsize < pathlen + len + 1) {
443 if (newbufsize >= 0x80000000)
444 newbufsize = 0xffffffff;
445 else
446 newbufsize *= 2;
447 }
448
449 newbuf = realloc(*buf, newbufsize);
450 if (newbuf == NULL)
451 return NULL;
452
453 *buf = newbuf;
454 s = newbuf + newbufsize - pathlen;
455 memmove(s, newbuf + *bufsize - pathlen, pathlen);
456 *bufsize = newbufsize;
457 }
458 s -= len;
459 #else /* ! __SOLARIS__ */
460 s -= len;
461 if (s <= buf) {
462 fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
463 return NULL;
464 }
465 #endif /* __SOLARIS__ */
466 memcpy(s, name, len);
467 s--;
468 *s = '/';
469
470 return s;
471 }
472
get_path_name(struct fuse * f,fuse_ino_t nodeid,const char * name)473 static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
474 {
475 #ifdef __SOLARIS__
476 char buf[FUSE_MAX_PATH];
477 char *s = buf + FUSE_MAX_PATH - 1;
478 struct node *node;
479
480 *s = '\0';
481
482 if (name != NULL) {
483 s = add_name(buf, s, name);
484 if (s == NULL)
485 return NULL;
486 }
487
488 pthread_mutex_lock(&f->lock);
489 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
490 node = node->parent) {
491 if (node->name == NULL) {
492 s = NULL;
493 break;
494 }
495
496 s = add_name(buf, s, node->name);
497 if (s == NULL)
498 break;
499 }
500 pthread_mutex_unlock(&f->lock);
501
502 if (node == NULL || s == NULL)
503 return NULL;
504 else if (*s == '\0')
505 return strdup("/");
506 else
507 return strdup(s);
508
509 #else /* __SOLARIS__ */
510
511 unsigned bufsize = 256;
512 char *buf;
513 char *s;
514 struct node *node;
515
516 buf = malloc(bufsize);
517 if (buf == NULL)
518 return NULL;
519
520 s = buf + bufsize - 1;
521 *s = '\0';
522
523 if (name != NULL) {
524 s = add_name(&buf, &bufsize, s, name);
525 if (s == NULL)
526 goto out_free;
527 }
528
529 pthread_mutex_lock(&f->lock);
530 for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
531 node = node->parent) {
532 if (node->name == NULL) {
533 s = NULL;
534 break;
535 }
536
537 s = add_name(&buf, &bufsize, s, node->name);
538 if (s == NULL)
539 break;
540 }
541 pthread_mutex_unlock(&f->lock);
542
543 if (node == NULL || s == NULL)
544 goto out_free;
545
546 if (s[0])
547 memmove(buf, s, bufsize - (s - buf));
548 else
549 strcpy(buf, "/");
550 return buf;
551
552 out_free:
553 free(buf);
554 return NULL;
555 #endif /* __SOLARIS__ */
556 }
557
get_path(struct fuse * f,fuse_ino_t nodeid)558 static char *get_path(struct fuse *f, fuse_ino_t nodeid)
559 {
560 return get_path_name(f, nodeid, NULL);
561 }
562
forget_node(struct fuse * f,fuse_ino_t nodeid,uint64_t nlookup)563 static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
564 {
565 struct node *node;
566 if (nodeid == FUSE_ROOT_ID)
567 return;
568 pthread_mutex_lock(&f->lock);
569 node = get_node(f, nodeid);
570 assert(node->nlookup >= nlookup);
571 node->nlookup -= nlookup;
572 if (!node->nlookup) {
573 unhash_name(f, node);
574 unref_node(f, node);
575 }
576 pthread_mutex_unlock(&f->lock);
577 }
578
remove_node(struct fuse * f,fuse_ino_t dir,const char * name)579 static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
580 {
581 struct node *node;
582
583 pthread_mutex_lock(&f->lock);
584 node = lookup_node(f, dir, name);
585 if (node != NULL)
586 unhash_name(f, node);
587 pthread_mutex_unlock(&f->lock);
588 }
589
rename_node(struct fuse * f,fuse_ino_t olddir,const char * oldname,fuse_ino_t newdir,const char * newname,int hide)590 static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
591 fuse_ino_t newdir, const char *newname, int hide)
592 {
593 struct node *node;
594 struct node *newnode;
595 int err = 0;
596
597 pthread_mutex_lock(&f->lock);
598 node = lookup_node(f, olddir, oldname);
599 newnode = lookup_node(f, newdir, newname);
600 if (node == NULL)
601 goto out;
602
603 if (newnode != NULL) {
604 if (hide) {
605 fprintf(stderr, "fuse: hidden file got created during hiding\n");
606 err = -EBUSY;
607 goto out;
608 }
609 unhash_name(f, newnode);
610 }
611
612 unhash_name(f, node);
613 if (hash_name(f, node, newdir, newname) == -1) {
614 err = -ENOMEM;
615 goto out;
616 }
617
618 if (hide)
619 node->is_hidden = 1;
620
621 out:
622 pthread_mutex_unlock(&f->lock);
623 return err;
624 }
625
set_stat(struct fuse * f,fuse_ino_t nodeid,struct stat * stbuf)626 static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
627 {
628 if (!f->conf.use_ino)
629 stbuf->st_ino = nodeid;
630 if (f->conf.set_mode)
631 stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
632 if (f->conf.set_uid)
633 stbuf->st_uid = f->conf.uid;
634 if (f->conf.set_gid)
635 stbuf->st_gid = f->conf.gid;
636 }
637
req_fuse(fuse_req_t req)638 static struct fuse *req_fuse(fuse_req_t req)
639 {
640 return (struct fuse *) fuse_req_userdata(req);
641 }
642
fuse_intr_sighandler(int sig)643 static void fuse_intr_sighandler(int sig)
644 {
645 (void) sig;
646 /* Nothing to do */
647 }
648
649 struct fuse_intr_data {
650 pthread_t id;
651 pthread_cond_t cond;
652 int finished;
653 };
654
fuse_interrupt(fuse_req_t req,void * d_)655 static void fuse_interrupt(fuse_req_t req, void *d_)
656 {
657 struct fuse_intr_data *d = d_;
658 struct fuse *f = req_fuse(req);
659
660 if (d->id == pthread_self())
661 return;
662
663 pthread_mutex_lock(&f->lock);
664 while (!d->finished) {
665 struct timeval now;
666 struct timespec timeout;
667
668 pthread_kill(d->id, f->conf.intr_signal);
669 gettimeofday(&now, NULL);
670 timeout.tv_sec = now.tv_sec + 1;
671 timeout.tv_nsec = now.tv_usec * 1000;
672 pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
673 }
674 pthread_mutex_unlock(&f->lock);
675 }
676
fuse_do_finish_interrupt(struct fuse * f,fuse_req_t req,struct fuse_intr_data * d)677 static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
678 struct fuse_intr_data *d)
679 {
680 pthread_mutex_lock(&f->lock);
681 d->finished = 1;
682 pthread_cond_broadcast(&d->cond);
683 pthread_mutex_unlock(&f->lock);
684 fuse_req_interrupt_func(req, NULL, NULL);
685 pthread_cond_destroy(&d->cond);
686 }
687
fuse_do_prepare_interrupt(fuse_req_t req,struct fuse_intr_data * d)688 static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
689 {
690 d->id = pthread_self();
691 pthread_cond_init(&d->cond, NULL);
692 d->finished = 0;
693 fuse_req_interrupt_func(req, fuse_interrupt, d);
694 }
695
fuse_finish_interrupt(struct fuse * f,fuse_req_t req,struct fuse_intr_data * d)696 static void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
697 struct fuse_intr_data *d)
698 {
699 if (f->conf.intr)
700 fuse_do_finish_interrupt(f, req, d);
701 }
702
fuse_prepare_interrupt(struct fuse * f,fuse_req_t req,struct fuse_intr_data * d)703 static void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
704 struct fuse_intr_data *d)
705 {
706 if (f->conf.intr)
707 fuse_do_prepare_interrupt(req, d);
708 }
709
fuse_fs_getattr(struct fuse_fs * fs,const char * path,struct stat * buf)710 int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf)
711 {
712 fuse_get_context()->private_data = fs->user_data;
713 if (fs->op.getattr)
714 return fs->op.getattr(path, buf);
715 else
716 return -ENOSYS;
717 }
718
fuse_fs_fgetattr(struct fuse_fs * fs,const char * path,struct stat * buf,struct fuse_file_info * fi)719 int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
720 struct fuse_file_info *fi)
721 {
722 fuse_get_context()->private_data = fs->user_data;
723 if (fs->op.fgetattr)
724 return fs->op.fgetattr(path, buf, fi);
725 else if (fs->op.getattr)
726 return fs->op.getattr(path, buf);
727 else
728 return -ENOSYS;
729 }
730
fuse_fs_rename(struct fuse_fs * fs,const char * oldpath,const char * newpath)731 int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
732 const char *newpath)
733 {
734 fuse_get_context()->private_data = fs->user_data;
735 if (fs->op.rename)
736 return fs->op.rename(oldpath, newpath);
737 else
738 return -ENOSYS;
739 }
740
fuse_fs_unlink(struct fuse_fs * fs,const char * path)741 int fuse_fs_unlink(struct fuse_fs *fs, const char *path)
742 {
743 fuse_get_context()->private_data = fs->user_data;
744 if (fs->op.unlink)
745 return fs->op.unlink(path);
746 else
747 return -ENOSYS;
748 }
749
fuse_fs_rmdir(struct fuse_fs * fs,const char * path)750 int fuse_fs_rmdir(struct fuse_fs *fs, const char *path)
751 {
752 fuse_get_context()->private_data = fs->user_data;
753 if (fs->op.rmdir)
754 return fs->op.rmdir(path);
755 else
756 return -ENOSYS;
757 }
758
fuse_fs_symlink(struct fuse_fs * fs,const char * linkname,const char * path)759 int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path)
760 {
761 fuse_get_context()->private_data = fs->user_data;
762 if (fs->op.symlink)
763 return fs->op.symlink(linkname, path);
764 else
765 return -ENOSYS;
766 }
767
fuse_fs_link(struct fuse_fs * fs,const char * oldpath,const char * newpath)768 int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath)
769 {
770 fuse_get_context()->private_data = fs->user_data;
771 if (fs->op.link)
772 return fs->op.link(oldpath, newpath);
773 else
774 return -ENOSYS;
775 }
776
fuse_fs_release(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi)777 int fuse_fs_release(struct fuse_fs *fs, const char *path,
778 struct fuse_file_info *fi)
779 {
780 fuse_get_context()->private_data = fs->user_data;
781 if (fs->op.release)
782 return fs->op.release(path, fi);
783 else
784 return 0;
785 }
786
fuse_fs_opendir(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi)787 int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
788 struct fuse_file_info *fi)
789 {
790 fuse_get_context()->private_data = fs->user_data;
791 if (fs->op.opendir)
792 return fs->op.opendir(path, fi);
793 else
794 return 0;
795 }
796
fuse_fs_open(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi)797 int fuse_fs_open(struct fuse_fs *fs, const char *path,
798 struct fuse_file_info *fi)
799 {
800 fuse_get_context()->private_data = fs->user_data;
801 if (fs->op.open)
802 return fs->op.open(path, fi);
803 else
804 return 0;
805 }
806
fuse_fs_read(struct fuse_fs * fs,const char * path,char * buf,size_t size,off_t off,struct fuse_file_info * fi)807 int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
808 off_t off, struct fuse_file_info *fi)
809 {
810 fuse_get_context()->private_data = fs->user_data;
811 if (fs->op.read)
812 return fs->op.read(path, buf, size, off, fi);
813 else
814 return -ENOSYS;
815 }
816
fuse_fs_write(struct fuse_fs * fs,const char * path,const char * buf,size_t size,off_t off,struct fuse_file_info * fi)817 int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
818 size_t size, off_t off, struct fuse_file_info *fi)
819 {
820 fuse_get_context()->private_data = fs->user_data;
821 if (fs->op.write)
822 return fs->op.write(path, buf, size, off, fi);
823 else
824 return -ENOSYS;
825 }
826
fuse_fs_fsync(struct fuse_fs * fs,const char * path,int datasync,struct fuse_file_info * fi)827 int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
828 struct fuse_file_info *fi)
829 {
830 fuse_get_context()->private_data = fs->user_data;
831 if (fs->op.fsync)
832 return fs->op.fsync(path, datasync, fi);
833 else
834 return -ENOSYS;
835 }
836
fuse_fs_fsyncdir(struct fuse_fs * fs,const char * path,int datasync,struct fuse_file_info * fi)837 int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
838 struct fuse_file_info *fi)
839 {
840 fuse_get_context()->private_data = fs->user_data;
841 if (fs->op.fsyncdir)
842 return fs->op.fsyncdir(path, datasync, fi);
843 else
844 return -ENOSYS;
845 }
846
fuse_fs_flush(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi)847 int fuse_fs_flush(struct fuse_fs *fs, const char *path,
848 struct fuse_file_info *fi)
849 {
850 fuse_get_context()->private_data = fs->user_data;
851 if (fs->op.flush)
852 return fs->op.flush(path, fi);
853 else
854 return -ENOSYS;
855 }
856
fuse_fs_statfs(struct fuse_fs * fs,const char * path,struct statvfs * buf)857 int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf)
858 {
859 fuse_get_context()->private_data = fs->user_data;
860 if (fs->op.statfs)
861 return fs->op.statfs(path, buf);
862 else {
863 buf->f_namemax = 255;
864 buf->f_bsize = 512;
865 return 0;
866 }
867 }
868
fuse_fs_releasedir(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi)869 int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
870 struct fuse_file_info *fi)
871 {
872 fuse_get_context()->private_data = fs->user_data;
873 if (fs->op.releasedir)
874 return fs->op.releasedir(path, fi);
875 else
876 return 0;
877 }
878
fuse_fs_readdir(struct fuse_fs * fs,const char * path,void * buf,fuse_fill_dir_t filler,off_t off,struct fuse_file_info * fi)879 int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
880 fuse_fill_dir_t filler, off_t off,
881 struct fuse_file_info *fi)
882 {
883 fuse_get_context()->private_data = fs->user_data;
884 if (fs->op.readdir)
885 return fs->op.readdir(path, buf, filler, off, fi);
886 else
887 return -ENOSYS;
888 }
889
fuse_fs_create(struct fuse_fs * fs,const char * path,mode_t mode,struct fuse_file_info * fi)890 int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
891 struct fuse_file_info *fi)
892 {
893 fuse_get_context()->private_data = fs->user_data;
894 if (fs->op.create)
895 return fs->op.create(path, mode, fi);
896 else
897 return -ENOSYS;
898 }
899
fuse_fs_lock(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi,int cmd,struct flock * lock)900 int fuse_fs_lock(struct fuse_fs *fs, const char *path,
901 struct fuse_file_info *fi, int cmd, struct flock *lock)
902 {
903 fuse_get_context()->private_data = fs->user_data;
904 if (fs->op.lock)
905 return fs->op.lock(path, fi, cmd, lock);
906 else
907 return -ENOSYS;
908 }
909
fuse_fs_chown(struct fuse_fs * fs,const char * path,uid_t uid,gid_t gid)910 int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid)
911 {
912 fuse_get_context()->private_data = fs->user_data;
913 if (fs->op.chown)
914 return fs->op.chown(path, uid, gid);
915 else
916 return -ENOSYS;
917 }
918
fuse_fs_truncate(struct fuse_fs * fs,const char * path,off_t size)919 int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size)
920 {
921 fuse_get_context()->private_data = fs->user_data;
922 if (fs->op.truncate)
923 return fs->op.truncate(path, size);
924 else
925 return -ENOSYS;
926 }
927
fuse_fs_ftruncate(struct fuse_fs * fs,const char * path,off_t size,struct fuse_file_info * fi)928 int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size,
929 struct fuse_file_info *fi)
930 {
931 fuse_get_context()->private_data = fs->user_data;
932 if (fs->op.ftruncate)
933 return fs->op.ftruncate(path, size, fi);
934 else if (fs->op.truncate)
935 return fs->op.truncate(path, size);
936 else
937 return -ENOSYS;
938 }
939
fuse_fs_utimens(struct fuse_fs * fs,const char * path,const struct timespec tv[2])940 int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
941 const struct timespec tv[2])
942 {
943 fuse_get_context()->private_data = fs->user_data;
944 if (fs->op.utimens)
945 return fs->op.utimens(path, tv);
946 else if(fs->op.utime) {
947 struct utimbuf buf;
948 buf.actime = tv[0].tv_sec;
949 buf.modtime = tv[1].tv_sec;
950 return fs->op.utime(path, &buf);
951 } else
952 return -ENOSYS;
953 }
954
fuse_fs_access(struct fuse_fs * fs,const char * path,int mask)955 int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask)
956 {
957 fuse_get_context()->private_data = fs->user_data;
958 if (fs->op.access)
959 return fs->op.access(path, mask);
960 else
961 return -ENOSYS;
962 }
963
fuse_fs_readlink(struct fuse_fs * fs,const char * path,char * buf,size_t len)964 int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
965 size_t len)
966 {
967 fuse_get_context()->private_data = fs->user_data;
968 if (fs->op.readlink)
969 return fs->op.readlink(path, buf, len);
970 else
971 return -ENOSYS;
972 }
973
fuse_fs_mknod(struct fuse_fs * fs,const char * path,mode_t mode,dev_t rdev)974 int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
975 dev_t rdev)
976 {
977 fuse_get_context()->private_data = fs->user_data;
978 if (fs->op.mknod)
979 return fs->op.mknod(path, mode, rdev);
980 else
981 return -ENOSYS;
982 }
983
fuse_fs_mkdir(struct fuse_fs * fs,const char * path,mode_t mode)984 int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode)
985 {
986 fuse_get_context()->private_data = fs->user_data;
987 if (fs->op.mkdir)
988 return fs->op.mkdir(path, mode);
989 else
990 return -ENOSYS;
991 }
992
fuse_fs_setxattr(struct fuse_fs * fs,const char * path,const char * name,const char * value,size_t size,int flags)993 int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
994 const char *value, size_t size, int flags)
995 {
996 fuse_get_context()->private_data = fs->user_data;
997 if (fs->op.setxattr)
998 return fs->op.setxattr(path, name, value, size, flags);
999 else
1000 return -ENOSYS;
1001 }
1002
fuse_fs_getxattr(struct fuse_fs * fs,const char * path,const char * name,char * value,size_t size)1003 int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
1004 char *value, size_t size)
1005 {
1006 fuse_get_context()->private_data = fs->user_data;
1007 if (fs->op.getxattr)
1008 return fs->op.getxattr(path, name, value, size);
1009 else
1010 return -ENOSYS;
1011 }
1012
fuse_fs_listxattr(struct fuse_fs * fs,const char * path,char * list,size_t size)1013 int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
1014 size_t size)
1015 {
1016 fuse_get_context()->private_data = fs->user_data;
1017 if (fs->op.listxattr)
1018 return fs->op.listxattr(path, list, size);
1019 else
1020 return -ENOSYS;
1021 }
1022
fuse_fs_bmap(struct fuse_fs * fs,const char * path,size_t blocksize,uint64_t * idx)1023 int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
1024 uint64_t *idx)
1025 {
1026 fuse_get_context()->private_data = fs->user_data;
1027 if (fs->op.bmap)
1028 return fs->op.bmap(path, blocksize, idx);
1029 else
1030 return -ENOSYS;
1031 }
1032
fuse_fs_removexattr(struct fuse_fs * fs,const char * path,const char * name)1033 int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name)
1034 {
1035 fuse_get_context()->private_data = fs->user_data;
1036 if (fs->op.removexattr)
1037 return fs->op.removexattr(path, name);
1038 else
1039 return -ENOSYS;
1040 }
1041
fuse_fs_ioctl(struct fuse_fs * fs,const char * path,int cmd,void * arg,struct fuse_file_info * fi,unsigned int flags,void * data)1042 int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
1043 struct fuse_file_info *fi, unsigned int flags, void *data)
1044 {
1045 fuse_get_context()->private_data = fs->user_data;
1046 if (fs->op.ioctl) {
1047 /*
1048 if (fs->debug)
1049 fprintf(stderr, "ioctl[%llu] 0x%x flags: 0x%x\n",
1050 (unsigned long long) fi->fh, cmd, flags);
1051 */
1052 return fs->op.ioctl(path, cmd, arg, fi, flags, data);
1053 } else
1054 return -ENOSYS;
1055 }
1056
is_open(struct fuse * f,fuse_ino_t dir,const char * name)1057 static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
1058 {
1059 struct node *node;
1060 int isopen = 0;
1061 pthread_mutex_lock(&f->lock);
1062 node = lookup_node(f, dir, name);
1063 if (node && node->open_count > 0)
1064 isopen = 1;
1065 pthread_mutex_unlock(&f->lock);
1066 return isopen;
1067 }
1068
hidden_name(struct fuse * f,fuse_ino_t dir,const char * oldname,char * newname,size_t bufsize)1069 static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname,
1070 char *newname, size_t bufsize)
1071 {
1072 struct stat buf;
1073 struct node *node;
1074 struct node *newnode;
1075 char *newpath;
1076 int res;
1077 int failctr = 10;
1078
1079 do {
1080 pthread_mutex_lock(&f->lock);
1081 node = lookup_node(f, dir, oldname);
1082 if (node == NULL) {
1083 pthread_mutex_unlock(&f->lock);
1084 return NULL;
1085 }
1086 do {
1087 f->hidectr ++;
1088 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
1089 (unsigned int) node->nodeid, f->hidectr);
1090 newnode = lookup_node(f, dir, newname);
1091 } while(newnode);
1092 pthread_mutex_unlock(&f->lock);
1093
1094 newpath = get_path_name(f, dir, newname);
1095 if (!newpath)
1096 break;
1097
1098 res = fuse_fs_getattr(f->fs, newpath, &buf);
1099 if (res == -ENOENT)
1100 break;
1101 free(newpath);
1102 newpath = NULL;
1103 } while(res == 0 && --failctr);
1104
1105 return newpath;
1106 }
1107
hide_node(struct fuse * f,const char * oldpath,fuse_ino_t dir,const char * oldname)1108 static int hide_node(struct fuse *f, const char *oldpath,
1109 fuse_ino_t dir, const char *oldname)
1110 {
1111 char newname[64];
1112 char *newpath;
1113 int err = -EBUSY;
1114
1115 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
1116 if (newpath) {
1117 err = fuse_fs_rename(f->fs, oldpath, newpath);
1118 if (!err)
1119 err = rename_node(f, dir, oldname, dir, newname, 1);
1120 free(newpath);
1121 }
1122 return err;
1123 }
1124
1125 #ifdef __SOLARIS__
1126
mtime_eq(const struct stat * stbuf,const struct timespec * ts)1127 static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
1128 {
1129 return stbuf->st_mtime == ts->tv_sec && ST_MTIM_NSEC(stbuf) == ts->tv_nsec;
1130 }
1131
1132 #ifndef CLOCK_MONOTONIC
1133 #define CLOCK_MONOTONIC CLOCK_REALTIME
1134 #endif
1135
curr_time(struct timespec * now)1136 static void curr_time(struct timespec *now)
1137 {
1138 static clockid_t clockid = CLOCK_MONOTONIC;
1139 int res = clock_gettime(clockid, now);
1140 if (res == -1 && errno == EINVAL) {
1141 clockid = CLOCK_REALTIME;
1142 res = clock_gettime(clockid, now);
1143 }
1144 if (res == -1) {
1145 perror("fuse: clock_gettime");
1146 abort();
1147 }
1148 }
1149
update_stat(struct node * node,const struct stat * stbuf)1150 static void update_stat(struct node *node, const struct stat *stbuf)
1151 {
1152 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
1153 stbuf->st_size != node->size))
1154 node->cache_valid = 0;
1155 node->mtime.tv_sec = stbuf->st_mtime;
1156 node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf);
1157 node->size = stbuf->st_size;
1158 curr_time(&node->stat_updated);
1159 }
1160
1161 #endif /* __SOLARIS__ */
1162
lookup_path(struct fuse * f,fuse_ino_t nodeid,const char * name,const char * path,struct fuse_entry_param * e,struct fuse_file_info * fi)1163 static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
1164 const char *name, const char *path,
1165 struct fuse_entry_param *e, struct fuse_file_info *fi)
1166 {
1167 int res;
1168
1169 memset(e, 0, sizeof(struct fuse_entry_param));
1170 if (fi)
1171 res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi);
1172 else
1173 res = fuse_fs_getattr(f->fs, path, &e->attr);
1174 if (res == 0) {
1175 struct node *node;
1176
1177 node = find_node(f, nodeid, name);
1178 if (node == NULL)
1179 res = -ENOMEM;
1180 else {
1181 e->ino = node->nodeid;
1182 e->generation = node->generation;
1183 e->entry_timeout = f->conf.entry_timeout;
1184 e->attr_timeout = f->conf.attr_timeout;
1185 #ifdef __SOLARIS__
1186 if (f->conf.auto_cache) {
1187 pthread_mutex_lock(&f->lock);
1188 update_stat(node, &e->attr);
1189 pthread_mutex_unlock(&f->lock);
1190 }
1191 #endif /* __SOLARIS__ */
1192 set_stat(f, e->ino, &e->attr);
1193 if (f->conf.debug)
1194 fprintf(stderr, " NODEID: %lu\n", (unsigned long) e->ino);
1195 }
1196 }
1197 return res;
1198 }
1199
fuse_get_context_internal(void)1200 static struct fuse_context_i *fuse_get_context_internal(void)
1201 {
1202 struct fuse_context_i *c;
1203
1204 c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
1205 if (c == NULL) {
1206 c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
1207 if (c == NULL) {
1208 /* This is hard to deal with properly, so just abort. If
1209 memory is so low that the context cannot be allocated,
1210 there's not much hope for the filesystem anyway */
1211 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
1212 abort();
1213 }
1214 pthread_setspecific(fuse_context_key, c);
1215 }
1216 return c;
1217 }
1218
fuse_freecontext(void * data)1219 static void fuse_freecontext(void *data)
1220 {
1221 free(data);
1222 }
1223
fuse_create_context_key(void)1224 static int fuse_create_context_key(void)
1225 {
1226 int err = 0;
1227 pthread_mutex_lock(&fuse_context_lock);
1228 if (!fuse_context_ref) {
1229 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
1230 if (err) {
1231 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
1232 strerror(err));
1233 pthread_mutex_unlock(&fuse_context_lock);
1234 return -1;
1235 }
1236 }
1237 fuse_context_ref++;
1238 pthread_mutex_unlock(&fuse_context_lock);
1239 return 0;
1240 }
1241
fuse_delete_context_key(void)1242 static void fuse_delete_context_key(void)
1243 {
1244 pthread_mutex_lock(&fuse_context_lock);
1245 fuse_context_ref--;
1246 if (!fuse_context_ref) {
1247 free(pthread_getspecific(fuse_context_key));
1248 pthread_key_delete(fuse_context_key);
1249 }
1250 pthread_mutex_unlock(&fuse_context_lock);
1251 }
1252
req_fuse_prepare(fuse_req_t req)1253 static struct fuse *req_fuse_prepare(fuse_req_t req)
1254 {
1255 struct fuse_context_i *c = fuse_get_context_internal();
1256 const struct fuse_ctx *ctx = fuse_req_ctx(req);
1257 c->req = req;
1258 c->ctx.fuse = req_fuse(req);
1259 c->ctx.uid = ctx->uid;
1260 c->ctx.gid = ctx->gid;
1261 c->ctx.pid = ctx->pid;
1262 #ifdef POSIXACLS
1263 c->ctx.umask = ctx->umask;
1264 #endif
1265 return c->ctx.fuse;
1266 }
1267
1268 #ifndef __SOLARIS__
reply_err(fuse_req_t req,int err)1269 static void reply_err(fuse_req_t req, int err)
1270 #else /* __SOLARIS__ */
1271 static inline void reply_err(fuse_req_t req, int err)
1272 #endif /* __SOLARIS__ */
1273 {
1274 /* fuse_reply_err() uses non-negated errno values */
1275 fuse_reply_err(req, -err);
1276 }
1277
reply_entry(fuse_req_t req,const struct fuse_entry_param * e,int err)1278 static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
1279 int err)
1280 {
1281 if (!err) {
1282 struct fuse *f = req_fuse(req);
1283 #ifdef __SOLARIS__
1284 /* Skip forget for negative result */
1285 if ((fuse_reply_entry(req, e) == -ENOENT)
1286 && (e->ino != 0))
1287 forget_node(f, e->ino, 1);
1288 #else /* __SOLARIS__ */
1289 if (fuse_reply_entry(req, e) == -ENOENT)
1290 forget_node(f, e->ino, 1);
1291 #endif
1292 } else
1293 reply_err(req, err);
1294 }
1295
fuse_fs_init(struct fuse_fs * fs,struct fuse_conn_info * conn)1296 void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn)
1297 {
1298 fuse_get_context()->private_data = fs->user_data;
1299 if (fs->op.init)
1300 fs->user_data = fs->op.init(conn);
1301 }
1302
fuse_lib_init(void * data,struct fuse_conn_info * conn)1303 static void fuse_lib_init(void *data, struct fuse_conn_info *conn)
1304 {
1305 struct fuse *f = (struct fuse *) data;
1306 struct fuse_context_i *c = fuse_get_context_internal();
1307
1308 memset(c, 0, sizeof(*c));
1309 c->ctx.fuse = f;
1310 fuse_fs_init(f->fs, conn);
1311 }
1312
fuse_fs_destroy(struct fuse_fs * fs)1313 void fuse_fs_destroy(struct fuse_fs *fs)
1314 {
1315 fuse_get_context()->private_data = fs->user_data;
1316 if (fs->op.destroy)
1317 fs->op.destroy(fs->user_data);
1318 #ifdef __SOLARIS__
1319 if (fs->m)
1320 fuse_put_module(fs->m);
1321 #endif /* __SOLARIS__ */
1322 free(fs);
1323 }
1324
fuse_lib_destroy(void * data)1325 static void fuse_lib_destroy(void *data)
1326 {
1327 struct fuse *f = (struct fuse *) data;
1328 struct fuse_context_i *c = fuse_get_context_internal();
1329
1330 memset(c, 0, sizeof(*c));
1331 c->ctx.fuse = f;
1332 fuse_fs_destroy(f->fs);
1333 f->fs = NULL;
1334 }
1335
fuse_lib_lookup(fuse_req_t req,fuse_ino_t parent,const char * name)1336 static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent,
1337 const char *name)
1338 {
1339 struct fuse *f = req_fuse_prepare(req);
1340 struct fuse_entry_param e;
1341 char *path;
1342 int err;
1343
1344 err = -ENOENT;
1345 pthread_rwlock_rdlock(&f->tree_lock);
1346 path = get_path_name(f, parent, name);
1347 if (path != NULL) {
1348 struct fuse_intr_data d;
1349 if (f->conf.debug)
1350 fprintf(stderr, "LOOKUP %s\n", path);
1351 fuse_prepare_interrupt(f, req, &d);
1352 err = lookup_path(f, parent, name, path, &e, NULL);
1353 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
1354 e.ino = 0;
1355 e.entry_timeout = f->conf.negative_timeout;
1356 err = 0;
1357 }
1358 fuse_finish_interrupt(f, req, &d);
1359 free(path);
1360 }
1361 pthread_rwlock_unlock(&f->tree_lock);
1362 reply_entry(req, &e, err);
1363 }
1364
fuse_lib_forget(fuse_req_t req,fuse_ino_t ino,unsigned long nlookup)1365 static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino,
1366 unsigned long nlookup)
1367 {
1368 struct fuse *f = req_fuse(req);
1369 if (f->conf.debug)
1370 fprintf(stderr, "FORGET %llu/%lu\n", (unsigned long long)ino, nlookup);
1371 forget_node(f, ino, nlookup);
1372 fuse_reply_none(req);
1373 }
1374
fuse_lib_getattr(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)1375 static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
1376 struct fuse_file_info *fi)
1377 {
1378 struct fuse *f = req_fuse_prepare(req);
1379 struct stat buf;
1380 char *path;
1381 int err;
1382
1383 (void) fi;
1384 memset(&buf, 0, sizeof(buf));
1385
1386 err = -ENOENT;
1387 pthread_rwlock_rdlock(&f->tree_lock);
1388 path = get_path(f, ino);
1389 if (path != NULL) {
1390 struct fuse_intr_data d;
1391 fuse_prepare_interrupt(f, req, &d);
1392 err = fuse_fs_getattr(f->fs, path, &buf);
1393 fuse_finish_interrupt(f, req, &d);
1394 free(path);
1395 }
1396 pthread_rwlock_unlock(&f->tree_lock);
1397 if (!err) {
1398 #ifdef __SOLARIS__
1399 if (f->conf.auto_cache) {
1400 pthread_mutex_lock(&f->lock);
1401 update_stat(get_node(f, ino), &buf);
1402 pthread_mutex_unlock(&f->lock);
1403 }
1404 #endif /* __SOLARIS__ */
1405 set_stat(f, ino, &buf);
1406 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
1407 } else
1408 reply_err(req, err);
1409 }
1410
fuse_fs_chmod(struct fuse_fs * fs,const char * path,mode_t mode)1411 int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode)
1412 {
1413 fuse_get_context()->private_data = fs->user_data;
1414 if (fs->op.chmod)
1415 return fs->op.chmod(path, mode);
1416 else
1417 return -ENOSYS;
1418 }
1419
fuse_lib_setattr(fuse_req_t req,fuse_ino_t ino,struct stat * attr,int valid,struct fuse_file_info * fi)1420 static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
1421 int valid, struct fuse_file_info *fi)
1422 {
1423 struct fuse *f = req_fuse_prepare(req);
1424 struct stat buf;
1425 char *path;
1426 int err;
1427
1428 err = -ENOENT;
1429 pthread_rwlock_rdlock(&f->tree_lock);
1430 path = get_path(f, ino);
1431 if (path != NULL) {
1432 struct fuse_intr_data d;
1433 fuse_prepare_interrupt(f, req, &d);
1434 err = 0;
1435 if (!err && (valid & FUSE_SET_ATTR_MODE))
1436 err = fuse_fs_chmod(f->fs, path, attr->st_mode);
1437 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) {
1438 uid_t uid =
1439 (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
1440 gid_t gid =
1441 (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
1442 err = fuse_fs_chown(f->fs, path, uid, gid);
1443 }
1444 if (!err && (valid & FUSE_SET_ATTR_SIZE)) {
1445 if (fi)
1446 err = fuse_fs_ftruncate(f->fs, path, attr->st_size, fi);
1447 else
1448 err = fuse_fs_truncate(f->fs, path, attr->st_size);
1449 }
1450 #ifdef HAVE_UTIMENSAT
1451 if (!err &&
1452 (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) {
1453 struct timespec tv[2];
1454
1455 tv[0].tv_sec = 0;
1456 tv[1].tv_sec = 0;
1457 tv[0].tv_nsec = UTIME_OMIT;
1458 tv[1].tv_nsec = UTIME_OMIT;
1459
1460 if (valid & FUSE_SET_ATTR_ATIME_NOW)
1461 tv[0].tv_nsec = UTIME_NOW;
1462 else if (valid & FUSE_SET_ATTR_ATIME)
1463 tv[0] = attr->st_atim;
1464
1465 if (valid & FUSE_SET_ATTR_MTIME_NOW)
1466 tv[1].tv_nsec = UTIME_NOW;
1467 else if (valid & FUSE_SET_ATTR_MTIME)
1468 tv[1] = attr->st_mtim;
1469
1470 err = fuse_fs_utimens(f->fs, path, tv);
1471 } else
1472 #endif
1473 if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ==
1474 (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
1475 struct timespec tv[2];
1476 tv[0].tv_sec = attr->st_atime;
1477 tv[0].tv_nsec = ST_ATIM_NSEC(attr);
1478 tv[1].tv_sec = attr->st_mtime;
1479 tv[1].tv_nsec = ST_MTIM_NSEC(attr);
1480 err = fuse_fs_utimens(f->fs, path, tv);
1481 }
1482 if (!err)
1483 err = fuse_fs_getattr(f->fs, path, &buf);
1484 fuse_finish_interrupt(f, req, &d);
1485 free(path);
1486 }
1487 pthread_rwlock_unlock(&f->tree_lock);
1488 if (!err) {
1489 #ifdef __SOLARIS__
1490 if (f->conf.auto_cache) {
1491 pthread_mutex_lock(&f->lock);
1492 update_stat(get_node(f, ino), &buf);
1493 pthread_mutex_unlock(&f->lock);
1494 }
1495 #endif /* __SOLARIS__ */
1496 set_stat(f, ino, &buf);
1497 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
1498 } else
1499 reply_err(req, err);
1500 }
1501
fuse_lib_access(fuse_req_t req,fuse_ino_t ino,int mask)1502 static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask)
1503 {
1504 struct fuse *f = req_fuse_prepare(req);
1505 char *path;
1506 int err;
1507
1508 err = -ENOENT;
1509 pthread_rwlock_rdlock(&f->tree_lock);
1510 path = get_path(f, ino);
1511 if (path != NULL) {
1512 struct fuse_intr_data d;
1513 if (f->conf.debug)
1514 fprintf(stderr, "ACCESS %s 0%o\n", path, mask);
1515 fuse_prepare_interrupt(f, req, &d);
1516 err = fuse_fs_access(f->fs, path, mask);
1517 fuse_finish_interrupt(f, req, &d);
1518 free(path);
1519 }
1520 pthread_rwlock_unlock(&f->tree_lock);
1521 reply_err(req, err);
1522 }
1523
fuse_lib_readlink(fuse_req_t req,fuse_ino_t ino)1524 static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino)
1525 {
1526 struct fuse *f = req_fuse_prepare(req);
1527 char linkname[PATH_MAX + 1];
1528 char *path;
1529 int err;
1530
1531 err = -ENOENT;
1532 pthread_rwlock_rdlock(&f->tree_lock);
1533 path = get_path(f, ino);
1534 if (path != NULL) {
1535 struct fuse_intr_data d;
1536 fuse_prepare_interrupt(f, req, &d);
1537 err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname));
1538 fuse_finish_interrupt(f, req, &d);
1539 free(path);
1540 }
1541 pthread_rwlock_unlock(&f->tree_lock);
1542 if (!err) {
1543 linkname[PATH_MAX] = '\0';
1544 fuse_reply_readlink(req, linkname);
1545 } else
1546 reply_err(req, err);
1547 }
1548
fuse_lib_mknod(fuse_req_t req,fuse_ino_t parent,const char * name,mode_t mode,dev_t rdev)1549 static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1550 mode_t mode, dev_t rdev)
1551 {
1552 struct fuse *f = req_fuse_prepare(req);
1553 struct fuse_entry_param e;
1554 char *path;
1555 int err;
1556
1557 err = -ENOENT;
1558 pthread_rwlock_rdlock(&f->tree_lock);
1559 path = get_path_name(f, parent, name);
1560 if (path) {
1561 struct fuse_intr_data d;
1562 if (f->conf.debug)
1563 fprintf(stderr, "MKNOD %s\n", path);
1564 fuse_prepare_interrupt(f, req, &d);
1565 err = -ENOSYS;
1566 if (S_ISREG(mode)) {
1567 struct fuse_file_info fi;
1568
1569 memset(&fi, 0, sizeof(fi));
1570 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
1571 err = fuse_fs_create(f->fs, path, mode, &fi);
1572 if (!err) {
1573 err = lookup_path(f, parent, name, path, &e, &fi);
1574 fuse_fs_release(f->fs, path, &fi);
1575 }
1576 }
1577 if (err == -ENOSYS) {
1578 err = fuse_fs_mknod(f->fs, path, mode, rdev);
1579 if (!err)
1580 err = lookup_path(f, parent, name, path, &e, NULL);
1581 }
1582 fuse_finish_interrupt(f, req, &d);
1583 free(path);
1584 }
1585 pthread_rwlock_unlock(&f->tree_lock);
1586 reply_entry(req, &e, err);
1587 }
1588
fuse_lib_mkdir(fuse_req_t req,fuse_ino_t parent,const char * name,mode_t mode)1589 static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1590 mode_t mode)
1591 {
1592 struct fuse *f = req_fuse_prepare(req);
1593 struct fuse_entry_param e;
1594 char *path;
1595 int err;
1596
1597 err = -ENOENT;
1598 pthread_rwlock_rdlock(&f->tree_lock);
1599 path = get_path_name(f, parent, name);
1600 if (path != NULL) {
1601 struct fuse_intr_data d;
1602 if (f->conf.debug)
1603 fprintf(stderr, "MKDIR %s\n", path);
1604 fuse_prepare_interrupt(f, req, &d);
1605 err = fuse_fs_mkdir(f->fs, path, mode);
1606 if (!err)
1607 err = lookup_path(f, parent, name, path, &e, NULL);
1608 fuse_finish_interrupt(f, req, &d);
1609 free(path);
1610 }
1611 pthread_rwlock_unlock(&f->tree_lock);
1612 reply_entry(req, &e, err);
1613 }
1614
fuse_lib_unlink(fuse_req_t req,fuse_ino_t parent,const char * name)1615 static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent,
1616 const char *name)
1617 {
1618 struct fuse *f = req_fuse_prepare(req);
1619 char *path;
1620 int err;
1621
1622 err = -ENOENT;
1623 pthread_rwlock_wrlock(&f->tree_lock);
1624 path = get_path_name(f, parent, name);
1625 if (path != NULL) {
1626 struct fuse_intr_data d;
1627 if (f->conf.debug)
1628 fprintf(stderr, "UNLINK %s\n", path);
1629 fuse_prepare_interrupt(f, req, &d);
1630 if (!f->conf.hard_remove && is_open(f, parent, name))
1631 err = hide_node(f, path, parent, name);
1632 else {
1633 err = fuse_fs_unlink(f->fs, path);
1634 if (!err)
1635 remove_node(f, parent, name);
1636 }
1637 fuse_finish_interrupt(f, req, &d);
1638 free(path);
1639 }
1640 pthread_rwlock_unlock(&f->tree_lock);
1641 reply_err(req, err);
1642 }
1643
fuse_lib_rmdir(fuse_req_t req,fuse_ino_t parent,const char * name)1644 static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
1645 {
1646 struct fuse *f = req_fuse_prepare(req);
1647 char *path;
1648 int err;
1649
1650 err = -ENOENT;
1651 pthread_rwlock_wrlock(&f->tree_lock);
1652 path = get_path_name(f, parent, name);
1653 if (path != NULL) {
1654 struct fuse_intr_data d;
1655 if (f->conf.debug)
1656 fprintf(stderr, "RMDIR %s\n", path);
1657 fuse_prepare_interrupt(f, req, &d);
1658 err = fuse_fs_rmdir(f->fs, path);
1659 fuse_finish_interrupt(f, req, &d);
1660 if (!err)
1661 remove_node(f, parent, name);
1662 free(path);
1663 }
1664 pthread_rwlock_unlock(&f->tree_lock);
1665 reply_err(req, err);
1666 }
1667
fuse_lib_symlink(fuse_req_t req,const char * linkname,fuse_ino_t parent,const char * name)1668 static void fuse_lib_symlink(fuse_req_t req, const char *linkname,
1669 fuse_ino_t parent, const char *name)
1670 {
1671 struct fuse *f = req_fuse_prepare(req);
1672 struct fuse_entry_param e;
1673 char *path;
1674 int err;
1675
1676 err = -ENOENT;
1677 pthread_rwlock_rdlock(&f->tree_lock);
1678 path = get_path_name(f, parent, name);
1679 if (path != NULL) {
1680 struct fuse_intr_data d;
1681 if (f->conf.debug)
1682 fprintf(stderr, "SYMLINK %s\n", path);
1683 fuse_prepare_interrupt(f, req, &d);
1684 err = fuse_fs_symlink(f->fs, linkname, path);
1685 if (!err)
1686 err = lookup_path(f, parent, name, path, &e, NULL);
1687 fuse_finish_interrupt(f, req, &d);
1688 free(path);
1689 }
1690 pthread_rwlock_unlock(&f->tree_lock);
1691 reply_entry(req, &e, err);
1692 }
1693
fuse_lib_rename(fuse_req_t req,fuse_ino_t olddir,const char * oldname,fuse_ino_t newdir,const char * newname)1694 static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir,
1695 const char *oldname, fuse_ino_t newdir,
1696 const char *newname)
1697 {
1698 struct fuse *f = req_fuse_prepare(req);
1699 char *oldpath;
1700 char *newpath;
1701 int err;
1702
1703 err = -ENOENT;
1704 pthread_rwlock_wrlock(&f->tree_lock);
1705 oldpath = get_path_name(f, olddir, oldname);
1706 if (oldpath != NULL) {
1707 newpath = get_path_name(f, newdir, newname);
1708 if (newpath != NULL) {
1709 struct fuse_intr_data d;
1710 if (f->conf.debug)
1711 fprintf(stderr, "RENAME %s -> %s\n", oldpath, newpath);
1712 err = 0;
1713 fuse_prepare_interrupt(f, req, &d);
1714 if (!f->conf.hard_remove && is_open(f, newdir, newname))
1715 err = hide_node(f, newpath, newdir, newname);
1716 if (!err) {
1717 err = fuse_fs_rename(f->fs, oldpath, newpath);
1718 if (!err)
1719 err = rename_node(f, olddir, oldname, newdir, newname, 0);
1720 }
1721 fuse_finish_interrupt(f, req, &d);
1722 free(newpath);
1723 }
1724 free(oldpath);
1725 }
1726 pthread_rwlock_unlock(&f->tree_lock);
1727 reply_err(req, err);
1728 }
1729
fuse_lib_link(fuse_req_t req,fuse_ino_t ino,fuse_ino_t newparent,const char * newname)1730 static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1731 const char *newname)
1732 {
1733 struct fuse *f = req_fuse_prepare(req);
1734 struct fuse_entry_param e;
1735 char *oldpath;
1736 char *newpath;
1737 int err;
1738
1739 err = -ENOENT;
1740 pthread_rwlock_rdlock(&f->tree_lock);
1741 oldpath = get_path(f, ino);
1742 if (oldpath != NULL) {
1743 newpath = get_path_name(f, newparent, newname);
1744 if (newpath != NULL) {
1745 struct fuse_intr_data d;
1746 if (f->conf.debug)
1747 fprintf(stderr, "LINK %s\n", newpath);
1748 fuse_prepare_interrupt(f, req, &d);
1749 err = fuse_fs_link(f->fs, oldpath, newpath);
1750 if (!err)
1751 err = lookup_path(f, newparent, newname, newpath, &e, NULL);
1752 fuse_finish_interrupt(f, req, &d);
1753 free(newpath);
1754 }
1755 free(oldpath);
1756 }
1757 pthread_rwlock_unlock(&f->tree_lock);
1758 reply_entry(req, &e, err);
1759 }
1760
fuse_do_release(struct fuse * f,fuse_ino_t ino,const char * path,struct fuse_file_info * fi)1761 static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path,
1762 struct fuse_file_info *fi)
1763 {
1764 struct node *node;
1765 int unlink_hidden = 0;
1766
1767 fuse_fs_release(f->fs, path ? path : "-", fi);
1768
1769 pthread_mutex_lock(&f->lock);
1770 node = get_node(f, ino);
1771 assert(node->open_count > 0);
1772 --node->open_count;
1773 if (node->is_hidden && !node->open_count) {
1774 unlink_hidden = 1;
1775 node->is_hidden = 0;
1776 }
1777 pthread_mutex_unlock(&f->lock);
1778
1779 if(unlink_hidden && path)
1780 fuse_fs_unlink(f->fs, path);
1781 }
1782
fuse_lib_create(fuse_req_t req,fuse_ino_t parent,const char * name,mode_t mode,struct fuse_file_info * fi)1783 static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
1784 const char *name, mode_t mode,
1785 struct fuse_file_info *fi)
1786 {
1787 struct fuse *f = req_fuse_prepare(req);
1788 struct fuse_intr_data d;
1789 struct fuse_entry_param e;
1790 char *path;
1791 int err;
1792
1793 err = -ENOENT;
1794 pthread_rwlock_rdlock(&f->tree_lock);
1795 path = get_path_name(f, parent, name);
1796 if (path) {
1797 fuse_prepare_interrupt(f, req, &d);
1798 err = fuse_fs_create(f->fs, path, mode, fi);
1799 if (!err) {
1800 err = lookup_path(f, parent, name, path, &e, fi);
1801 if (err)
1802 fuse_fs_release(f->fs, path, fi);
1803 else if (!S_ISREG(e.attr.st_mode)) {
1804 err = -EIO;
1805 fuse_fs_release(f->fs, path, fi);
1806 forget_node(f, e.ino, 1);
1807 } else {
1808 if (f->conf.direct_io)
1809 fi->direct_io = 1;
1810 if (f->conf.kernel_cache)
1811 fi->keep_cache = 1;
1812
1813 }
1814 }
1815 fuse_finish_interrupt(f, req, &d);
1816 }
1817 if (!err) {
1818 pthread_mutex_lock(&f->lock);
1819 get_node(f, e.ino)->open_count++;
1820 pthread_mutex_unlock(&f->lock);
1821 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1822 /* The open syscall was interrupted, so it must be cancelled */
1823 fuse_prepare_interrupt(f, req, &d);
1824 fuse_do_release(f, e.ino, path, fi);
1825 fuse_finish_interrupt(f, req, &d);
1826 forget_node(f, e.ino, 1);
1827 } else if (f->conf.debug) {
1828 fprintf(stderr, " CREATE[%llu] flags: 0x%x %s\n",
1829 (unsigned long long) fi->fh, fi->flags, path);
1830 }
1831 } else
1832 reply_err(req, err);
1833
1834 if (path)
1835 free(path);
1836
1837 pthread_rwlock_unlock(&f->tree_lock);
1838 }
1839
1840 #ifdef __SOLARIS__
1841
diff_timespec(const struct timespec * t1,const struct timespec * t2)1842 static double diff_timespec(const struct timespec *t1,
1843 const struct timespec *t2)
1844 {
1845 return (t1->tv_sec - t2->tv_sec) +
1846 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1847 }
1848
open_auto_cache(struct fuse * f,fuse_ino_t ino,const char * path,struct fuse_file_info * fi)1849 static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path,
1850 struct fuse_file_info *fi)
1851 {
1852 struct node *node;
1853
1854 pthread_mutex_lock(&f->lock);
1855 node = get_node(f, ino);
1856 if (node->cache_valid) {
1857 struct timespec now;
1858
1859 curr_time(&now);
1860 if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
1861 struct stat stbuf;
1862 int err;
1863 pthread_mutex_unlock(&f->lock);
1864 err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi);
1865 pthread_mutex_lock(&f->lock);
1866 if (!err)
1867 update_stat(node, &stbuf);
1868 else
1869 node->cache_valid = 0;
1870 }
1871 }
1872 if (node->cache_valid)
1873 fi->keep_cache = 1;
1874
1875 node->cache_valid = 1;
1876 pthread_mutex_unlock(&f->lock);
1877 }
1878
1879 #endif /* __SOLARIS__ */
1880
fuse_lib_open(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)1881 static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
1882 struct fuse_file_info *fi)
1883 {
1884 struct fuse *f = req_fuse_prepare(req);
1885 struct fuse_intr_data d;
1886 char *path = NULL;
1887 int err = 0;
1888
1889 err = -ENOENT;
1890 pthread_rwlock_rdlock(&f->tree_lock);
1891 path = get_path(f, ino);
1892 if (path) {
1893 fuse_prepare_interrupt(f, req, &d);
1894 err = fuse_fs_open(f->fs, path, fi);
1895 if (!err) {
1896 if (f->conf.direct_io)
1897 fi->direct_io = 1;
1898 if (f->conf.kernel_cache)
1899 fi->keep_cache = 1;
1900 #ifdef __SOLARIS__
1901
1902 if (f->conf.auto_cache)
1903 open_auto_cache(f, ino, path, fi);
1904 #endif /* __SOLARIS__ */
1905 }
1906 fuse_finish_interrupt(f, req, &d);
1907 }
1908 if (!err) {
1909 pthread_mutex_lock(&f->lock);
1910 get_node(f, ino)->open_count++;
1911 pthread_mutex_unlock(&f->lock);
1912 if (fuse_reply_open(req, fi) == -ENOENT) {
1913 /* The open syscall was interrupted, so it must be cancelled */
1914 fuse_prepare_interrupt(f, req, &d);
1915 fuse_do_release(f, ino, path, fi);
1916 fuse_finish_interrupt(f, req, &d);
1917 } else if (f->conf.debug) {
1918 fprintf(stderr, "OPEN[%llu] flags: 0x%x %s\n",
1919 (unsigned long long) fi->fh, fi->flags, path);
1920 }
1921 } else
1922 reply_err(req, err);
1923
1924 if (path)
1925 free(path);
1926 pthread_rwlock_unlock(&f->tree_lock);
1927 }
1928
fuse_lib_read(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)1929 static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
1930 off_t off, struct fuse_file_info *fi)
1931 {
1932 struct fuse *f = req_fuse_prepare(req);
1933 char *path;
1934 char *buf;
1935 int res;
1936
1937 buf = (char *) malloc(size);
1938 if (buf == NULL) {
1939 reply_err(req, -ENOMEM);
1940 return;
1941 }
1942
1943 res = -ENOENT;
1944 pthread_rwlock_rdlock(&f->tree_lock);
1945 path = get_path(f, ino);
1946 if (path != NULL) {
1947 struct fuse_intr_data d;
1948 if (f->conf.debug)
1949 fprintf(stderr, "READ[%llu] %lu bytes from %llu\n",
1950 (unsigned long long) fi->fh, (unsigned long) size,
1951 (unsigned long long) off);
1952
1953 fuse_prepare_interrupt(f, req, &d);
1954 res = fuse_fs_read(f->fs, path, buf, size, off, fi);
1955 fuse_finish_interrupt(f, req, &d);
1956 free(path);
1957 }
1958 pthread_rwlock_unlock(&f->tree_lock);
1959
1960 if (res >= 0) {
1961 if (f->conf.debug)
1962 fprintf(stderr, " READ[%llu] %u bytes\n",
1963 (unsigned long long)fi->fh, res);
1964 if ((size_t) res > size)
1965 fprintf(stderr, "fuse: read too many bytes");
1966 fuse_reply_buf(req, buf, res);
1967 } else
1968 reply_err(req, res);
1969
1970 free(buf);
1971 }
1972
fuse_lib_write(fuse_req_t req,fuse_ino_t ino,const char * buf,size_t size,off_t off,struct fuse_file_info * fi)1973 static void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1974 size_t size, off_t off, struct fuse_file_info *fi)
1975 {
1976 struct fuse *f = req_fuse_prepare(req);
1977 char *path;
1978 int res;
1979
1980 res = -ENOENT;
1981 pthread_rwlock_rdlock(&f->tree_lock);
1982 path = get_path(f, ino);
1983 if (path != NULL) {
1984 struct fuse_intr_data d;
1985 if (f->conf.debug)
1986 fprintf(stderr, "WRITE%s[%llu] %lu bytes to %llu\n",
1987 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1988 (unsigned long) size, (unsigned long long) off);
1989
1990 fuse_prepare_interrupt(f, req, &d);
1991 res = fuse_fs_write(f->fs, path, buf, size, off, fi);
1992 fuse_finish_interrupt(f, req, &d);
1993 free(path);
1994 }
1995 pthread_rwlock_unlock(&f->tree_lock);
1996
1997 if (res >= 0) {
1998 if (f->conf.debug)
1999 fprintf(stderr, " WRITE%s[%llu] %u bytes\n",
2000 fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
2001 res);
2002 if ((size_t) res > size)
2003 fprintf(stderr, "fuse: wrote too many bytes");
2004 fuse_reply_write(req, res);
2005 } else
2006 reply_err(req, res);
2007 }
2008
fuse_lib_fsync(fuse_req_t req,fuse_ino_t ino,int datasync,struct fuse_file_info * fi)2009 static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
2010 struct fuse_file_info *fi)
2011 {
2012 struct fuse *f = req_fuse_prepare(req);
2013 char *path;
2014 int err;
2015
2016 err = -ENOENT;
2017 pthread_rwlock_rdlock(&f->tree_lock);
2018 path = get_path(f, ino);
2019 if (path != NULL) {
2020 struct fuse_intr_data d;
2021 if (f->conf.debug)
2022 fprintf(stderr, "FSYNC[%llu]\n", (unsigned long long) fi->fh);
2023 fuse_prepare_interrupt(f, req, &d);
2024 err = fuse_fs_fsync(f->fs, path, datasync, fi);
2025 fuse_finish_interrupt(f, req, &d);
2026 free(path);
2027 }
2028 pthread_rwlock_unlock(&f->tree_lock);
2029 reply_err(req, err);
2030 }
2031
get_dirhandle(const struct fuse_file_info * llfi,struct fuse_file_info * fi)2032 static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi,
2033 struct fuse_file_info *fi)
2034 {
2035 struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh;
2036 memset(fi, 0, sizeof(struct fuse_file_info));
2037 fi->fh = dh->fh;
2038 fi->fh_old = dh->fh;
2039 return dh;
2040 }
2041
fuse_lib_opendir(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * llfi)2042 static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
2043 struct fuse_file_info *llfi)
2044 {
2045 struct fuse *f = req_fuse_prepare(req);
2046 struct fuse_intr_data d;
2047 struct fuse_dh *dh;
2048 struct fuse_file_info fi;
2049 char *path;
2050 int err;
2051
2052 dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
2053 if (dh == NULL) {
2054 reply_err(req, -ENOMEM);
2055 return;
2056 }
2057 memset(dh, 0, sizeof(struct fuse_dh));
2058 dh->fuse = f;
2059 dh->contents = NULL;
2060 dh->len = 0;
2061 dh->filled = 0;
2062 dh->nodeid = ino;
2063 fuse_mutex_init(&dh->lock);
2064
2065 llfi->fh = (uintptr_t) dh;
2066
2067 memset(&fi, 0, sizeof(fi));
2068 fi.flags = llfi->flags;
2069
2070 err = -ENOENT;
2071 pthread_rwlock_rdlock(&f->tree_lock);
2072 path = get_path(f, ino);
2073 if (path != NULL) {
2074 fuse_prepare_interrupt(f, req, &d);
2075 err = fuse_fs_opendir(f->fs, path, &fi);
2076 fuse_finish_interrupt(f, req, &d);
2077 dh->fh = fi.fh;
2078 }
2079 if (!err) {
2080 if (fuse_reply_open(req, llfi) == -ENOENT) {
2081 /* The opendir syscall was interrupted, so it must be cancelled */
2082 fuse_prepare_interrupt(f, req, &d);
2083 fuse_fs_releasedir(f->fs, path, &fi);
2084 fuse_finish_interrupt(f, req, &d);
2085 pthread_mutex_destroy(&dh->lock);
2086 free(dh);
2087 }
2088 } else {
2089 reply_err(req, err);
2090 pthread_mutex_destroy(&dh->lock);
2091 free(dh);
2092 }
2093 free(path);
2094 pthread_rwlock_unlock(&f->tree_lock);
2095 }
2096
extend_contents(struct fuse_dh * dh,unsigned minsize)2097 static int extend_contents(struct fuse_dh *dh, unsigned minsize)
2098 {
2099 if (minsize > dh->size) {
2100 char *newptr;
2101 unsigned newsize = dh->size;
2102 if (!newsize)
2103 newsize = 1024;
2104 #ifndef __SOLARIS__
2105 while (newsize < minsize) {
2106 if (newsize >= 0x80000000)
2107 newsize = 0xffffffff;
2108 else
2109 newsize *= 2;
2110 }
2111 #else /* __SOLARIS__ */
2112 while (newsize < minsize)
2113 newsize *= 2;
2114 #endif /* __SOLARIS__ */
2115
2116 newptr = (char *) realloc(dh->contents, newsize);
2117 if (!newptr) {
2118 dh->error = -ENOMEM;
2119 return -1;
2120 }
2121 dh->contents = newptr;
2122 dh->size = newsize;
2123 }
2124 return 0;
2125 }
2126
fill_dir(void * dh_,const char * name,const struct stat * statp,off_t off)2127 static int fill_dir(void *dh_, const char *name, const struct stat *statp,
2128 off_t off)
2129 {
2130 struct fuse_dh *dh = (struct fuse_dh *) dh_;
2131 struct stat stbuf;
2132 size_t newlen;
2133
2134 if (statp)
2135 stbuf = *statp;
2136 else {
2137 memset(&stbuf, 0, sizeof(stbuf));
2138 stbuf.st_ino = FUSE_UNKNOWN_INO;
2139 }
2140
2141 if (!dh->fuse->conf.use_ino) {
2142 stbuf.st_ino = FUSE_UNKNOWN_INO;
2143 if (dh->fuse->conf.readdir_ino) {
2144 struct node *node;
2145 pthread_mutex_lock(&dh->fuse->lock);
2146 node = lookup_node(dh->fuse, dh->nodeid, name);
2147 if (node)
2148 stbuf.st_ino = (ino_t) node->nodeid;
2149 pthread_mutex_unlock(&dh->fuse->lock);
2150 }
2151 }
2152
2153 if (off) {
2154 if (extend_contents(dh, dh->needlen) == -1)
2155 return 1;
2156
2157 dh->filled = 0;
2158 newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
2159 dh->needlen - dh->len, name,
2160 &stbuf, off);
2161 if (newlen > dh->needlen)
2162 return 1;
2163 } else {
2164 newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
2165 if (extend_contents(dh, newlen) == -1)
2166 return 1;
2167
2168 fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
2169 name, &stbuf, newlen);
2170 }
2171 dh->len = newlen;
2172 return 0;
2173 }
2174
readdir_fill(struct fuse * f,fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_dh * dh,struct fuse_file_info * fi)2175 static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2176 size_t size, off_t off, struct fuse_dh *dh,
2177 struct fuse_file_info *fi)
2178 {
2179 int err = -ENOENT;
2180 char *path;
2181 pthread_rwlock_rdlock(&f->tree_lock);
2182 path = get_path(f, ino);
2183 if (path != NULL) {
2184 struct fuse_intr_data d;
2185
2186 dh->len = 0;
2187 dh->error = 0;
2188 dh->needlen = size;
2189 dh->filled = 1;
2190 dh->req = req;
2191 fuse_prepare_interrupt(f, req, &d);
2192 err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi);
2193 fuse_finish_interrupt(f, req, &d);
2194 dh->req = NULL;
2195 if (!err)
2196 err = dh->error;
2197 if (err)
2198 dh->filled = 0;
2199 free(path);
2200 }
2201 pthread_rwlock_unlock(&f->tree_lock);
2202 return err;
2203 }
2204
fuse_lib_readdir(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * llfi)2205 static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
2206 off_t off, struct fuse_file_info *llfi)
2207 {
2208 struct fuse *f = req_fuse_prepare(req);
2209 struct fuse_file_info fi;
2210 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
2211
2212 pthread_mutex_lock(&dh->lock);
2213 /* According to SUS, directory contents need to be refreshed on
2214 rewinddir() */
2215 if (!off)
2216 dh->filled = 0;
2217
2218 if (!dh->filled) {
2219 int err = readdir_fill(f, req, ino, size, off, dh, &fi);
2220 if (err) {
2221 reply_err(req, err);
2222 goto out;
2223 }
2224 }
2225 if (dh->filled) {
2226 if ((off >= 0) && (off < dh->len)) {
2227 if (off + size > dh->len)
2228 size = dh->len - off;
2229 } else
2230 size = 0;
2231 } else {
2232 size = dh->len;
2233 off = 0;
2234 }
2235 fuse_reply_buf(req, dh->contents + off, size);
2236 out:
2237 pthread_mutex_unlock(&dh->lock);
2238 }
2239
fuse_lib_releasedir(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * llfi)2240 static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
2241 struct fuse_file_info *llfi)
2242 {
2243 struct fuse *f = req_fuse_prepare(req);
2244 struct fuse_intr_data d;
2245 struct fuse_file_info fi;
2246 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
2247 char *path;
2248
2249 pthread_rwlock_rdlock(&f->tree_lock);
2250 path = get_path(f, ino);
2251 fuse_prepare_interrupt(f, req, &d);
2252 fuse_fs_releasedir(f->fs, path ? path : "-", &fi);
2253 fuse_finish_interrupt(f, req, &d);
2254 if (path)
2255 free(path);
2256 pthread_rwlock_unlock(&f->tree_lock);
2257 pthread_mutex_lock(&dh->lock);
2258 pthread_mutex_unlock(&dh->lock);
2259 pthread_mutex_destroy(&dh->lock);
2260 free(dh->contents);
2261 free(dh);
2262 reply_err(req, 0);
2263 }
2264
fuse_lib_fsyncdir(fuse_req_t req,fuse_ino_t ino,int datasync,struct fuse_file_info * llfi)2265 static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
2266 struct fuse_file_info *llfi)
2267 {
2268 struct fuse *f = req_fuse_prepare(req);
2269 struct fuse_file_info fi;
2270 char *path;
2271 int err;
2272
2273 get_dirhandle(llfi, &fi);
2274
2275 err = -ENOENT;
2276 pthread_rwlock_rdlock(&f->tree_lock);
2277 path = get_path(f, ino);
2278 if (path != NULL) {
2279 struct fuse_intr_data d;
2280 fuse_prepare_interrupt(f, req, &d);
2281 err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi);
2282 fuse_finish_interrupt(f, req, &d);
2283 free(path);
2284 }
2285 pthread_rwlock_unlock(&f->tree_lock);
2286 reply_err(req, err);
2287 }
2288
fuse_lib_statfs(fuse_req_t req,fuse_ino_t ino)2289 static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino)
2290 {
2291 struct fuse *f = req_fuse_prepare(req);
2292 struct statvfs buf;
2293 char *path;
2294 int err;
2295
2296 memset(&buf, 0, sizeof(buf));
2297 pthread_rwlock_rdlock(&f->tree_lock);
2298 if (!ino) {
2299 err = -ENOMEM;
2300 path = strdup("/");
2301 } else {
2302 err = -ENOENT;
2303 path = get_path(f, ino);
2304 }
2305 if (path) {
2306 struct fuse_intr_data d;
2307 fuse_prepare_interrupt(f, req, &d);
2308 err = fuse_fs_statfs(f->fs, path, &buf);
2309 fuse_finish_interrupt(f, req, &d);
2310 free(path);
2311 }
2312 pthread_rwlock_unlock(&f->tree_lock);
2313
2314 if (!err)
2315 fuse_reply_statfs(req, &buf);
2316 else
2317 reply_err(req, err);
2318 }
2319
fuse_lib_setxattr(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value,size_t size,int flags)2320 static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2321 const char *value, size_t size, int flags)
2322 {
2323 struct fuse *f = req_fuse_prepare(req);
2324 char *path;
2325 int err;
2326
2327 err = -ENOENT;
2328 pthread_rwlock_rdlock(&f->tree_lock);
2329 path = get_path(f, ino);
2330 if (path != NULL) {
2331 struct fuse_intr_data d;
2332 fuse_prepare_interrupt(f, req, &d);
2333 err = fuse_fs_setxattr(f->fs, path, name, value, size, flags);
2334 fuse_finish_interrupt(f, req, &d);
2335 free(path);
2336 }
2337 pthread_rwlock_unlock(&f->tree_lock);
2338 reply_err(req, err);
2339 }
2340
common_getxattr(struct fuse * f,fuse_req_t req,fuse_ino_t ino,const char * name,char * value,size_t size)2341 static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2342 const char *name, char *value, size_t size)
2343 {
2344 int err;
2345 char *path;
2346
2347 err = -ENOENT;
2348 pthread_rwlock_rdlock(&f->tree_lock);
2349 path = get_path(f, ino);
2350 if (path != NULL) {
2351 struct fuse_intr_data d;
2352 fuse_prepare_interrupt(f, req, &d);
2353 err = fuse_fs_getxattr(f->fs, path, name, value, size);
2354 fuse_finish_interrupt(f, req, &d);
2355 free(path);
2356 }
2357 pthread_rwlock_unlock(&f->tree_lock);
2358 return err;
2359 }
2360
fuse_lib_getxattr(fuse_req_t req,fuse_ino_t ino,const char * name,size_t size)2361 static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2362 size_t size)
2363 {
2364 struct fuse *f = req_fuse_prepare(req);
2365 int res;
2366
2367 if (size) {
2368 char *value = (char *) malloc(size);
2369 if (value == NULL) {
2370 reply_err(req, -ENOMEM);
2371 return;
2372 }
2373 res = common_getxattr(f, req, ino, name, value, size);
2374 if (res > 0)
2375 fuse_reply_buf(req, value, res);
2376 else
2377 reply_err(req, res);
2378 free(value);
2379 } else {
2380 res = common_getxattr(f, req, ino, name, NULL, 0);
2381 if (res >= 0)
2382 fuse_reply_xattr(req, res);
2383 else
2384 reply_err(req, res);
2385 }
2386 }
2387
common_listxattr(struct fuse * f,fuse_req_t req,fuse_ino_t ino,char * list,size_t size)2388 static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2389 char *list, size_t size)
2390 {
2391 char *path;
2392 int err;
2393
2394 err = -ENOENT;
2395 pthread_rwlock_rdlock(&f->tree_lock);
2396 path = get_path(f, ino);
2397 if (path != NULL) {
2398 struct fuse_intr_data d;
2399 fuse_prepare_interrupt(f, req, &d);
2400 err = fuse_fs_listxattr(f->fs, path, list, size);
2401 fuse_finish_interrupt(f, req, &d);
2402 free(path);
2403 }
2404 pthread_rwlock_unlock(&f->tree_lock);
2405 return err;
2406 }
2407
fuse_lib_listxattr(fuse_req_t req,fuse_ino_t ino,size_t size)2408 static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
2409 {
2410 struct fuse *f = req_fuse_prepare(req);
2411 int res;
2412
2413 if (size) {
2414 char *list = (char *) malloc(size);
2415 if (list == NULL) {
2416 reply_err(req, -ENOMEM);
2417 return;
2418 }
2419 res = common_listxattr(f, req, ino, list, size);
2420 if (res > 0)
2421 fuse_reply_buf(req, list, res);
2422 else
2423 reply_err(req, res);
2424 free(list);
2425 } else {
2426 res = common_listxattr(f, req, ino, NULL, 0);
2427 if (res >= 0)
2428 fuse_reply_xattr(req, res);
2429 else
2430 reply_err(req, res);
2431 }
2432 }
2433
fuse_lib_removexattr(fuse_req_t req,fuse_ino_t ino,const char * name)2434 static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino,
2435 const char *name)
2436 {
2437 struct fuse *f = req_fuse_prepare(req);
2438 char *path;
2439 int err;
2440
2441 err = -ENOENT;
2442 pthread_rwlock_rdlock(&f->tree_lock);
2443 path = get_path(f, ino);
2444 if (path != NULL) {
2445 struct fuse_intr_data d;
2446 fuse_prepare_interrupt(f, req, &d);
2447 err = fuse_fs_removexattr(f->fs, path, name);
2448 fuse_finish_interrupt(f, req, &d);
2449 free(path);
2450 }
2451 pthread_rwlock_unlock(&f->tree_lock);
2452 reply_err(req, err);
2453 }
2454
locks_conflict(struct node * node,const struct lock * lock)2455 static struct lock *locks_conflict(struct node *node, const struct lock *lock)
2456 {
2457 struct lock *l;
2458
2459 for (l = node->locks; l; l = l->next)
2460 if (l->owner != lock->owner &&
2461 lock->start <= l->end && l->start <= lock->end &&
2462 (l->type == F_WRLCK || lock->type == F_WRLCK))
2463 break;
2464
2465 return l;
2466 }
2467
delete_lock(struct lock ** lockp)2468 static void delete_lock(struct lock **lockp)
2469 {
2470 struct lock *l = *lockp;
2471 *lockp = l->next;
2472 free(l);
2473 }
2474
insert_lock(struct lock ** pos,struct lock * lock)2475 static void insert_lock(struct lock **pos, struct lock *lock)
2476 {
2477 lock->next = *pos;
2478 *pos = lock;
2479 }
2480
locks_insert(struct node * node,struct lock * lock)2481 static int locks_insert(struct node *node, struct lock *lock)
2482 {
2483 struct lock **lp;
2484 struct lock *newl1 = NULL;
2485 struct lock *newl2 = NULL;
2486
2487 if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2488 newl1 = malloc(sizeof(struct lock));
2489 newl2 = malloc(sizeof(struct lock));
2490
2491 if (!newl1 || !newl2) {
2492 free(newl1);
2493 free(newl2);
2494 return -ENOLCK;
2495 }
2496 }
2497
2498 for (lp = &node->locks; *lp;) {
2499 struct lock *l = *lp;
2500 if (l->owner != lock->owner)
2501 goto skip;
2502
2503 if (lock->type == l->type) {
2504 if (l->end < lock->start - 1)
2505 goto skip;
2506 if (lock->end < l->start - 1)
2507 break;
2508 if (l->start <= lock->start && lock->end <= l->end)
2509 goto out;
2510 if (l->start < lock->start)
2511 lock->start = l->start;
2512 if (lock->end < l->end)
2513 lock->end = l->end;
2514 goto delete;
2515 } else {
2516 if (l->end < lock->start)
2517 goto skip;
2518 if (lock->end < l->start)
2519 break;
2520 if (lock->start <= l->start && l->end <= lock->end)
2521 goto delete;
2522 if (l->end <= lock->end) {
2523 l->end = lock->start - 1;
2524 goto skip;
2525 }
2526 if (lock->start <= l->start) {
2527 l->start = lock->end + 1;
2528 break;
2529 }
2530 *newl2 = *l;
2531 newl2->start = lock->end + 1;
2532 l->end = lock->start - 1;
2533 insert_lock(&l->next, newl2);
2534 newl2 = NULL;
2535 }
2536 skip:
2537 lp = &l->next;
2538 continue;
2539
2540 delete:
2541 delete_lock(lp);
2542 }
2543 if (lock->type != F_UNLCK) {
2544 *newl1 = *lock;
2545 insert_lock(lp, newl1);
2546 newl1 = NULL;
2547 }
2548 out:
2549 free(newl1);
2550 free(newl2);
2551 return 0;
2552 }
2553
flock_to_lock(struct flock * flock,struct lock * lock)2554 static void flock_to_lock(struct flock *flock, struct lock *lock)
2555 {
2556 memset(lock, 0, sizeof(struct lock));
2557 lock->type = flock->l_type;
2558 lock->start = flock->l_start;
2559 lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2560 lock->pid = flock->l_pid;
2561 }
2562
lock_to_flock(struct lock * lock,struct flock * flock)2563 static void lock_to_flock(struct lock *lock, struct flock *flock)
2564 {
2565 flock->l_type = lock->type;
2566 flock->l_start = lock->start;
2567 flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2568 flock->l_pid = lock->pid;
2569 }
2570
fuse_flush_common(struct fuse * f,fuse_req_t req,fuse_ino_t ino,const char * path,struct fuse_file_info * fi)2571 static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2572 const char *path, struct fuse_file_info *fi)
2573 {
2574 struct fuse_intr_data d;
2575 struct flock lock;
2576 struct lock l;
2577 int err;
2578 int errlock;
2579
2580 fuse_prepare_interrupt(f, req, &d);
2581 memset(&lock, 0, sizeof(lock));
2582 lock.l_type = F_UNLCK;
2583 lock.l_whence = SEEK_SET;
2584 err = fuse_fs_flush(f->fs, path, fi);
2585 errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock);
2586 fuse_finish_interrupt(f, req, &d);
2587
2588 if (errlock != -ENOSYS) {
2589 flock_to_lock(&lock, &l);
2590 l.owner = fi->lock_owner;
2591 pthread_mutex_lock(&f->lock);
2592 locks_insert(get_node(f, ino), &l);
2593 pthread_mutex_unlock(&f->lock);
2594
2595 /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2596 if (err == -ENOSYS)
2597 err = 0;
2598 }
2599 return err;
2600 }
2601
fuse_lib_release(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)2602 static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino,
2603 struct fuse_file_info *fi)
2604 {
2605 struct fuse *f = req_fuse_prepare(req);
2606 struct fuse_intr_data d;
2607 char *path;
2608 int err = 0;
2609
2610 pthread_rwlock_rdlock(&f->tree_lock);
2611 path = get_path(f, ino);
2612 if (f->conf.debug)
2613 fprintf(stderr, "RELEASE%s[%llu] flags: 0x%x\n",
2614 fi->flush ? "+FLUSH" : "",
2615 (unsigned long long) fi->fh, fi->flags);
2616
2617 if (fi->flush) {
2618 err = fuse_flush_common(f, req, ino, path, fi);
2619 if (err == -ENOSYS)
2620 err = 0;
2621 }
2622
2623 fuse_prepare_interrupt(f, req, &d);
2624 fuse_do_release(f, ino, path, fi);
2625 fuse_finish_interrupt(f, req, &d);
2626 free(path);
2627 pthread_rwlock_unlock(&f->tree_lock);
2628
2629 reply_err(req, err);
2630 }
2631
fuse_lib_flush(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)2632 static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
2633 struct fuse_file_info *fi)
2634 {
2635 struct fuse *f = req_fuse_prepare(req);
2636 char *path;
2637 int err;
2638
2639 pthread_rwlock_rdlock(&f->tree_lock);
2640 path = get_path(f, ino);
2641 if (path && f->conf.debug)
2642 fprintf(stderr, "FLUSH[%llu]\n", (unsigned long long) fi->fh);
2643 err = fuse_flush_common(f, req, ino, path, fi);
2644 free(path);
2645 pthread_rwlock_unlock(&f->tree_lock);
2646 reply_err(req, err);
2647 }
2648
fuse_lock_common(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi,struct flock * lock,int cmd)2649 static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2650 struct fuse_file_info *fi, struct flock *lock,
2651 int cmd)
2652 {
2653 struct fuse *f = req_fuse_prepare(req);
2654 char *path;
2655 int err;
2656
2657 err = -ENOENT;
2658 pthread_rwlock_rdlock(&f->tree_lock);
2659 path = get_path(f, ino);
2660 if (path != NULL) {
2661 struct fuse_intr_data d;
2662 fuse_prepare_interrupt(f, req, &d);
2663 err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
2664 fuse_finish_interrupt(f, req, &d);
2665 free(path);
2666 }
2667 pthread_rwlock_unlock(&f->tree_lock);
2668 return err;
2669 }
2670
fuse_lib_getlk(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi,struct flock * lock)2671 static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino,
2672 struct fuse_file_info *fi, struct flock *lock)
2673 {
2674 int err;
2675 struct lock l;
2676 struct lock *conflict;
2677 struct fuse *f = req_fuse(req);
2678
2679 flock_to_lock(lock, &l);
2680 l.owner = fi->lock_owner;
2681 pthread_mutex_lock(&f->lock);
2682 conflict = locks_conflict(get_node(f, ino), &l);
2683 if (conflict)
2684 lock_to_flock(conflict, lock);
2685 pthread_mutex_unlock(&f->lock);
2686 if (!conflict)
2687 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
2688 else
2689 err = 0;
2690
2691 if (!err)
2692 fuse_reply_lock(req, lock);
2693 else
2694 reply_err(req, err);
2695 }
2696
fuse_lib_setlk(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi,struct flock * lock,int should_sleep)2697 static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino,
2698 struct fuse_file_info *fi, struct flock *lock,
2699 int should_sleep)
2700 {
2701 int err = fuse_lock_common(req, ino, fi, lock, should_sleep ? F_SETLKW : F_SETLK);
2702 if (!err) {
2703 struct fuse *f = req_fuse(req);
2704 struct lock l;
2705 flock_to_lock(lock, &l);
2706 l.owner = fi->lock_owner;
2707 pthread_mutex_lock(&f->lock);
2708 locks_insert(get_node(f, ino), &l);
2709 pthread_mutex_unlock(&f->lock);
2710 }
2711 reply_err(req, err);
2712 }
2713
fuse_lib_bmap(fuse_req_t req,fuse_ino_t ino,size_t blocksize,uint64_t idx)2714 static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2715 uint64_t idx)
2716 {
2717 struct fuse *f = req_fuse_prepare(req);
2718 struct fuse_intr_data d;
2719 char *path;
2720 int err;
2721
2722 err = -ENOENT;
2723 pthread_rwlock_rdlock(&f->tree_lock);
2724 path = get_path(f, ino);
2725 if (path != NULL) {
2726 fuse_prepare_interrupt(f, req, &d);
2727 err = fuse_fs_bmap(f->fs, path, blocksize, &idx);
2728 fuse_finish_interrupt(f, req, &d);
2729 free(path);
2730 }
2731 pthread_rwlock_unlock(&f->tree_lock);
2732 if (!err)
2733 fuse_reply_bmap(req, idx);
2734 else
2735 reply_err(req, err);
2736 }
2737
fuse_lib_ioctl(fuse_req_t req,fuse_ino_t ino,int cmd,void * arg,struct fuse_file_info * llfi,unsigned int flags,const void * in_buf,size_t in_bufsz,size_t out_bufsz)2738 static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
2739 struct fuse_file_info *llfi, unsigned int flags,
2740 const void *in_buf, size_t in_bufsz,
2741 size_t out_bufsz)
2742 {
2743 struct fuse *f = req_fuse_prepare(req);
2744 struct fuse_intr_data d;
2745 struct fuse_file_info fi;
2746 char *path, *out_buf = NULL;
2747 int err;
2748
2749 err = -EPERM;
2750 if (flags & FUSE_IOCTL_UNRESTRICTED)
2751 goto err;
2752
2753 if (flags & FUSE_IOCTL_DIR)
2754 get_dirhandle(llfi, &fi);
2755 else
2756 fi = *llfi;
2757
2758 if (out_bufsz) {
2759 err = -ENOMEM;
2760 out_buf = malloc(out_bufsz);
2761 if (!out_buf)
2762 goto err;
2763 }
2764
2765 assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz);
2766 if (out_buf)
2767 memcpy(out_buf, in_buf, in_bufsz);
2768
2769 path = get_path(f, ino); /* Should be get_path_nullok() */
2770 if (!path) {
2771 err = ENOENT;
2772 goto err;
2773 }
2774
2775 fuse_prepare_interrupt(f, req, &d);
2776
2777 /* Note : const qualifier dropped */
2778 err = fuse_fs_ioctl(f->fs, path, cmd, arg, &fi, flags,
2779 out_buf ? (void*)out_buf : (void*)(uintptr_t)in_buf);
2780
2781 fuse_finish_interrupt(f, req, &d);
2782 free(path);
2783
2784 if (err >= 0) { /* not an error */
2785 fuse_reply_ioctl(req, err, out_buf, out_bufsz);
2786 goto out;
2787 }
2788 err:
2789 reply_err(req, err);
2790 out:
2791 free(out_buf);
2792 }
2793
2794 static struct fuse_lowlevel_ops fuse_path_ops = {
2795 .init = fuse_lib_init,
2796 .destroy = fuse_lib_destroy,
2797 .lookup = fuse_lib_lookup,
2798 .forget = fuse_lib_forget,
2799 .getattr = fuse_lib_getattr,
2800 .setattr = fuse_lib_setattr,
2801 .access = fuse_lib_access,
2802 .readlink = fuse_lib_readlink,
2803 .mknod = fuse_lib_mknod,
2804 .mkdir = fuse_lib_mkdir,
2805 .unlink = fuse_lib_unlink,
2806 .rmdir = fuse_lib_rmdir,
2807 .symlink = fuse_lib_symlink,
2808 .rename = fuse_lib_rename,
2809 .link = fuse_lib_link,
2810 .create = fuse_lib_create,
2811 .open = fuse_lib_open,
2812 .read = fuse_lib_read,
2813 .write = fuse_lib_write,
2814 .flush = fuse_lib_flush,
2815 .release = fuse_lib_release,
2816 .fsync = fuse_lib_fsync,
2817 .opendir = fuse_lib_opendir,
2818 .readdir = fuse_lib_readdir,
2819 .releasedir = fuse_lib_releasedir,
2820 .fsyncdir = fuse_lib_fsyncdir,
2821 .statfs = fuse_lib_statfs,
2822 .setxattr = fuse_lib_setxattr,
2823 .getxattr = fuse_lib_getxattr,
2824 .listxattr = fuse_lib_listxattr,
2825 .removexattr = fuse_lib_removexattr,
2826 .getlk = fuse_lib_getlk,
2827 .setlk = fuse_lib_setlk,
2828 .bmap = fuse_lib_bmap,
2829 .ioctl = fuse_lib_ioctl,
2830 };
2831
fuse_get_session(struct fuse * f)2832 struct fuse_session *fuse_get_session(struct fuse *f)
2833 {
2834 return f->se;
2835 }
2836
fuse_loop(struct fuse * f)2837 int fuse_loop(struct fuse *f)
2838 {
2839 if (f)
2840 return fuse_session_loop(f->se);
2841 else
2842 return -1;
2843 }
2844
fuse_exit(struct fuse * f)2845 void fuse_exit(struct fuse *f)
2846 {
2847 fuse_session_exit(f->se);
2848 }
2849
fuse_get_context(void)2850 struct fuse_context *fuse_get_context(void)
2851 {
2852 return &fuse_get_context_internal()->ctx;
2853 }
2854
fuse_interrupted(void)2855 int fuse_interrupted(void)
2856 {
2857 return fuse_req_interrupted(fuse_get_context_internal()->req);
2858 }
2859
2860 enum {
2861 KEY_HELP,
2862 };
2863
2864 #define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2865
2866 static const struct fuse_opt fuse_lib_opts[] = {
2867 FUSE_OPT_KEY("-h", KEY_HELP),
2868 FUSE_OPT_KEY("--help", KEY_HELP),
2869 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
2870 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
2871 FUSE_LIB_OPT("debug", debug, 1),
2872 FUSE_LIB_OPT("-d", debug, 1),
2873 FUSE_LIB_OPT("hard_remove", hard_remove, 1),
2874 FUSE_LIB_OPT("use_ino", use_ino, 1),
2875 FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
2876 FUSE_LIB_OPT("direct_io", direct_io, 1),
2877 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
2878 #ifdef __SOLARIS__
2879 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
2880 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
2881 #endif /* __SOLARIS__ */
2882 FUSE_LIB_OPT("umask=", set_mode, 1),
2883 FUSE_LIB_OPT("umask=%o", umask, 0),
2884 FUSE_LIB_OPT("uid=", set_uid, 1),
2885 FUSE_LIB_OPT("uid=%d", uid, 0),
2886 FUSE_LIB_OPT("gid=", set_gid, 1),
2887 FUSE_LIB_OPT("gid=%d", gid, 0),
2888 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
2889 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
2890 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
2891 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
2892 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
2893 FUSE_LIB_OPT("intr", intr, 1),
2894 FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
2895 #ifdef __SOLARIS__
2896 FUSE_LIB_OPT("modules=%s", modules, 0),
2897 #endif /* __SOLARIS__ */
2898 FUSE_OPT_END
2899 };
2900
fuse_lib_help(void)2901 static void fuse_lib_help(void)
2902 {
2903 fprintf(stderr,
2904 " -o hard_remove immediate removal (don't hide files)\n"
2905 " -o use_ino let filesystem set inode numbers\n"
2906 " -o readdir_ino try to fill in d_ino in readdir\n"
2907 " -o direct_io use direct I/O\n"
2908 " -o kernel_cache cache files in kernel\n"
2909 #ifdef __SOLARIS__
2910 " -o [no]auto_cache enable caching based on modification times (off)\n"
2911 #endif /* __SOLARIS__ */
2912 " -o umask=M set file permissions (octal)\n"
2913 " -o uid=N set file owner\n"
2914 " -o gid=N set file group\n"
2915 " -o entry_timeout=T cache timeout for names (1.0s)\n"
2916 " -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
2917 " -o attr_timeout=T cache timeout for attributes (1.0s)\n"
2918 " -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
2919 " -o intr allow requests to be interrupted\n"
2920 " -o intr_signal=NUM signal to send on interrupt (%i)\n"
2921 #ifdef __SOLARIS__
2922 " -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"
2923 #endif /* __SOLARIS__ */
2924 "\n", FUSE_DEFAULT_INTR_SIGNAL);
2925 }
2926
2927 #ifdef __SOLARIS__
2928
fuse_lib_help_modules(void)2929 static void fuse_lib_help_modules(void)
2930 {
2931 struct fuse_module *m;
2932 fprintf(stderr, "\nModule options:\n");
2933 pthread_mutex_lock(&fuse_context_lock);
2934 for (m = fuse_modules; m; m = m->next) {
2935 struct fuse_fs *fs = NULL;
2936 struct fuse_fs *newfs;
2937 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2938 if (fuse_opt_add_arg(&args, "") != -1 &&
2939 fuse_opt_add_arg(&args, "-h") != -1) {
2940 fprintf(stderr, "\n[%s]\n", m->name);
2941 newfs = m->factory(&args, &fs);
2942 assert(newfs == NULL);
2943 }
2944 fuse_opt_free_args(&args);
2945 }
2946 pthread_mutex_unlock(&fuse_context_lock);
2947 }
2948
fuse_is_lib_option(const char * opt)2949 int fuse_is_lib_option(const char *opt)
2950 {
2951 return fuse_lowlevel_is_lib_option(opt) ||
2952 fuse_opt_match(fuse_lib_opts, opt);
2953 }
2954
2955 #endif /* __SOLARIS__ */
2956
fuse_lib_opt_proc(void * data,const char * arg,int key,struct fuse_args * outargs)2957 static int fuse_lib_opt_proc(void *data, const char *arg, int key,
2958 struct fuse_args *outargs)
2959 {
2960 (void) arg; (void) outargs;
2961
2962 if (key == KEY_HELP) {
2963 struct fuse_config *conf = (struct fuse_config *) data;
2964 fuse_lib_help();
2965 conf->help = 1;
2966 }
2967
2968 return 1;
2969 }
2970
fuse_init_intr_signal(int signum,int * installed)2971 static int fuse_init_intr_signal(int signum, int *installed)
2972 {
2973 struct sigaction old_sa;
2974
2975 if (sigaction(signum, NULL, &old_sa) == -1) {
2976 perror("fuse: cannot get old signal handler");
2977 return -1;
2978 }
2979
2980 if (old_sa.sa_handler == SIG_DFL) {
2981 struct sigaction sa;
2982
2983 memset(&sa, 0, sizeof(struct sigaction));
2984 sa.sa_handler = fuse_intr_sighandler;
2985 sigemptyset(&sa.sa_mask);
2986
2987 if (sigaction(signum, &sa, NULL) == -1) {
2988 perror("fuse: cannot set interrupt signal handler");
2989 return -1;
2990 }
2991 *installed = 1;
2992 }
2993 return 0;
2994 }
2995
fuse_restore_intr_signal(int signum)2996 static void fuse_restore_intr_signal(int signum)
2997 {
2998 struct sigaction sa;
2999
3000 memset(&sa, 0, sizeof(struct sigaction));
3001 sa.sa_handler = SIG_DFL;
3002 sigaction(signum, &sa, NULL);
3003 }
3004
3005 #ifdef __SOLARIS__
3006
fuse_push_module(struct fuse * f,const char * module,struct fuse_args * args)3007 static int fuse_push_module(struct fuse *f, const char *module,
3008 struct fuse_args *args)
3009 {
3010 struct fuse_fs *newfs;
3011 struct fuse_module *m = fuse_get_module(module);
3012 struct fuse_fs *fs[2];
3013
3014 fs[0] = f->fs;
3015 fs[1] = NULL;
3016 if (!m)
3017 return -1;
3018
3019 newfs = m->factory(args, fs);
3020 if (!newfs) {
3021 fuse_put_module(m);
3022 return -1;
3023 }
3024 newfs->m = m;
3025 f->fs = newfs;
3026 return 0;
3027 }
3028
3029 #endif /* __SOLARIS__ */
3030
fuse_fs_new(const struct fuse_operations * op,size_t op_size,void * user_data)3031 struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
3032 void *user_data)
3033 {
3034 struct fuse_fs *fs;
3035
3036 if (sizeof(struct fuse_operations) < op_size) {
3037 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
3038 op_size = sizeof(struct fuse_operations);
3039 }
3040
3041 fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs));
3042 if (!fs) {
3043 fprintf(stderr, "fuse: failed to allocate fuse_fs object\n");
3044 return NULL;
3045 }
3046
3047 fs->user_data = user_data;
3048 if (op)
3049 memcpy(&fs->op, op, op_size);
3050 return fs;
3051 }
3052
fuse_new(struct fuse_chan * ch,struct fuse_args * args,const struct fuse_operations * op,size_t op_size,void * user_data)3053 struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
3054 const struct fuse_operations *op, size_t op_size,
3055 void *user_data)
3056 {
3057 struct fuse *f;
3058 struct node *root;
3059 struct fuse_fs *fs;
3060 struct fuse_lowlevel_ops llop = fuse_path_ops;
3061
3062 if (fuse_create_context_key() == -1)
3063 goto out;
3064
3065 f = (struct fuse *) calloc(1, sizeof(struct fuse));
3066 if (f == NULL) {
3067 fprintf(stderr, "fuse: failed to allocate fuse object\n");
3068 goto out_delete_context_key;
3069 }
3070
3071 fs = fuse_fs_new(op, op_size, user_data);
3072 if (!fs)
3073 goto out_free;
3074
3075 f->fs = fs;
3076
3077 /* Oh f**k, this is ugly! */
3078 if (!fs->op.lock) {
3079 llop.getlk = NULL;
3080 llop.setlk = NULL;
3081 }
3082
3083 f->conf.entry_timeout = 1.0;
3084 f->conf.attr_timeout = 1.0;
3085 f->conf.negative_timeout = 0.0;
3086 f->conf.hard_remove = 1;
3087 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
3088
3089 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
3090 goto out_free_fs;
3091
3092 #ifdef __SOLARIS__
3093 if (f->conf.modules) {
3094 char *module;
3095 char *next;
3096
3097 for (module = f->conf.modules; module; module = next) {
3098 char *p;
3099 for (p = module; *p && *p != ':'; p++);
3100 next = *p ? p + 1 : NULL;
3101 *p = '\0';
3102 if (module[0] && fuse_push_module(f, module, args) == -1)
3103 goto out_free_fs;
3104 }
3105 }
3106 #endif /* __SOLARIS__ */
3107
3108 if (!f->conf.ac_attr_timeout_set)
3109 f->conf.ac_attr_timeout = f->conf.attr_timeout;
3110
3111 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
3112 /*
3113 * In FreeBSD, we always use these settings as inode numbers are needed to
3114 * make getcwd(3) work.
3115 */
3116 f->conf.readdir_ino = 1;
3117 #endif
3118
3119 f->se = fuse_lowlevel_new(args, &llop, sizeof(llop), f);
3120
3121 if (f->se == NULL) {
3122 #ifdef __SOLARIS__
3123 if (f->conf.help)
3124 fuse_lib_help_modules();
3125 #endif /* __SOLARIS__ */
3126 goto out_free_fs;
3127 }
3128
3129 fuse_session_add_chan(f->se, ch);
3130
3131 f->ctr = 0;
3132 f->generation = 0;
3133 /* FIXME: Dynamic hash table */
3134 f->name_table_size = 14057;
3135 f->name_table = (struct node **)
3136 calloc(1, sizeof(struct node *) * f->name_table_size);
3137 if (f->name_table == NULL) {
3138 fprintf(stderr, "fuse: memory allocation failed\n");
3139 goto out_free_session;
3140 }
3141
3142 f->id_table_size = 14057;
3143 f->id_table = (struct node **)
3144 calloc(1, sizeof(struct node *) * f->id_table_size);
3145 if (f->id_table == NULL) {
3146 fprintf(stderr, "fuse: memory allocation failed\n");
3147 goto out_free_name_table;
3148 }
3149
3150 fuse_mutex_init(&f->lock);
3151 pthread_rwlock_init(&f->tree_lock, NULL);
3152
3153 root = (struct node *) calloc(1, sizeof(struct node));
3154 if (root == NULL) {
3155 fprintf(stderr, "fuse: memory allocation failed\n");
3156 goto out_free_id_table;
3157 }
3158
3159 root->name = strdup("/");
3160 if (root->name == NULL) {
3161 fprintf(stderr, "fuse: memory allocation failed\n");
3162 goto out_free_root;
3163 }
3164
3165 if (f->conf.intr &&
3166 fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
3167 goto out_free_root_name;
3168
3169 root->parent = NULL;
3170 root->nodeid = FUSE_ROOT_ID;
3171 root->generation = 0;
3172 root->refctr = 1;
3173 root->nlookup = 1;
3174 hash_id(f, root);
3175
3176 return f;
3177
3178 out_free_root_name:
3179 free(root->name);
3180 out_free_root:
3181 free(root);
3182 out_free_id_table:
3183 free(f->id_table);
3184 out_free_name_table:
3185 free(f->name_table);
3186 out_free_session:
3187 fuse_session_destroy(f->se);
3188 out_free_fs:
3189 /* Horrible compatibility hack to stop the destructor from being
3190 called on the filesystem without init being called first */
3191 fs->op.destroy = NULL;
3192 fuse_fs_destroy(f->fs);
3193 #ifdef __SOLARIS__
3194 free(f->conf.modules);
3195 #endif /* __SOLARIS__ */
3196 out_free:
3197 free(f);
3198 out_delete_context_key:
3199 fuse_delete_context_key();
3200 out:
3201 return NULL;
3202 }
3203
fuse_destroy(struct fuse * f)3204 void fuse_destroy(struct fuse *f)
3205 {
3206 size_t i;
3207
3208 if (f->conf.intr && f->intr_installed)
3209 fuse_restore_intr_signal(f->conf.intr_signal);
3210
3211 if (f->fs) {
3212 struct fuse_context_i *c = fuse_get_context_internal();
3213
3214 memset(c, 0, sizeof(*c));
3215 c->ctx.fuse = f;
3216
3217 for (i = 0; i < f->id_table_size; i++) {
3218 struct node *node;
3219
3220 for (node = f->id_table[i]; node != NULL; node = node->id_next) {
3221 if (node->is_hidden) {
3222 char *path = get_path(f, node->nodeid);
3223 if (path) {
3224 fuse_fs_unlink(f->fs, path);
3225 free(path);
3226 }
3227 }
3228 }
3229 }
3230 }
3231 for (i = 0; i < f->id_table_size; i++) {
3232 struct node *node;
3233 struct node *next;
3234
3235 for (node = f->id_table[i]; node != NULL; node = next) {
3236 next = node->id_next;
3237 free_node(node);
3238 }
3239 }
3240 free(f->id_table);
3241 free(f->name_table);
3242 pthread_mutex_destroy(&f->lock);
3243 pthread_rwlock_destroy(&f->tree_lock);
3244 fuse_session_destroy(f->se);
3245 #ifdef __SOLARIS__
3246 free(f->conf.modules);
3247 #endif /* __SOLARIS__ */
3248 free(f);
3249 fuse_delete_context_key();
3250 }
3251