• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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