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