diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/fuse.c | 4987 | ||||
-rw-r--r-- | lib/fuse_i.h | 22 | ||||
-rw-r--r-- | lib/fuse_kern_chan.c | 118 | ||||
-rw-r--r-- | lib/fuse_loop.c | 48 | ||||
-rw-r--r-- | lib/fuse_loop_mt.c | 347 | ||||
-rw-r--r-- | lib/fuse_lowlevel.c | 1791 | ||||
-rw-r--r-- | lib/fuse_misc.h | 18 | ||||
-rw-r--r-- | lib/fuse_mt.c | 136 | ||||
-rw-r--r-- | lib/fuse_opt.c | 528 | ||||
-rw-r--r-- | lib/fuse_session.c | 185 | ||||
-rw-r--r-- | lib/fuse_signals.c | 78 | ||||
-rw-r--r-- | lib/helper.c | 568 | ||||
-rw-r--r-- | lib/modules/iconv.c | 1021 | ||||
-rw-r--r-- | lib/modules/subdir.c | 913 | ||||
-rw-r--r-- | lib/mount.c | 966 | ||||
-rw-r--r-- | lib/mount_bsd.c | 560 | ||||
-rw-r--r-- | lib/mount_util.c | 397 | ||||
-rw-r--r-- | lib/mount_util.h | 12 | ||||
-rw-r--r-- | lib/ulockmgr.c | 702 |
19 files changed, 6737 insertions, 6660 deletions
@@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ @@ -40,109 +40,109 @@ #define OFFSET_MAX 0x7fffffffffffffffLL struct fuse_config { - unsigned int uid; - unsigned int gid; - unsigned int umask; - double entry_timeout; - double negative_timeout; - double attr_timeout; - double ac_attr_timeout; - int ac_attr_timeout_set; - int debug; - int hard_remove; - int use_ino; - int readdir_ino; - int set_mode; - int set_uid; - int set_gid; - int direct_io; - int kernel_cache; - int auto_cache; - int intr; - int intr_signal; - int help; - char *modules; + unsigned int uid; + unsigned int gid; + unsigned int umask; + double entry_timeout; + double negative_timeout; + double attr_timeout; + double ac_attr_timeout; + int ac_attr_timeout_set; + int debug; + int hard_remove; + int use_ino; + int readdir_ino; + int set_mode; + int set_uid; + int set_gid; + int direct_io; + int kernel_cache; + int auto_cache; + int intr; + int intr_signal; + int help; + char *modules; }; struct fuse_fs { - struct fuse_operations op; - struct fuse_module *m; - void *user_data; - int compat; + struct fuse_operations op; + struct fuse_module *m; + void *user_data; + int compat; }; struct fusemod_so { - void *handle; - int ctr; + void *handle; + int ctr; }; struct fuse { - struct fuse_session *se; - struct node **name_table; - size_t name_table_size; - struct node **id_table; - size_t id_table_size; - fuse_ino_t ctr; - unsigned int generation; - unsigned int hidectr; - pthread_mutex_t lock; - pthread_rwlock_t tree_lock; - struct fuse_config conf; - int intr_installed; - struct fuse_fs *fs; + struct fuse_session *se; + struct node **name_table; + size_t name_table_size; + struct node **id_table; + size_t id_table_size; + fuse_ino_t ctr; + unsigned int generation; + unsigned int hidectr; + pthread_mutex_t lock; + pthread_rwlock_t tree_lock; + struct fuse_config conf; + int intr_installed; + struct fuse_fs *fs; }; struct lock { - int type; - off_t start; - off_t end; - pid_t pid; - uint64_t owner; - struct lock *next; + int type; + off_t start; + off_t end; + pid_t pid; + uint64_t owner; + struct lock *next; }; struct node { - struct node *name_next; - struct node *id_next; - fuse_ino_t nodeid; - unsigned int generation; - int refctr; - struct node *parent; - char *name; - uint64_t nlookup; - int open_count; - int is_hidden; - struct timespec stat_updated; - struct timespec mtime; - off_t size; - int cache_valid; - struct lock *locks; + struct node *name_next; + struct node *id_next; + fuse_ino_t nodeid; + unsigned int generation; + int refctr; + struct node *parent; + char *name; + uint64_t nlookup; + int open_count; + int is_hidden; + struct timespec stat_updated; + struct timespec mtime; + off_t size; + int cache_valid; + struct lock *locks; }; struct fuse_dh { - pthread_mutex_t lock; - struct fuse *fuse; - fuse_req_t req; - char *contents; - int allocated; - unsigned len; - unsigned size; - unsigned needlen; - int filled; - uint64_t fh; - int error; - fuse_ino_t nodeid; + pthread_mutex_t lock; + struct fuse *fuse; + fuse_req_t req; + char *contents; + int allocated; + unsigned len; + unsigned size; + unsigned needlen; + int filled; + uint64_t fh; + int error; + fuse_ino_t nodeid; }; /* old dir handle */ struct fuse_dirhandle { - fuse_fill_dir_t filler; - void *buf; + fuse_fill_dir_t filler; + void *buf; }; struct fuse_context_i { - struct fuse_context ctx; - fuse_req_t req; + struct fuse_context ctx; + fuse_req_t req; }; static pthread_key_t fuse_context_key; @@ -153,1017 +153,1025 @@ static struct fuse_module *fuse_modules; static int fuse_load_so_name(const char *soname) { - struct fusemod_so *so; - - so = calloc(1, sizeof(struct fusemod_so)); - if (!so) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - - fuse_current_so = so; - so->handle = dlopen(soname, RTLD_NOW); - fuse_current_so = NULL; - if (!so->handle) { - fprintf(stderr, "fuse: %s\n", dlerror()); - goto err; - } - if (!so->ctr) { - fprintf(stderr, "fuse: %s did not register any modules", soname); - goto err; - } - return 0; - - err: - if (so->handle) - dlclose(so->handle); - free(so); - return -1; + struct fusemod_so *so; + + so = calloc(1, sizeof(struct fusemod_so)); + if (!so) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + + fuse_current_so = so; + so->handle = dlopen(soname, RTLD_NOW); + fuse_current_so = NULL; + if (!so->handle) { + fprintf(stderr, "fuse: %s\n", dlerror()); + goto err; + } + if (!so->ctr) { + fprintf(stderr, "fuse: %s did not register any modules", + soname); + goto err; + } + return 0; + +err: + if (so->handle) + dlclose(so->handle); + free(so); + return -1; } static int fuse_load_so_module(const char *module) { - int res; - char *soname = malloc(strlen(module) + 64); - if (!soname) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - sprintf(soname, "libfusemod_%s.so", module); - res = fuse_load_so_name(soname); - free(soname); - return res; + int res; + char *soname = malloc(strlen(module) + 64); + if (!soname) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + sprintf(soname, "libfusemod_%s.so", module); + res = fuse_load_so_name(soname); + free(soname); + return res; } static struct fuse_module *fuse_find_module(const char *module) { - struct fuse_module *m; - for (m = fuse_modules; m; m = m->next) { - if (strcmp(module, m->name) == 0) { - m->ctr++; - break; - } - } - return m; + struct fuse_module *m; + for (m = fuse_modules; m; m = m->next) { + if (strcmp(module, m->name) == 0) { + m->ctr++; + break; + } + } + return m; } static struct fuse_module *fuse_get_module(const char *module) { - struct fuse_module *m; + struct fuse_module *m; - pthread_mutex_lock(&fuse_context_lock); - m = fuse_find_module(module); - if (!m) { - int err = fuse_load_so_module(module); - if (!err) - m = fuse_find_module(module); - } - pthread_mutex_unlock(&fuse_context_lock); - return m; + pthread_mutex_lock(&fuse_context_lock); + m = fuse_find_module(module); + if (!m) { + int err = fuse_load_so_module(module); + if (!err) + m = fuse_find_module(module); + } + pthread_mutex_unlock(&fuse_context_lock); + return m; } static void fuse_put_module(struct fuse_module *m) { - pthread_mutex_lock(&fuse_context_lock); - assert(m->ctr > 0); - m->ctr--; - if (!m->ctr && m->so) { - struct fusemod_so *so = m->so; - assert(so->ctr > 0); - so->ctr--; - if (!so->ctr) { - struct fuse_module **mp; - for (mp = &fuse_modules; *mp;) { - if ((*mp)->so == so) - *mp = (*mp)->next; - else - mp = &(*mp)->next; - } - dlclose(so->handle); - free(so); - } - } - pthread_mutex_unlock(&fuse_context_lock); + pthread_mutex_lock(&fuse_context_lock); + assert(m->ctr > 0); + m->ctr--; + if (!m->ctr && m->so) { + struct fusemod_so *so = m->so; + assert(so->ctr > 0); + so->ctr--; + if (!so->ctr) { + struct fuse_module **mp; + for (mp = &fuse_modules; *mp;) { + if ((*mp)->so == so) + *mp = (*mp)->next; + else + mp = &(*mp)->next; + } + dlclose(so->handle); + free(so); + } + } + pthread_mutex_unlock(&fuse_context_lock); } static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid) { - size_t hash = nodeid % f->id_table_size; - struct node *node; + size_t hash = nodeid % f->id_table_size; + struct node *node; - for (node = f->id_table[hash]; node != NULL; node = node->id_next) - if (node->nodeid == nodeid) - return node; + for (node = f->id_table[hash]; node != NULL; node = node->id_next) + if (node->nodeid == nodeid) + return node; - return NULL; + return NULL; } static struct node *get_node(struct fuse *f, fuse_ino_t nodeid) { - struct node *node = get_node_nocheck(f, nodeid); - if (!node) { - fprintf(stderr, "fuse internal error: node %llu not found\n", - (unsigned long long) nodeid); - abort(); - } - return node; + struct node *node = get_node_nocheck(f, nodeid); + if (!node) { + fprintf(stderr, "fuse internal error: node %llu not found\n", + (unsigned long long) nodeid); + abort(); + } + return node; } static void free_node(struct node *node) { - free(node->name); - free(node); + free(node->name); + free(node); } static void unhash_id(struct fuse *f, struct node *node) { - size_t hash = node->nodeid % f->id_table_size; - struct node **nodep = &f->id_table[hash]; + size_t hash = node->nodeid % f->id_table_size; + struct node **nodep = &f->id_table[hash]; - for (; *nodep != NULL; nodep = &(*nodep)->id_next) - if (*nodep == node) { - *nodep = node->id_next; - return; - } + for (; *nodep != NULL; nodep = &(*nodep)->id_next) + if (*nodep == node) { + *nodep = node->id_next; + return; + } } static void hash_id(struct fuse *f, struct node *node) { - size_t hash = node->nodeid % f->id_table_size; - node->id_next = f->id_table[hash]; - f->id_table[hash] = node; + size_t hash = node->nodeid % f->id_table_size; + node->id_next = f->id_table[hash]; + f->id_table[hash] = node; } static unsigned int name_hash(struct fuse *f, fuse_ino_t parent, - const char *name) + const char *name) { - unsigned int hash = *name; + unsigned int hash = *name; - if (hash) - for (name += 1; *name != '\0'; name++) - hash = (hash << 5) - hash + *name; + if (hash) + for (name += 1; *name != '\0'; name++) + hash = (hash << 5) - hash + *name; - return (hash + parent) % f->name_table_size; + return (hash + parent) % f->name_table_size; } static void unref_node(struct fuse *f, struct node *node); static void unhash_name(struct fuse *f, struct node *node) { - if (node->name) { - size_t hash = name_hash(f, node->parent->nodeid, node->name); - struct node **nodep = &f->name_table[hash]; - - for (; *nodep != NULL; nodep = &(*nodep)->name_next) - if (*nodep == node) { - *nodep = node->name_next; - node->name_next = NULL; - unref_node(f, node->parent); - free(node->name); - node->name = NULL; - node->parent = NULL; - return; - } - fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n", - (unsigned long long) node->nodeid); - abort(); - } + if (node->name) { + size_t hash = name_hash(f, node->parent->nodeid, node->name); + struct node **nodep = &f->name_table[hash]; + + for (; *nodep != NULL; nodep = &(*nodep)->name_next) + if (*nodep == node) { + *nodep = node->name_next; + node->name_next = NULL; + unref_node(f, node->parent); + free(node->name); + node->name = NULL; + node->parent = NULL; + return; + } + fprintf(stderr, + "fuse internal error: unable to unhash node: %llu\n", + (unsigned long long) node->nodeid); + abort(); + } } static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid, - const char *name) + const char *name) { - size_t hash = name_hash(f, parentid, name); - struct node *parent = get_node(f, parentid); - node->name = strdup(name); - if (node->name == NULL) - return -1; + size_t hash = name_hash(f, parentid, name); + struct node *parent = get_node(f, parentid); + node->name = strdup(name); + if (node->name == NULL) + return -1; - parent->refctr ++; - node->parent = parent; - node->name_next = f->name_table[hash]; - f->name_table[hash] = node; - return 0; + parent->refctr ++; + node->parent = parent; + node->name_next = f->name_table[hash]; + f->name_table[hash] = node; + return 0; } static void delete_node(struct fuse *f, struct node *node) { - if (f->conf.debug) - fprintf(stderr, "delete: %llu\n", (unsigned long long) node->nodeid); + if (f->conf.debug) + fprintf(stderr, "delete: %llu\n", + (unsigned long long) node->nodeid); - assert(!node->name); - unhash_id(f, node); - free_node(node); + assert(!node->name); + unhash_id(f, node); + free_node(node); } static void unref_node(struct fuse *f, struct node *node) { - assert(node->refctr > 0); - node->refctr --; - if (!node->refctr) - delete_node(f, node); + assert(node->refctr > 0); + node->refctr --; + if (!node->refctr) + delete_node(f, node); } static fuse_ino_t next_id(struct fuse *f) { - do { - f->ctr = (f->ctr + 1) & 0xffffffff; - if (!f->ctr) - f->generation ++; - } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO || - get_node_nocheck(f, f->ctr) != NULL); - return f->ctr; + do { + f->ctr = (f->ctr + 1) & 0xffffffff; + if (!f->ctr) + f->generation ++; + } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO || + get_node_nocheck(f, f->ctr) != NULL); + return f->ctr; } static struct node *lookup_node(struct fuse *f, fuse_ino_t parent, - const char *name) + const char *name) { - size_t hash = name_hash(f, parent, name); - struct node *node; + size_t hash = name_hash(f, parent, name); + struct node *node; - for (node = f->name_table[hash]; node != NULL; node = node->name_next) - if (node->parent->nodeid == parent && strcmp(node->name, name) == 0) - return node; + for (node = f->name_table[hash]; node != NULL; node = node->name_next) + if (node->parent->nodeid == parent && + strcmp(node->name, name) == 0) + return node; - return NULL; + return NULL; } static struct node *find_node(struct fuse *f, fuse_ino_t parent, - const char *name) -{ - struct node *node; - - pthread_mutex_lock(&f->lock); - node = lookup_node(f, parent, name); - if (node == NULL) { - node = (struct node *) calloc(1, sizeof(struct node)); - if (node == NULL) - goto out_err; - - node->refctr = 1; - node->nodeid = next_id(f); - node->open_count = 0; - node->is_hidden = 0; - node->generation = f->generation; - if (hash_name(f, node, parent, name) == -1) { - free(node); - node = NULL; - goto out_err; - } - hash_id(f, node); - } - node->nlookup ++; - out_err: - pthread_mutex_unlock(&f->lock); - return node; + const char *name) +{ + struct node *node; + + pthread_mutex_lock(&f->lock); + node = lookup_node(f, parent, name); + if (node == NULL) { + node = (struct node *) calloc(1, sizeof(struct node)); + if (node == NULL) + goto out_err; + + node->refctr = 1; + node->nodeid = next_id(f); + node->open_count = 0; + node->is_hidden = 0; + node->generation = f->generation; + if (hash_name(f, node, parent, name) == -1) { + free(node); + node = NULL; + goto out_err; + } + hash_id(f, node); + } + node->nlookup ++; +out_err: + pthread_mutex_unlock(&f->lock); + return node; } static char *add_name(char *buf, char *s, const char *name) { - size_t len = strlen(name); - s -= len; - if (s <= buf) { - fprintf(stderr, "fuse: path too long: ...%s\n", s + len); - return NULL; - } - strncpy(s, name, len); - s--; - *s = '/'; + size_t len = strlen(name); + s -= len; + if (s <= buf) { + fprintf(stderr, "fuse: path too long: ...%s\n", s + len); + return NULL; + } + strncpy(s, name, len); + s--; + *s = '/'; - return s; + return s; } static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name) { - char buf[FUSE_MAX_PATH]; - char *s = buf + FUSE_MAX_PATH - 1; - struct node *node; + char buf[FUSE_MAX_PATH]; + char *s = buf + FUSE_MAX_PATH - 1; + struct node *node; - *s = '\0'; + *s = '\0'; - if (name != NULL) { - s = add_name(buf, s, name); - if (s == NULL) - return NULL; - } + if (name != NULL) { + s = add_name(buf, s, name); + if (s == NULL) + return NULL; + } - pthread_mutex_lock(&f->lock); - for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID; - node = node->parent) { - if (node->name == NULL) { - s = NULL; - break; - } + pthread_mutex_lock(&f->lock); + for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID; + node = node->parent) { + if (node->name == NULL) { + s = NULL; + break; + } - s = add_name(buf, s, node->name); - if (s == NULL) - break; - } - pthread_mutex_unlock(&f->lock); + s = add_name(buf, s, node->name); + if (s == NULL) + break; + } + pthread_mutex_unlock(&f->lock); - if (node == NULL || s == NULL) - return NULL; - else if (*s == '\0') - return strdup("/"); - else - return strdup(s); + if (node == NULL || s == NULL) + return NULL; + else if (*s == '\0') + return strdup("/"); + else + return strdup(s); } static char *get_path(struct fuse *f, fuse_ino_t nodeid) { - return get_path_name(f, nodeid, NULL); + return get_path_name(f, nodeid, NULL); } static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup) { - struct node *node; - if (nodeid == FUSE_ROOT_ID) - return; - pthread_mutex_lock(&f->lock); - node = get_node(f, nodeid); - assert(node->nlookup >= nlookup); - node->nlookup -= nlookup; - if (!node->nlookup) { - unhash_name(f, node); - unref_node(f, node); - } - pthread_mutex_unlock(&f->lock); + struct node *node; + if (nodeid == FUSE_ROOT_ID) + return; + pthread_mutex_lock(&f->lock); + node = get_node(f, nodeid); + assert(node->nlookup >= nlookup); + node->nlookup -= nlookup; + if (!node->nlookup) { + unhash_name(f, node); + unref_node(f, node); + } + pthread_mutex_unlock(&f->lock); } static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name) { - struct node *node; + struct node *node; - pthread_mutex_lock(&f->lock); - node = lookup_node(f, dir, name); - if (node != NULL) - unhash_name(f, node); - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + node = lookup_node(f, dir, name); + if (node != NULL) + unhash_name(f, node); + pthread_mutex_unlock(&f->lock); } static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname, - fuse_ino_t newdir, const char *newname, int hide) -{ - struct node *node; - struct node *newnode; - int err = 0; - - pthread_mutex_lock(&f->lock); - node = lookup_node(f, olddir, oldname); - newnode = lookup_node(f, newdir, newname); - if (node == NULL) - goto out; - - if (newnode != NULL) { - if (hide) { - fprintf(stderr, "fuse: hidden file got created during hiding\n"); - err = -EBUSY; - goto out; - } - unhash_name(f, newnode); - } - - unhash_name(f, node); - if (hash_name(f, node, newdir, newname) == -1) { - err = -ENOMEM; - goto out; - } - - if (hide) - node->is_hidden = 1; + fuse_ino_t newdir, const char *newname, int hide) +{ + struct node *node; + struct node *newnode; + int err = 0; + + pthread_mutex_lock(&f->lock); + node = lookup_node(f, olddir, oldname); + newnode = lookup_node(f, newdir, newname); + if (node == NULL) + goto out; + + if (newnode != NULL) { + if (hide) { + fprintf(stderr, "fuse: hidden file got created during hiding\n"); + err = -EBUSY; + goto out; + } + unhash_name(f, newnode); + } + + unhash_name(f, node); + if (hash_name(f, node, newdir, newname) == -1) { + err = -ENOMEM; + goto out; + } + + if (hide) + node->is_hidden = 1; - out: - pthread_mutex_unlock(&f->lock); - return err; +out: + pthread_mutex_unlock(&f->lock); + return err; } static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf) { - if (!f->conf.use_ino) - stbuf->st_ino = nodeid; - if (f->conf.set_mode) - stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask); - if (f->conf.set_uid) - stbuf->st_uid = f->conf.uid; - if (f->conf.set_gid) - stbuf->st_gid = f->conf.gid; + if (!f->conf.use_ino) + stbuf->st_ino = nodeid; + if (f->conf.set_mode) + stbuf->st_mode = (stbuf->st_mode & S_IFMT) | + (0777 & ~f->conf.umask); + if (f->conf.set_uid) + stbuf->st_uid = f->conf.uid; + if (f->conf.set_gid) + stbuf->st_gid = f->conf.gid; } static struct fuse *req_fuse(fuse_req_t req) { - return (struct fuse *) fuse_req_userdata(req); + return (struct fuse *) fuse_req_userdata(req); } static void fuse_intr_sighandler(int sig) { - (void) sig; - /* Nothing to do */ + (void) sig; + /* Nothing to do */ } struct fuse_intr_data { - pthread_t id; - pthread_cond_t cond; - int finished; + pthread_t id; + pthread_cond_t cond; + int finished; }; static void fuse_interrupt(fuse_req_t req, void *d_) { - struct fuse_intr_data *d = d_; - struct fuse *f = req_fuse(req); + struct fuse_intr_data *d = d_; + struct fuse *f = req_fuse(req); - if (d->id == pthread_self()) - return; + if (d->id == pthread_self()) + return; - pthread_mutex_lock(&f->lock); - while (!d->finished) { - struct timeval now; - struct timespec timeout; + pthread_mutex_lock(&f->lock); + while (!d->finished) { + struct timeval now; + struct timespec timeout; - pthread_kill(d->id, f->conf.intr_signal); - gettimeofday(&now, NULL); - timeout.tv_sec = now.tv_sec + 1; - timeout.tv_nsec = now.tv_usec * 1000; - pthread_cond_timedwait(&d->cond, &f->lock, &timeout); - } - pthread_mutex_unlock(&f->lock); + pthread_kill(d->id, f->conf.intr_signal); + gettimeofday(&now, NULL); + timeout.tv_sec = now.tv_sec + 1; + timeout.tv_nsec = now.tv_usec * 1000; + pthread_cond_timedwait(&d->cond, &f->lock, &timeout); + } + pthread_mutex_unlock(&f->lock); } static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req, - struct fuse_intr_data *d) + struct fuse_intr_data *d) { - pthread_mutex_lock(&f->lock); - d->finished = 1; - pthread_cond_broadcast(&d->cond); - pthread_mutex_unlock(&f->lock); - fuse_req_interrupt_func(req, NULL, NULL); - pthread_cond_destroy(&d->cond); + pthread_mutex_lock(&f->lock); + d->finished = 1; + pthread_cond_broadcast(&d->cond); + pthread_mutex_unlock(&f->lock); + fuse_req_interrupt_func(req, NULL, NULL); + pthread_cond_destroy(&d->cond); } static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d) { - d->id = pthread_self(); - pthread_cond_init(&d->cond, NULL); - d->finished = 0; - fuse_req_interrupt_func(req, fuse_interrupt, d); + d->id = pthread_self(); + pthread_cond_init(&d->cond, NULL); + d->finished = 0; + fuse_req_interrupt_func(req, fuse_interrupt, d); } static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req, - struct fuse_intr_data *d) + struct fuse_intr_data *d) { - if (f->conf.intr) - fuse_do_finish_interrupt(f, req, d); + if (f->conf.intr) + fuse_do_finish_interrupt(f, req, d); } static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req, - struct fuse_intr_data *d) + struct fuse_intr_data *d) { - if (f->conf.intr) - fuse_do_prepare_interrupt(req, d); + if (f->conf.intr) + fuse_do_prepare_interrupt(req, d); } #ifndef __FreeBSD__ static int fuse_compat_open(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) -{ - int err; - if (!fs->compat || fs->compat >= 25) - err = fs->op.open(path, fi); - else if (fs->compat == 22) { - struct fuse_file_info_compat tmp; - memcpy(&tmp, fi, sizeof(tmp)); - err = ((struct fuse_operations_compat22 *) &fs->op)->open(path, &tmp); - memcpy(fi, &tmp, sizeof(tmp)); - fi->fh = tmp.fh; - } else - err = ((struct fuse_operations_compat2 *) &fs->op) - ->open(path, fi->flags); - return err; + struct fuse_file_info *fi) +{ + int err; + if (!fs->compat || fs->compat >= 25) + err = fs->op.open(path, fi); + else if (fs->compat == 22) { + struct fuse_file_info_compat tmp; + memcpy(&tmp, fi, sizeof(tmp)); + err = ((struct fuse_operations_compat22 *) &fs->op)->open(path, + &tmp); + memcpy(fi, &tmp, sizeof(tmp)); + fi->fh = tmp.fh; + } else + err = ((struct fuse_operations_compat2 *) &fs->op) + ->open(path, fi->flags); + return err; } static int fuse_compat_release(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - if (!fs->compat || fs->compat >= 22) - return fs->op.release(path, fi); - else - return ((struct fuse_operations_compat2 *) &fs->op) - ->release(path, fi->flags); + if (!fs->compat || fs->compat >= 22) + return fs->op.release(path, fi); + else + return ((struct fuse_operations_compat2 *) &fs->op) + ->release(path, fi->flags); } static int fuse_compat_opendir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) -{ - if (!fs->compat || fs->compat >= 25) - return fs->op.opendir(path, fi); - else { - int err; - struct fuse_file_info_compat tmp; - memcpy(&tmp, fi, sizeof(tmp)); - err = ((struct fuse_operations_compat22 *) &fs->op) - ->opendir(path, &tmp); - memcpy(fi, &tmp, sizeof(tmp)); - fi->fh = tmp.fh; - return err; - } + struct fuse_file_info *fi) +{ + if (!fs->compat || fs->compat >= 25) + return fs->op.opendir(path, fi); + else { + int err; + struct fuse_file_info_compat tmp; + memcpy(&tmp, fi, sizeof(tmp)); + err = ((struct fuse_operations_compat22 *) &fs->op) + ->opendir(path, &tmp); + memcpy(fi, &tmp, sizeof(tmp)); + fi->fh = tmp.fh; + return err; + } } static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf, - struct statvfs *stbuf) + struct statvfs *stbuf) { - stbuf->f_bsize = compatbuf->block_size; - stbuf->f_blocks = compatbuf->blocks; - stbuf->f_bfree = compatbuf->blocks_free; - stbuf->f_bavail = compatbuf->blocks_free; - stbuf->f_files = compatbuf->files; - stbuf->f_ffree = compatbuf->files_free; - stbuf->f_namemax = compatbuf->namelen; + stbuf->f_bsize = compatbuf->block_size; + stbuf->f_blocks = compatbuf->blocks; + stbuf->f_bfree = compatbuf->blocks_free; + stbuf->f_bavail = compatbuf->blocks_free; + stbuf->f_files = compatbuf->files; + stbuf->f_ffree = compatbuf->files_free; + stbuf->f_namemax = compatbuf->namelen; } static void convert_statfs_old(struct statfs *oldbuf, struct statvfs *stbuf) { - stbuf->f_bsize = oldbuf->f_bsize; - stbuf->f_blocks = oldbuf->f_blocks; - stbuf->f_bfree = oldbuf->f_bfree; - stbuf->f_bavail = oldbuf->f_bavail; - stbuf->f_files = oldbuf->f_files; - stbuf->f_ffree = oldbuf->f_ffree; - stbuf->f_namemax = oldbuf->f_namelen; + stbuf->f_bsize = oldbuf->f_bsize; + stbuf->f_blocks = oldbuf->f_blocks; + stbuf->f_bfree = oldbuf->f_bfree; + stbuf->f_bavail = oldbuf->f_bavail; + stbuf->f_files = oldbuf->f_files; + stbuf->f_ffree = oldbuf->f_ffree; + stbuf->f_namemax = oldbuf->f_namelen; } static int fuse_compat_statfs(struct fuse_fs *fs, const char *path, - struct statvfs *buf) -{ - int err; - - if (!fs->compat || fs->compat >= 25) { - err = fs->op.statfs(fs->compat == 25 ? "/" : path, buf); - } else if (fs->compat > 11) { - struct statfs oldbuf; - err = ((struct fuse_operations_compat22 *) &fs->op) - ->statfs("/", &oldbuf); - if (!err) - convert_statfs_old(&oldbuf, buf); - } else { - struct fuse_statfs_compat1 compatbuf; - memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1)); - err = ((struct fuse_operations_compat1 *) &fs->op)->statfs(&compatbuf); - if (!err) - convert_statfs_compat(&compatbuf, buf); - } - return err; + struct statvfs *buf) +{ + int err; + + if (!fs->compat || fs->compat >= 25) { + err = fs->op.statfs(fs->compat == 25 ? "/" : path, buf); + } else if (fs->compat > 11) { + struct statfs oldbuf; + err = ((struct fuse_operations_compat22 *) &fs->op) + ->statfs("/", &oldbuf); + if (!err) + convert_statfs_old(&oldbuf, buf); + } else { + struct fuse_statfs_compat1 compatbuf; + memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1)); + err = ((struct fuse_operations_compat1 *) &fs->op) + ->statfs(&compatbuf); + if (!err) + convert_statfs_compat(&compatbuf, buf); + } + return err; } #else /* __FreeBSD__ */ static inline int fuse_compat_open(struct fuse_fs *fs, char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - return fs->op.open(path, fi); + return fs->op.open(path, fi); } static inline int fuse_compat_release(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - return fs->op.release(path, fi); + return fs->op.release(path, fi); } static inline int fuse_compat_opendir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - return fs->op.opendir(path, fi); + return fs->op.opendir(path, fi); } static inline int fuse_compat_statfs(struct fuse_fs *fs, const char *path, - struct statvfs *buf) + struct statvfs *buf) { - return fs->op.statfs(fs->compat == 25 ? "/" : path, buf); + return fs->op.statfs(fs->compat == 25 ? "/" : path, buf); } #endif /* __FreeBSD__ */ int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.getattr) - return fs->op.getattr(path, buf); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.getattr) + return fs->op.getattr(path, buf); + else + return -ENOSYS; } int fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fgetattr) - return fs->op.fgetattr(path, buf, fi); - else if (fs->op.getattr) - return fs->op.getattr(path, buf); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fgetattr) + return fs->op.fgetattr(path, buf, fi); + else if (fs->op.getattr) + return fs->op.getattr(path, buf); + else + return -ENOSYS; } int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, - const char *newpath) + const char *newpath) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.rename) - return fs->op.rename(oldpath, newpath); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.rename) + return fs->op.rename(oldpath, newpath); + else + return -ENOSYS; } int fuse_fs_unlink(struct fuse_fs *fs, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.unlink) - return fs->op.unlink(path); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.unlink) + return fs->op.unlink(path); + else + return -ENOSYS; } int fuse_fs_rmdir(struct fuse_fs *fs, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.rmdir) - return fs->op.rmdir(path); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.rmdir) + return fs->op.rmdir(path); + else + return -ENOSYS; } int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.symlink) - return fs->op.symlink(linkname, path); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.symlink) + return fs->op.symlink(linkname, path); + else + return -ENOSYS; } int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.link) - return fs->op.link(oldpath, newpath); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.link) + return fs->op.link(oldpath, newpath); + else + return -ENOSYS; } -int fuse_fs_release(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) +int fuse_fs_release(struct fuse_fs *fs, const char *path, + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.release) - return fuse_compat_release(fs, path, fi); - else - return 0; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.release) + return fuse_compat_release(fs, path, fi); + else + return 0; } int fuse_fs_opendir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.opendir) - return fuse_compat_opendir(fs, path, fi); - else - return 0; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.opendir) + return fuse_compat_opendir(fs, path, fi); + else + return 0; } int fuse_fs_open(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.open) - return fuse_compat_open(fs, path, fi); - else - return 0; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.open) + return fuse_compat_open(fs, path, fi); + else + return 0; } int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size, - off_t off, struct fuse_file_info *fi) + off_t off, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.read) - return fs->op.read(path, buf, size, off, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.read) + return fs->op.read(path, buf, size, off, fi); + else + return -ENOSYS; } int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf, - size_t size, off_t off, struct fuse_file_info *fi) + size_t size, off_t off, struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.write) - return fs->op.write(path, buf, size, off, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.write) + return fs->op.write(path, buf, size, off, fi); + else + return -ENOSYS; } int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fsync) - return fs->op.fsync(path, datasync, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fsync) + return fs->op.fsync(path, datasync, fi); + else + return -ENOSYS; } int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.fsyncdir) - return fs->op.fsyncdir(path, datasync, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.fsyncdir) + return fs->op.fsyncdir(path, datasync, fi); + else + return -ENOSYS; } int fuse_fs_flush(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.flush) - return fs->op.flush(path, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.flush) + return fs->op.flush(path, fi); + else + return -ENOSYS; } int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.statfs) - return fuse_compat_statfs(fs, path, buf); - else { - buf->f_namemax = 255; - buf->f_bsize = 512; - return 0; - } + fuse_get_context()->private_data = fs->user_data; + if (fs->op.statfs) + return fuse_compat_statfs(fs, path, buf); + else { + buf->f_namemax = 255; + buf->f_bsize = 512; + return 0; + } } int fuse_fs_releasedir(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.releasedir) - return fs->op.releasedir(path, fi); - else - return 0; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.releasedir) + return fs->op.releasedir(path, fi); + else + return 0; } static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type, - ino_t ino) + ino_t ino) { - int res; - struct stat stbuf; + int res; + struct stat stbuf; - memset(&stbuf, 0, sizeof(stbuf)); - stbuf.st_mode = type << 12; - stbuf.st_ino = ino; + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_mode = type << 12; + stbuf.st_ino = ino; - res = dh->filler(dh->buf, name, &stbuf, 0); - return res ? -ENOMEM : 0; + res = dh->filler(dh->buf, name, &stbuf, 0); + return res ? -ENOMEM : 0; } int 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) + fuse_fill_dir_t filler, off_t off, + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.readdir) - return fs->op.readdir(path, buf, filler, off, fi); - else if (fs->op.getdir) { - struct fuse_dirhandle dh; - dh.filler = filler; - dh.buf = buf; - return fs->op.getdir(path, &dh, fill_dir_old); - } else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.readdir) + return fs->op.readdir(path, buf, filler, off, fi); + else if (fs->op.getdir) { + struct fuse_dirhandle dh; + dh.filler = filler; + dh.buf = buf; + return fs->op.getdir(path, &dh, fill_dir_old); + } else + return -ENOSYS; } int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.create) - return fs->op.create(path, mode, fi); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.create) + return fs->op.create(path, mode, fi); + else + return -ENOSYS; } int fuse_fs_lock(struct fuse_fs *fs, const char *path, - struct fuse_file_info *fi, int cmd, struct flock *lock) + struct fuse_file_info *fi, int cmd, struct flock *lock) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.lock) - return fs->op.lock(path, fi, cmd, lock); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.lock) + return fs->op.lock(path, fi, cmd, lock); + else + return -ENOSYS; } int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.chown) - return fs->op.chown(path, uid, gid); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.chown) + return fs->op.chown(path, uid, gid); + else + return -ENOSYS; } int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.truncate) - return fs->op.truncate(path, size); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.truncate) + return fs->op.truncate(path, size); + else + return -ENOSYS; } int fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.ftruncate) - return fs->op.ftruncate(path, size, fi); - else if (fs->op.truncate) - return fs->op.truncate(path, size); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.ftruncate) + return fs->op.ftruncate(path, size, fi); + else if (fs->op.truncate) + return fs->op.truncate(path, size); + else + return -ENOSYS; } int fuse_fs_utimens(struct fuse_fs *fs, const char *path, - const struct timespec tv[2]) + const struct timespec tv[2]) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.utimens) - return fs->op.utimens(path, tv); - else if(fs->op.utime) { - struct utimbuf buf; - buf.actime = tv[0].tv_sec; - buf.modtime = tv[1].tv_sec; - return fs->op.utime(path, &buf); - } else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.utimens) + return fs->op.utimens(path, tv); + else if(fs->op.utime) { + struct utimbuf buf; + buf.actime = tv[0].tv_sec; + buf.modtime = tv[1].tv_sec; + return fs->op.utime(path, &buf); + } else + return -ENOSYS; } int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.access) - return fs->op.access(path, mask); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.access) + return fs->op.access(path, mask); + else + return -ENOSYS; } int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf, - size_t len) + size_t len) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.readlink) - return fs->op.readlink(path, buf, len); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.readlink) + return fs->op.readlink(path, buf, len); + else + return -ENOSYS; } int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, - dev_t rdev) + dev_t rdev) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.mknod) - return fs->op.mknod(path, mode, rdev); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.mknod) + return fs->op.mknod(path, mode, rdev); + else + return -ENOSYS; } int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.mkdir) - return fs->op.mkdir(path, mode); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.mkdir) + return fs->op.mkdir(path, mode); + else + return -ENOSYS; } int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name, - const char *value, size_t size, int flags) + const char *value, size_t size, int flags) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.setxattr) - return fs->op.setxattr(path, name, value, size, flags); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.setxattr) + return fs->op.setxattr(path, name, value, size, flags); + else + return -ENOSYS; } int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, - char *value, size_t size) + char *value, size_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.getxattr) - return fs->op.getxattr(path, name, value, size); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.getxattr) + return fs->op.getxattr(path, name, value, size); + else + return -ENOSYS; } int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list, - size_t size) + size_t size) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.listxattr) - return fs->op.listxattr(path, list, size); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.listxattr) + return fs->op.listxattr(path, list, size); + else + return -ENOSYS; } int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, - uint64_t *idx) + uint64_t *idx) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.bmap) - return fs->op.bmap(path, blocksize, idx); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.bmap) + return fs->op.bmap(path, blocksize, idx); + else + return -ENOSYS; } int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.removexattr) - return fs->op.removexattr(path, name); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.removexattr) + return fs->op.removexattr(path, name); + else + return -ENOSYS; } static int is_open(struct fuse *f, fuse_ino_t dir, const char *name) { - struct node *node; - int isopen = 0; - pthread_mutex_lock(&f->lock); - node = lookup_node(f, dir, name); - if (node && node->open_count > 0) - isopen = 1; - pthread_mutex_unlock(&f->lock); - return isopen; + struct node *node; + int isopen = 0; + pthread_mutex_lock(&f->lock); + node = lookup_node(f, dir, name); + if (node && node->open_count > 0) + isopen = 1; + pthread_mutex_unlock(&f->lock); + return isopen; } static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname, - char *newname, size_t bufsize) -{ - struct stat buf; - struct node *node; - struct node *newnode; - char *newpath; - int res; - int failctr = 10; - - do { - pthread_mutex_lock(&f->lock); - node = lookup_node(f, dir, oldname); - if (node == NULL) { - pthread_mutex_unlock(&f->lock); - return NULL; - } - do { - f->hidectr ++; - snprintf(newname, bufsize, ".fuse_hidden%08x%08x", - (unsigned int) node->nodeid, f->hidectr); - newnode = lookup_node(f, dir, newname); - } while(newnode); - pthread_mutex_unlock(&f->lock); - - newpath = get_path_name(f, dir, newname); - if (!newpath) - break; - - res = fuse_fs_getattr(f->fs, newpath, &buf); - if (res == -ENOENT) - break; - free(newpath); - newpath = NULL; - } while(res == 0 && --failctr); - - return newpath; + char *newname, size_t bufsize) +{ + struct stat buf; + struct node *node; + struct node *newnode; + char *newpath; + int res; + int failctr = 10; + + do { + pthread_mutex_lock(&f->lock); + node = lookup_node(f, dir, oldname); + if (node == NULL) { + pthread_mutex_unlock(&f->lock); + return NULL; + } + do { + f->hidectr ++; + snprintf(newname, bufsize, ".fuse_hidden%08x%08x", + (unsigned int) node->nodeid, f->hidectr); + newnode = lookup_node(f, dir, newname); + } while(newnode); + pthread_mutex_unlock(&f->lock); + + newpath = get_path_name(f, dir, newname); + if (!newpath) + break; + + res = fuse_fs_getattr(f->fs, newpath, &buf); + if (res == -ENOENT) + break; + free(newpath); + newpath = NULL; + } while(res == 0 && --failctr); + + return newpath; } static int hide_node(struct fuse *f, const char *oldpath, - fuse_ino_t dir, const char *oldname) + fuse_ino_t dir, const char *oldname) { - char newname[64]; - char *newpath; - int err = -EBUSY; + char newname[64]; + char *newpath; + int err = -EBUSY; - newpath = hidden_name(f, dir, oldname, newname, sizeof(newname)); - if (newpath) { - err = fuse_fs_rename(f->fs, oldpath, newpath); - if (!err) - err = rename_node(f, dir, oldname, dir, newname, 1); - free(newpath); - } - return err; + newpath = hidden_name(f, dir, oldname, newname, sizeof(newname)); + if (newpath) { + err = fuse_fs_rename(f->fs, oldpath, newpath); + if (!err) + err = rename_node(f, dir, oldname, dir, newname, 1); + free(newpath); + } + return err; } static int mtime_eq(const struct stat *stbuf, const struct timespec *ts) { - return stbuf->st_mtime == ts->tv_sec && ST_MTIM_NSEC(stbuf) == ts->tv_nsec; + return stbuf->st_mtime == ts->tv_sec && + ST_MTIM_NSEC(stbuf) == ts->tv_nsec; } #ifndef CLOCK_MONOTONIC @@ -1172,2122 +1180,2153 @@ static int mtime_eq(const struct stat *stbuf, const struct timespec *ts) static void curr_time(struct timespec *now) { - static clockid_t clockid = CLOCK_MONOTONIC; - int res = clock_gettime(clockid, now); - if (res == -1 && errno == EINVAL) { - clockid = CLOCK_REALTIME; - res = clock_gettime(clockid, now); - } - if (res == -1) { - perror("fuse: clock_gettime"); - abort(); - } + static clockid_t clockid = CLOCK_MONOTONIC; + int res = clock_gettime(clockid, now); + if (res == -1 && errno == EINVAL) { + clockid = CLOCK_REALTIME; + res = clock_gettime(clockid, now); + } + if (res == -1) { + perror("fuse: clock_gettime"); + abort(); + } } static void update_stat(struct node *node, const struct stat *stbuf) { - if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) || - stbuf->st_size != node->size)) - node->cache_valid = 0; - node->mtime.tv_sec = stbuf->st_mtime; - node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf); - node->size = stbuf->st_size; - curr_time(&node->stat_updated); + if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) || + stbuf->st_size != node->size)) + node->cache_valid = 0; + node->mtime.tv_sec = stbuf->st_mtime; + node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf); + node->size = stbuf->st_size; + curr_time(&node->stat_updated); } static int 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) -{ - int res; - - memset(e, 0, sizeof(struct fuse_entry_param)); - if (fi) - res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi); - else - res = fuse_fs_getattr(f->fs, path, &e->attr); - if (res == 0) { - struct node *node; - - node = find_node(f, nodeid, name); - if (node == NULL) - res = -ENOMEM; - else { - e->ino = node->nodeid; - e->generation = node->generation; - e->entry_timeout = f->conf.entry_timeout; - e->attr_timeout = f->conf.attr_timeout; - if (f->conf.auto_cache) { - pthread_mutex_lock(&f->lock); - update_stat(node, &e->attr); - pthread_mutex_unlock(&f->lock); - } - set_stat(f, e->ino, &e->attr); - if (f->conf.debug) - fprintf(stderr, " NODEID: %lu\n", (unsigned long) e->ino); - } - } - return res; + const char *name, const char *path, + struct fuse_entry_param *e, struct fuse_file_info *fi) +{ + int res; + + memset(e, 0, sizeof(struct fuse_entry_param)); + if (fi) + res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi); + else + res = fuse_fs_getattr(f->fs, path, &e->attr); + if (res == 0) { + struct node *node; + + node = find_node(f, nodeid, name); + if (node == NULL) + res = -ENOMEM; + else { + e->ino = node->nodeid; + e->generation = node->generation; + e->entry_timeout = f->conf.entry_timeout; + e->attr_timeout = f->conf.attr_timeout; + if (f->conf.auto_cache) { + pthread_mutex_lock(&f->lock); + update_stat(node, &e->attr); + pthread_mutex_unlock(&f->lock); + } + set_stat(f, e->ino, &e->attr); + if (f->conf.debug) + fprintf(stderr, " NODEID: %lu\n", + (unsigned long) e->ino); + } + } + return res; } static struct fuse_context_i *fuse_get_context_internal(void) { - struct fuse_context_i *c; - - c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key); - if (c == NULL) { - c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i)); - if (c == NULL) { - /* This is hard to deal with properly, so just abort. If - memory is so low that the context cannot be allocated, - there's not much hope for the filesystem anyway */ - fprintf(stderr, "fuse: failed to allocate thread specific data\n"); - abort(); - } - pthread_setspecific(fuse_context_key, c); - } - return c; + struct fuse_context_i *c; + + c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key); + if (c == NULL) { + c = (struct fuse_context_i *) + malloc(sizeof(struct fuse_context_i)); + if (c == NULL) { + /* This is hard to deal with properly, so just + abort. If memory is so low that the + context cannot be allocated, there's not + much hope for the filesystem anyway */ + fprintf(stderr, "fuse: failed to allocate thread specific data\n"); + abort(); + } + pthread_setspecific(fuse_context_key, c); + } + return c; } static void fuse_freecontext(void *data) { - free(data); + free(data); } static int fuse_create_context_key(void) { - int err = 0; - pthread_mutex_lock(&fuse_context_lock); - if (!fuse_context_ref) { - err = pthread_key_create(&fuse_context_key, fuse_freecontext); - if (err) { - fprintf(stderr, "fuse: failed to create thread specific key: %s\n", - strerror(err)); - pthread_mutex_unlock(&fuse_context_lock); - return -1; - } - } - fuse_context_ref++; - pthread_mutex_unlock(&fuse_context_lock); - return 0; + int err = 0; + pthread_mutex_lock(&fuse_context_lock); + if (!fuse_context_ref) { + err = pthread_key_create(&fuse_context_key, fuse_freecontext); + if (err) { + fprintf(stderr, "fuse: failed to create thread specific key: %s\n", + strerror(err)); + pthread_mutex_unlock(&fuse_context_lock); + return -1; + } + } + fuse_context_ref++; + pthread_mutex_unlock(&fuse_context_lock); + return 0; } static void fuse_delete_context_key(void) { - pthread_mutex_lock(&fuse_context_lock); - fuse_context_ref--; - if (!fuse_context_ref) { - free(pthread_getspecific(fuse_context_key)); - pthread_key_delete(fuse_context_key); - } - pthread_mutex_unlock(&fuse_context_lock); + pthread_mutex_lock(&fuse_context_lock); + fuse_context_ref--; + if (!fuse_context_ref) { + free(pthread_getspecific(fuse_context_key)); + pthread_key_delete(fuse_context_key); + } + pthread_mutex_unlock(&fuse_context_lock); } static struct fuse *req_fuse_prepare(fuse_req_t req) { - struct fuse_context_i *c = fuse_get_context_internal(); - const struct fuse_ctx *ctx = fuse_req_ctx(req); - c->req = req; - c->ctx.fuse = req_fuse(req); - c->ctx.uid = ctx->uid; - c->ctx.gid = ctx->gid; - c->ctx.pid = ctx->pid; - return c->ctx.fuse; + struct fuse_context_i *c = fuse_get_context_internal(); + const struct fuse_ctx *ctx = fuse_req_ctx(req); + c->req = req; + c->ctx.fuse = req_fuse(req); + c->ctx.uid = ctx->uid; + c->ctx.gid = ctx->gid; + c->ctx.pid = ctx->pid; + return c->ctx.fuse; } static inline void reply_err(fuse_req_t req, int err) { - /* fuse_reply_err() uses non-negated errno values */ - fuse_reply_err(req, -err); + /* fuse_reply_err() uses non-negated errno values */ + fuse_reply_err(req, -err); } static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e, - int err) + int err) { - if (!err) { - struct fuse *f = req_fuse(req); - if (fuse_reply_entry(req, e) == -ENOENT) - forget_node(f, e->ino, 1); - } else - reply_err(req, err); + if (!err) { + struct fuse *f = req_fuse(req); + if (fuse_reply_entry(req, e) == -ENOENT) + forget_node(f, e->ino, 1); + } else + reply_err(req, err); } void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.init) - fs->user_data = fs->op.init(conn); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.init) + fs->user_data = fs->op.init(conn); } static void fuse_lib_init(void *data, struct fuse_conn_info *conn) { - struct fuse *f = (struct fuse *) data; - struct fuse_context_i *c = fuse_get_context_internal(); + struct fuse *f = (struct fuse *) data; + struct fuse_context_i *c = fuse_get_context_internal(); - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; - fuse_fs_init(f->fs, conn); + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + fuse_fs_init(f->fs, conn); } void fuse_fs_destroy(struct fuse_fs *fs) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.destroy) - fs->op.destroy(fs->user_data); - if (fs->m) - fuse_put_module(fs->m); - free(fs); + fuse_get_context()->private_data = fs->user_data; + if (fs->op.destroy) + fs->op.destroy(fs->user_data); + if (fs->m) + fuse_put_module(fs->m); + free(fs); } static void fuse_lib_destroy(void *data) { - struct fuse *f = (struct fuse *) data; - struct fuse_context_i *c = fuse_get_context_internal(); + struct fuse *f = (struct fuse *) data; + struct fuse_context_i *c = fuse_get_context_internal(); - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; - fuse_fs_destroy(f->fs); - f->fs = NULL; + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + fuse_fs_destroy(f->fs); + f->fs = NULL; } static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent, - const char *name) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "LOOKUP %s\n", path); - fuse_prepare_interrupt(f, req, &d); - err = lookup_path(f, parent, name, path, &e, NULL); - if (err == -ENOENT && f->conf.negative_timeout != 0.0) { - e.ino = 0; - e.entry_timeout = f->conf.negative_timeout; - err = 0; - } - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_entry(req, &e, err); + const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "LOOKUP %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = lookup_path(f, parent, name, path, &e, NULL); + if (err == -ENOENT && f->conf.negative_timeout != 0.0) { + e.ino = 0; + e.entry_timeout = f->conf.negative_timeout; + err = 0; + } + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); } static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino, - unsigned long nlookup) + unsigned long nlookup) { - struct fuse *f = req_fuse(req); - if (f->conf.debug) - fprintf(stderr, "FORGET %llu/%lu\n", (unsigned long long)ino, nlookup); - forget_node(f, ino, nlookup); - fuse_reply_none(req); + struct fuse *f = req_fuse(req); + if (f->conf.debug) + fprintf(stderr, "FORGET %llu/%lu\n", (unsigned long long)ino, + nlookup); + forget_node(f, ino, nlookup); + fuse_reply_none(req); } static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - struct fuse *f = req_fuse_prepare(req); - struct stat buf; - char *path; - int err; - - (void) fi; - memset(&buf, 0, sizeof(buf)); - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_getattr(f->fs, path, &buf); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - if (!err) { - if (f->conf.auto_cache) { - pthread_mutex_lock(&f->lock); - update_stat(get_node(f, ino), &buf); - pthread_mutex_unlock(&f->lock); - } - set_stat(f, ino, &buf); - fuse_reply_attr(req, &buf, f->conf.attr_timeout); - } else - reply_err(req, err); + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct stat buf; + char *path; + int err; + + (void) fi; + memset(&buf, 0, sizeof(buf)); + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_getattr(f->fs, path, &buf); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) { + if (f->conf.auto_cache) { + pthread_mutex_lock(&f->lock); + update_stat(get_node(f, ino), &buf); + pthread_mutex_unlock(&f->lock); + } + set_stat(f, ino, &buf); + fuse_reply_attr(req, &buf, f->conf.attr_timeout); + } else + reply_err(req, err); } int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode) { - fuse_get_context()->private_data = fs->user_data; - if (fs->op.chmod) - return fs->op.chmod(path, mode); - else - return -ENOSYS; + fuse_get_context()->private_data = fs->user_data; + if (fs->op.chmod) + return fs->op.chmod(path, mode); + else + return -ENOSYS; } static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int valid, struct fuse_file_info *fi) -{ - struct fuse *f = req_fuse_prepare(req); - struct stat buf; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = 0; - if (!err && (valid & FUSE_SET_ATTR_MODE)) - err = fuse_fs_chmod(f->fs, path, attr->st_mode); - if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) { - uid_t uid = - (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1; - gid_t gid = - (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1; - err = fuse_fs_chown(f->fs, path, uid, gid); - } - if (!err && (valid & FUSE_SET_ATTR_SIZE)) { - if (fi) - err = fuse_fs_ftruncate(f->fs, path, attr->st_size, fi); - else - err = fuse_fs_truncate(f->fs, path, attr->st_size); - } - if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == - (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) { - struct timespec tv[2]; - tv[0].tv_sec = attr->st_atime; - tv[0].tv_nsec = ST_ATIM_NSEC(attr); - tv[1].tv_sec = attr->st_mtime; - tv[1].tv_nsec = ST_MTIM_NSEC(attr); - err = fuse_fs_utimens(f->fs, path, tv); - } - if (!err) - err = fuse_fs_getattr(f->fs, path, &buf); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - if (!err) { - if (f->conf.auto_cache) { - pthread_mutex_lock(&f->lock); - update_stat(get_node(f, ino), &buf); - pthread_mutex_unlock(&f->lock); - } - set_stat(f, ino, &buf); - fuse_reply_attr(req, &buf, f->conf.attr_timeout); - } else - reply_err(req, err); + int valid, struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct stat buf; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = 0; + if (!err && (valid & FUSE_SET_ATTR_MODE)) + err = fuse_fs_chmod(f->fs, path, attr->st_mode); + if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) { + uid_t uid = (valid & FUSE_SET_ATTR_UID) ? + attr->st_uid : (uid_t) -1; + gid_t gid = (valid & FUSE_SET_ATTR_GID) ? + attr->st_gid : (gid_t) -1; + err = fuse_fs_chown(f->fs, path, uid, gid); + } + if (!err && (valid & FUSE_SET_ATTR_SIZE)) { + if (fi) + err = fuse_fs_ftruncate(f->fs, path, + attr->st_size, fi); + else + err = fuse_fs_truncate(f->fs, path, + attr->st_size); + } + if (!err && + (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == + (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) { + struct timespec tv[2]; + tv[0].tv_sec = attr->st_atime; + tv[0].tv_nsec = ST_ATIM_NSEC(attr); + tv[1].tv_sec = attr->st_mtime; + tv[1].tv_nsec = ST_MTIM_NSEC(attr); + err = fuse_fs_utimens(f->fs, path, tv); + } + if (!err) + err = fuse_fs_getattr(f->fs, path, &buf); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) { + if (f->conf.auto_cache) { + pthread_mutex_lock(&f->lock); + update_stat(get_node(f, ino), &buf); + pthread_mutex_unlock(&f->lock); + } + set_stat(f, ino, &buf); + fuse_reply_attr(req, &buf, f->conf.attr_timeout); + } else + reply_err(req, err); } static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "ACCESS %s 0%o\n", path, mask); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_access(f->fs, path, mask); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "ACCESS %s 0%o\n", path, mask); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_access(f->fs, path, mask); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino) { - struct fuse *f = req_fuse_prepare(req); - char linkname[PATH_MAX + 1]; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - if (!err) { - linkname[PATH_MAX] = '\0'; - fuse_reply_readlink(req, linkname); - } else - reply_err(req, err); + struct fuse *f = req_fuse_prepare(req); + char linkname[PATH_MAX + 1]; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) { + linkname[PATH_MAX] = '\0'; + fuse_reply_readlink(req, linkname); + } else + reply_err(req, err); } static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode, dev_t rdev) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "MKNOD %s\n", path); - fuse_prepare_interrupt(f, req, &d); - err = -ENOSYS; - if (S_ISREG(mode)) { - struct fuse_file_info fi; - - memset(&fi, 0, sizeof(fi)); - fi.flags = O_CREAT | O_EXCL | O_WRONLY; - err = fuse_fs_create(f->fs, path, mode, &fi); - if (!err) { - err = lookup_path(f, parent, name, path, &e, &fi); - fuse_fs_release(f->fs, path, &fi); - } - } - if (err == -ENOSYS) { - err = fuse_fs_mknod(f->fs, path, mode, rdev); - if (!err) - err = lookup_path(f, parent, name, path, &e, NULL); - } - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_entry(req, &e, err); + mode_t mode, dev_t rdev) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "MKNOD %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = -ENOSYS; + if (S_ISREG(mode)) { + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.flags = O_CREAT | O_EXCL | O_WRONLY; + err = fuse_fs_create(f->fs, path, mode, &fi); + if (!err) { + err = lookup_path(f, parent, name, path, &e, + &fi); + fuse_fs_release(f->fs, path, &fi); + } + } + if (err == -ENOSYS) { + err = fuse_fs_mknod(f->fs, path, mode, rdev); + if (!err) + err = lookup_path(f, parent, name, path, &e, + NULL); + } + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); } static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, - mode_t mode) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "MKDIR %s\n", path); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_mkdir(f->fs, path, mode); - if (!err) - err = lookup_path(f, parent, name, path, &e, NULL); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_entry(req, &e, err); + mode_t mode) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "MKDIR %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_mkdir(f->fs, path, mode); + if (!err) + err = lookup_path(f, parent, name, path, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); } static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent, - const char *name) -{ - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_wrlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "UNLINK %s\n", path); - fuse_prepare_interrupt(f, req, &d); - if (!f->conf.hard_remove && is_open(f, parent, name)) - err = hide_node(f, path, parent, name); - else { - err = fuse_fs_unlink(f->fs, path); - if (!err) - remove_node(f, parent, name); - } - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_wrlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "UNLINK %s\n", path); + fuse_prepare_interrupt(f, req, &d); + if (!f->conf.hard_remove && is_open(f, parent, name)) + err = hide_node(f, path, parent, name); + else { + err = fuse_fs_unlink(f->fs, path); + if (!err) + remove_node(f, parent, name); + } + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_wrlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "RMDIR %s\n", path); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_rmdir(f->fs, path); - fuse_finish_interrupt(f, req, &d); - if (!err) - remove_node(f, parent, name); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_wrlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "RMDIR %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_rmdir(f->fs, path); + fuse_finish_interrupt(f, req, &d); + if (!err) + remove_node(f, parent, name); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static void fuse_lib_symlink(fuse_req_t req, const char *linkname, - fuse_ino_t parent, const char *name) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "SYMLINK %s\n", path); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_symlink(f->fs, linkname, path); - if (!err) - err = lookup_path(f, parent, name, path, &e, NULL); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_entry(req, &e, err); + fuse_ino_t parent, const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "SYMLINK %s\n", path); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_symlink(f->fs, linkname, path); + if (!err) + err = lookup_path(f, parent, name, path, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); } static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir, - const char *oldname, fuse_ino_t newdir, - const char *newname) -{ - struct fuse *f = req_fuse_prepare(req); - char *oldpath; - char *newpath; - int err; - - err = -ENOENT; - pthread_rwlock_wrlock(&f->tree_lock); - oldpath = get_path_name(f, olddir, oldname); - if (oldpath != NULL) { - newpath = get_path_name(f, newdir, newname); - if (newpath != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "RENAME %s -> %s\n", oldpath, newpath); - err = 0; - fuse_prepare_interrupt(f, req, &d); - if (!f->conf.hard_remove && is_open(f, newdir, newname)) - err = hide_node(f, newpath, newdir, newname); - if (!err) { - err = fuse_fs_rename(f->fs, oldpath, newpath); - if (!err) - err = rename_node(f, olddir, oldname, newdir, newname, 0); - } - fuse_finish_interrupt(f, req, &d); - free(newpath); - } - free(oldpath); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + const char *oldname, fuse_ino_t newdir, + const char *newname) +{ + struct fuse *f = req_fuse_prepare(req); + char *oldpath; + char *newpath; + int err; + + err = -ENOENT; + pthread_rwlock_wrlock(&f->tree_lock); + oldpath = get_path_name(f, olddir, oldname); + if (oldpath != NULL) { + newpath = get_path_name(f, newdir, newname); + if (newpath != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "RENAME %s -> %s\n", oldpath, + newpath); + err = 0; + fuse_prepare_interrupt(f, req, &d); + if (!f->conf.hard_remove && is_open(f, newdir, newname)) + err = hide_node(f, newpath, newdir, newname); + if (!err) { + err = fuse_fs_rename(f->fs, oldpath, newpath); + if (!err) + err = rename_node(f, olddir, oldname, + newdir, newname, 0); + } + fuse_finish_interrupt(f, req, &d); + free(newpath); + } + free(oldpath); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, - const char *newname) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_entry_param e; - char *oldpath; - char *newpath; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - oldpath = get_path(f, ino); - if (oldpath != NULL) { - newpath = get_path_name(f, newparent, newname); - if (newpath != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "LINK %s\n", newpath); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_link(f->fs, oldpath, newpath); - if (!err) - err = lookup_path(f, newparent, newname, newpath, &e, NULL); - fuse_finish_interrupt(f, req, &d); - free(newpath); - } - free(oldpath); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_entry(req, &e, err); + const char *newname) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_entry_param e; + char *oldpath; + char *newpath; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + oldpath = get_path(f, ino); + if (oldpath != NULL) { + newpath = get_path_name(f, newparent, newname); + if (newpath != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "LINK %s\n", newpath); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_link(f->fs, oldpath, newpath); + if (!err) + err = lookup_path(f, newparent, newname, + newpath, &e, NULL); + fuse_finish_interrupt(f, req, &d); + free(newpath); + } + free(oldpath); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_entry(req, &e, err); } static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct node *node; - int unlink_hidden = 0; + struct node *node; + int unlink_hidden = 0; - fuse_fs_release(f->fs, path ? path : "-", fi); + fuse_fs_release(f->fs, path ? path : "-", fi); - pthread_mutex_lock(&f->lock); - node = get_node(f, ino); - assert(node->open_count > 0); - --node->open_count; - if (node->is_hidden && !node->open_count) { - unlink_hidden = 1; - node->is_hidden = 0; - } - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + node = get_node(f, ino); + assert(node->open_count > 0); + --node->open_count; + if (node->is_hidden && !node->open_count) { + unlink_hidden = 1; + node->is_hidden = 0; + } + pthread_mutex_unlock(&f->lock); - if(unlink_hidden && path) - fuse_fs_unlink(f->fs, path); + if(unlink_hidden && path) + fuse_fs_unlink(f->fs, path); } static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent, - const char *name, mode_t mode, - struct fuse_file_info *fi) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - struct fuse_entry_param e; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, parent, name); - if (path) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_create(f->fs, path, mode, fi); - if (!err) { - err = lookup_path(f, parent, name, path, &e, fi); - if (err) - fuse_fs_release(f->fs, path, fi); - else if (!S_ISREG(e.attr.st_mode)) { - err = -EIO; - fuse_fs_release(f->fs, path, fi); - forget_node(f, e.ino, 1); - } else { - if (f->conf.direct_io) - fi->direct_io = 1; - if (f->conf.kernel_cache) - fi->keep_cache = 1; - - } - } - fuse_finish_interrupt(f, req, &d); - } - if (!err) { - pthread_mutex_lock(&f->lock); - get_node(f, e.ino)->open_count++; - pthread_mutex_unlock(&f->lock); - if (fuse_reply_create(req, &e, fi) == -ENOENT) { - /* The open syscall was interrupted, so it must be cancelled */ - fuse_prepare_interrupt(f, req, &d); - fuse_do_release(f, e.ino, path, fi); - fuse_finish_interrupt(f, req, &d); - forget_node(f, e.ino, 1); - } else if (f->conf.debug) { - fprintf(stderr, " CREATE[%llu] flags: 0x%x %s\n", - (unsigned long long) fi->fh, fi->flags, path); - } - } else - reply_err(req, err); - - if (path) - free(path); - - pthread_rwlock_unlock(&f->tree_lock); + const char *name, mode_t mode, + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_entry_param e; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path_name(f, parent, name); + if (path) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_create(f->fs, path, mode, fi); + if (!err) { + err = lookup_path(f, parent, name, path, &e, fi); + if (err) + fuse_fs_release(f->fs, path, fi); + else if (!S_ISREG(e.attr.st_mode)) { + err = -EIO; + fuse_fs_release(f->fs, path, fi); + forget_node(f, e.ino, 1); + } else { + if (f->conf.direct_io) + fi->direct_io = 1; + if (f->conf.kernel_cache) + fi->keep_cache = 1; + + } + } + fuse_finish_interrupt(f, req, &d); + } + if (!err) { + pthread_mutex_lock(&f->lock); + get_node(f, e.ino)->open_count++; + pthread_mutex_unlock(&f->lock); + if (fuse_reply_create(req, &e, fi) == -ENOENT) { + /* The open syscall was interrupted, so it + must be cancelled */ + fuse_prepare_interrupt(f, req, &d); + fuse_do_release(f, e.ino, path, fi); + fuse_finish_interrupt(f, req, &d); + forget_node(f, e.ino, 1); + } else if (f->conf.debug) { + fprintf(stderr, " CREATE[%llu] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); + } + } else + reply_err(req, err); + + if (path) + free(path); + + pthread_rwlock_unlock(&f->tree_lock); } static double diff_timespec(const struct timespec *t1, - const struct timespec *t2) + const struct timespec *t2) { - return (t1->tv_sec - t2->tv_sec) + - ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0; + return (t1->tv_sec - t2->tv_sec) + + ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0; } static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path, - struct fuse_file_info *fi) -{ - struct node *node; - - pthread_mutex_lock(&f->lock); - node = get_node(f, ino); - if (node->cache_valid) { - struct timespec now; - - curr_time(&now); - if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) { - struct stat stbuf; - int err; - pthread_mutex_unlock(&f->lock); - err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi); - pthread_mutex_lock(&f->lock); - if (!err) - update_stat(node, &stbuf); - else - node->cache_valid = 0; - } - } - if (node->cache_valid) - fi->keep_cache = 1; - - node->cache_valid = 1; - pthread_mutex_unlock(&f->lock); + struct fuse_file_info *fi) +{ + struct node *node; + + pthread_mutex_lock(&f->lock); + node = get_node(f, ino); + if (node->cache_valid) { + struct timespec now; + + curr_time(&now); + if (diff_timespec(&now, &node->stat_updated) > + f->conf.ac_attr_timeout) { + struct stat stbuf; + int err; + pthread_mutex_unlock(&f->lock); + err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi); + pthread_mutex_lock(&f->lock); + if (!err) + update_stat(node, &stbuf); + else + node->cache_valid = 0; + } + } + if (node->cache_valid) + fi->keep_cache = 1; + + node->cache_valid = 1; + pthread_mutex_unlock(&f->lock); } static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - char *path = NULL; - int err = 0; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_open(f->fs, path, fi); - if (!err) { - if (f->conf.direct_io) - fi->direct_io = 1; - if (f->conf.kernel_cache) - fi->keep_cache = 1; - - if (f->conf.auto_cache) - open_auto_cache(f, ino, path, fi); - } - fuse_finish_interrupt(f, req, &d); - } - if (!err) { - pthread_mutex_lock(&f->lock); - get_node(f, ino)->open_count++; - pthread_mutex_unlock(&f->lock); - if (fuse_reply_open(req, fi) == -ENOENT) { - /* The open syscall was interrupted, so it must be cancelled */ - fuse_prepare_interrupt(f, req, &d); - fuse_do_release(f, ino, path, fi); - fuse_finish_interrupt(f, req, &d); - } else if (f->conf.debug) { - fprintf(stderr, "OPEN[%llu] flags: 0x%x %s\n", - (unsigned long long) fi->fh, fi->flags, path); - } - } else - reply_err(req, err); - - if (path) - free(path); - pthread_rwlock_unlock(&f->tree_lock); + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path = NULL; + int err = 0; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_open(f->fs, path, fi); + if (!err) { + if (f->conf.direct_io) + fi->direct_io = 1; + if (f->conf.kernel_cache) + fi->keep_cache = 1; + + if (f->conf.auto_cache) + open_auto_cache(f, ino, path, fi); + } + fuse_finish_interrupt(f, req, &d); + } + if (!err) { + pthread_mutex_lock(&f->lock); + get_node(f, ino)->open_count++; + pthread_mutex_unlock(&f->lock); + if (fuse_reply_open(req, fi) == -ENOENT) { + /* The open syscall was interrupted, so it + must be cancelled */ + fuse_prepare_interrupt(f, req, &d); + fuse_do_release(f, ino, path, fi); + fuse_finish_interrupt(f, req, &d); + } else if (f->conf.debug) { + fprintf(stderr, "OPEN[%llu] flags: 0x%x %s\n", + (unsigned long long) fi->fh, fi->flags, path); + } + } else + reply_err(req, err); + + if (path) + free(path); + pthread_rwlock_unlock(&f->tree_lock); } static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *fi) -{ - struct fuse *f = req_fuse_prepare(req); - char *path; - char *buf; - int res; - - buf = (char *) malloc(size); - if (buf == NULL) { - reply_err(req, -ENOMEM); - return; - } - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "READ[%llu] %lu bytes from %llu\n", - (unsigned long long) fi->fh, (unsigned long) size, - (unsigned long long) off); - - fuse_prepare_interrupt(f, req, &d); - res = fuse_fs_read(f->fs, path, buf, size, off, fi); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - - if (res >= 0) { - if (f->conf.debug) - fprintf(stderr, " READ[%llu] %u bytes\n", - (unsigned long long)fi->fh, res); - if ((size_t) res > size) - fprintf(stderr, "fuse: read too many bytes"); - fuse_reply_buf(req, buf, res); - } else - reply_err(req, res); - - free(buf); + off_t off, struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + char *buf; + int res; + + buf = (char *) malloc(size); + if (buf == NULL) { + reply_err(req, -ENOMEM); + return; + } + + res = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "READ[%llu] %lu bytes from %llu\n", + (unsigned long long) fi->fh, + (unsigned long) size, (unsigned long long) off); + + fuse_prepare_interrupt(f, req, &d); + res = fuse_fs_read(f->fs, path, buf, size, off, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + + if (res >= 0) { + if (f->conf.debug) + fprintf(stderr, " READ[%llu] %u bytes\n", + (unsigned long long)fi->fh, res); + if ((size_t) res > size) + fprintf(stderr, "fuse: read too many bytes"); + fuse_reply_buf(req, buf, res); + } else + reply_err(req, res); + + free(buf); } static void 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) -{ - struct fuse *f = req_fuse_prepare(req); - char *path; - int res; - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "WRITE%s[%llu] %lu bytes to %llu\n", - fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh, - (unsigned long) size, (unsigned long long) off); - - fuse_prepare_interrupt(f, req, &d); - res = fuse_fs_write(f->fs, path, buf, size, off, fi); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - - if (res >= 0) { - if (f->conf.debug) - fprintf(stderr, " WRITE%s[%llu] %u bytes\n", - fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh, - res); - if ((size_t) res > size) - fprintf(stderr, "fuse: wrote too many bytes"); - fuse_reply_write(req, res); - } else - reply_err(req, res); + size_t size, off_t off, struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int res; + + res = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "WRITE%s[%llu] %lu bytes to %llu\n", + fi->writepage ? "PAGE" : "", + (unsigned long long) fi->fh, + (unsigned long) size, (unsigned long long) off); + + fuse_prepare_interrupt(f, req, &d); + res = fuse_fs_write(f->fs, path, buf, size, off, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + + if (res >= 0) { + if (f->conf.debug) + fprintf(stderr, " WRITE%s[%llu] %u bytes\n", + fi->writepage ? "PAGE" : "", + (unsigned long long) fi->fh, res); + if ((size_t) res > size) + fprintf(stderr, "fuse: wrote too many bytes"); + fuse_reply_write(req, res); + } else + reply_err(req, res); } static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *fi) -{ - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - if (f->conf.debug) - fprintf(stderr, "FSYNC[%llu]\n", (unsigned long long) fi->fh); - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_fsync(f->fs, path, datasync, fi); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + struct fuse_file_info *fi) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + if (f->conf.debug) + fprintf(stderr, "FSYNC[%llu]\n", + (unsigned long long) fi->fh); + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fsync(f->fs, path, datasync, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh; - memset(fi, 0, sizeof(struct fuse_file_info)); - fi->fh = dh->fh; - fi->fh_old = dh->fh; - return dh; + struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh; + memset(fi, 0, sizeof(struct fuse_file_info)); + fi->fh = dh->fh; + fi->fh_old = dh->fh; + return dh; } static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *llfi) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - struct fuse_dh *dh; - struct fuse_file_info fi; - char *path; - int err; - - dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh)); - if (dh == NULL) { - reply_err(req, -ENOMEM); - return; - } - memset(dh, 0, sizeof(struct fuse_dh)); - dh->fuse = f; - dh->contents = NULL; - dh->len = 0; - dh->filled = 0; - dh->nodeid = ino; - fuse_mutex_init(&dh->lock); - - llfi->fh = (uintptr_t) dh; - - memset(&fi, 0, sizeof(fi)); - fi.flags = llfi->flags; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_opendir(f->fs, path, &fi); - fuse_finish_interrupt(f, req, &d); - dh->fh = fi.fh; - } - if (!err) { - if (fuse_reply_open(req, llfi) == -ENOENT) { - /* The opendir syscall was interrupted, so it must be cancelled */ - fuse_prepare_interrupt(f, req, &d); - fuse_fs_releasedir(f->fs, path, &fi); - fuse_finish_interrupt(f, req, &d); - pthread_mutex_destroy(&dh->lock); - free(dh); - } - } else { - reply_err(req, err); - free(dh); - } - free(path); - pthread_rwlock_unlock(&f->tree_lock); + struct fuse_file_info *llfi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_dh *dh; + struct fuse_file_info fi; + char *path; + int err; + + dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh)); + if (dh == NULL) { + reply_err(req, -ENOMEM); + return; + } + memset(dh, 0, sizeof(struct fuse_dh)); + dh->fuse = f; + dh->contents = NULL; + dh->len = 0; + dh->filled = 0; + dh->nodeid = ino; + fuse_mutex_init(&dh->lock); + + llfi->fh = (uintptr_t) dh; + + memset(&fi, 0, sizeof(fi)); + fi.flags = llfi->flags; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_opendir(f->fs, path, &fi); + fuse_finish_interrupt(f, req, &d); + dh->fh = fi.fh; + } + if (!err) { + if (fuse_reply_open(req, llfi) == -ENOENT) { + /* The opendir syscall was interrupted, so it + must be cancelled */ + fuse_prepare_interrupt(f, req, &d); + fuse_fs_releasedir(f->fs, path, &fi); + fuse_finish_interrupt(f, req, &d); + pthread_mutex_destroy(&dh->lock); + free(dh); + } + } else { + reply_err(req, err); + free(dh); + } + free(path); + pthread_rwlock_unlock(&f->tree_lock); } static int extend_contents(struct fuse_dh *dh, unsigned minsize) { - if (minsize > dh->size) { - char *newptr; - unsigned newsize = dh->size; - if (!newsize) - newsize = 1024; - while (newsize < minsize) - newsize *= 2; - - newptr = (char *) realloc(dh->contents, newsize); - if (!newptr) { - dh->error = -ENOMEM; - return -1; - } - dh->contents = newptr; - dh->size = newsize; - } - return 0; + if (minsize > dh->size) { + char *newptr; + unsigned newsize = dh->size; + if (!newsize) + newsize = 1024; + while (newsize < minsize) + newsize *= 2; + + newptr = (char *) realloc(dh->contents, newsize); + if (!newptr) { + dh->error = -ENOMEM; + return -1; + } + dh->contents = newptr; + dh->size = newsize; + } + return 0; } static int fill_dir(void *dh_, const char *name, const struct stat *statp, - off_t off) -{ - struct fuse_dh *dh = (struct fuse_dh *) dh_; - struct stat stbuf; - size_t newlen; - - if (statp) - stbuf = *statp; - else { - memset(&stbuf, 0, sizeof(stbuf)); - stbuf.st_ino = FUSE_UNKNOWN_INO; - } - - if (!dh->fuse->conf.use_ino) { - stbuf.st_ino = FUSE_UNKNOWN_INO; - if (dh->fuse->conf.readdir_ino) { - struct node *node; - pthread_mutex_lock(&dh->fuse->lock); - node = lookup_node(dh->fuse, dh->nodeid, name); - if (node) - stbuf.st_ino = (ino_t) node->nodeid; - pthread_mutex_unlock(&dh->fuse->lock); - } - } - - if (off) { - if (extend_contents(dh, dh->needlen) == -1) - return 1; - - dh->filled = 0; - newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len, - dh->needlen - dh->len, name, - &stbuf, off); - if (newlen > dh->needlen) - return 1; - } else { - newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0); - if (extend_contents(dh, newlen) == -1) - return 1; - - fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len, - name, &stbuf, newlen); - } - dh->len = newlen; - return 0; + off_t off) +{ + struct fuse_dh *dh = (struct fuse_dh *) dh_; + struct stat stbuf; + size_t newlen; + + if (statp) + stbuf = *statp; + else { + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_ino = FUSE_UNKNOWN_INO; + } + + if (!dh->fuse->conf.use_ino) { + stbuf.st_ino = FUSE_UNKNOWN_INO; + if (dh->fuse->conf.readdir_ino) { + struct node *node; + pthread_mutex_lock(&dh->fuse->lock); + node = lookup_node(dh->fuse, dh->nodeid, name); + if (node) + stbuf.st_ino = (ino_t) node->nodeid; + pthread_mutex_unlock(&dh->fuse->lock); + } + } + + if (off) { + if (extend_contents(dh, dh->needlen) == -1) + return 1; + + dh->filled = 0; + newlen = dh->len + + fuse_add_direntry(dh->req, dh->contents + dh->len, + dh->needlen - dh->len, name, + &stbuf, off); + if (newlen > dh->needlen) + return 1; + } else { + newlen = dh->len + + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0); + if (extend_contents(dh, newlen) == -1) + return 1; + + fuse_add_direntry(dh->req, dh->contents + dh->len, + dh->size - dh->len, name, &stbuf, newlen); + } + dh->len = newlen; + return 0; } static int 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) -{ - int err = -ENOENT; - char *path; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - - dh->len = 0; - dh->error = 0; - dh->needlen = size; - dh->filled = 1; - dh->req = req; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi); - fuse_finish_interrupt(f, req, &d); - dh->req = NULL; - if (!err) - err = dh->error; - if (err) - dh->filled = 0; - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - return err; + size_t size, off_t off, struct fuse_dh *dh, + struct fuse_file_info *fi) +{ + int err = -ENOENT; + char *path; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + + dh->len = 0; + dh->error = 0; + dh->needlen = size; + dh->filled = 1; + dh->req = req; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi); + fuse_finish_interrupt(f, req, &d); + dh->req = NULL; + if (!err) + err = dh->error; + if (err) + dh->filled = 0; + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; } static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *llfi) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_file_info fi; - struct fuse_dh *dh = get_dirhandle(llfi, &fi); - - pthread_mutex_lock(&dh->lock); - /* According to SUS, directory contents need to be refreshed on - rewinddir() */ - if (!off) - dh->filled = 0; - - if (!dh->filled) { - int err = readdir_fill(f, req, ino, size, off, dh, &fi); - if (err) { - reply_err(req, err); - goto out; - } - } - if (dh->filled) { - if (off < dh->len) { - if (off + size > dh->len) - size = dh->len - off; - } else - size = 0; - } else { - size = dh->len; - off = 0; - } - fuse_reply_buf(req, dh->contents + off, size); - out: - pthread_mutex_unlock(&dh->lock); + off_t off, struct fuse_file_info *llfi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_file_info fi; + struct fuse_dh *dh = get_dirhandle(llfi, &fi); + + pthread_mutex_lock(&dh->lock); + /* According to SUS, directory contents need to be refreshed on + rewinddir() */ + if (!off) + dh->filled = 0; + + if (!dh->filled) { + int err = readdir_fill(f, req, ino, size, off, dh, &fi); + if (err) { + reply_err(req, err); + goto out; + } + } + if (dh->filled) { + if (off < dh->len) { + if (off + size > dh->len) + size = dh->len - off; + } else + size = 0; + } else { + size = dh->len; + off = 0; + } + fuse_reply_buf(req, dh->contents + off, size); +out: + pthread_mutex_unlock(&dh->lock); } static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *llfi) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - struct fuse_file_info fi; - struct fuse_dh *dh = get_dirhandle(llfi, &fi); - char *path; - - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - fuse_prepare_interrupt(f, req, &d); - fuse_fs_releasedir(f->fs, path ? path : "-", &fi); - fuse_finish_interrupt(f, req, &d); - if (path) - free(path); - pthread_rwlock_unlock(&f->tree_lock); - pthread_mutex_lock(&dh->lock); - pthread_mutex_unlock(&dh->lock); - pthread_mutex_destroy(&dh->lock); - free(dh->contents); - free(dh); - reply_err(req, 0); + struct fuse_file_info *llfi) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + struct fuse_file_info fi; + struct fuse_dh *dh = get_dirhandle(llfi, &fi); + char *path; + + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + fuse_prepare_interrupt(f, req, &d); + fuse_fs_releasedir(f->fs, path ? path : "-", &fi); + fuse_finish_interrupt(f, req, &d); + if (path) + free(path); + pthread_rwlock_unlock(&f->tree_lock); + pthread_mutex_lock(&dh->lock); + pthread_mutex_unlock(&dh->lock); + pthread_mutex_destroy(&dh->lock); + free(dh->contents); + free(dh); + reply_err(req, 0); } static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *llfi) + struct fuse_file_info *llfi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_file_info fi; - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + struct fuse_file_info fi; + char *path; + int err; - get_dirhandle(llfi, &fi); + get_dirhandle(llfi, &fi); - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino) { - struct fuse *f = req_fuse_prepare(req); - struct statvfs buf; - char *path; - int err; - - memset(&buf, 0, sizeof(buf)); - pthread_rwlock_rdlock(&f->tree_lock); - if (!ino) { - err = -ENOMEM; - path = strdup("/"); - } else { - err = -ENOENT; - path = get_path(f, ino); - } - if (path) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_statfs(f->fs, path, &buf); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - - if (!err) - fuse_reply_statfs(req, &buf); - else - reply_err(req, err); + struct fuse *f = req_fuse_prepare(req); + struct statvfs buf; + char *path; + int err; + + memset(&buf, 0, sizeof(buf)); + pthread_rwlock_rdlock(&f->tree_lock); + if (!ino) { + err = -ENOMEM; + path = strdup("/"); + } else { + err = -ENOENT; + path = get_path(f, ino); + } + if (path) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_statfs(f->fs, path, &buf); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + + if (!err) + fuse_reply_statfs(req, &buf); + else + reply_err(req, err); } static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, - const char *value, size_t size, int flags) -{ - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_setxattr(f->fs, path, name, value, size, flags); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + const char *value, size_t size, int flags) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_setxattr(f->fs, path, name, value, size, flags); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, - const char *name, char *value, size_t size) + const char *name, char *value, size_t size) { - int err; - char *path; + int err; + char *path; - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_getxattr(f->fs, path, name, value, size); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - return err; + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_getxattr(f->fs, path, name, value, size); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; } static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, - size_t size) -{ - struct fuse *f = req_fuse_prepare(req); - int res; - - if (size) { - char *value = (char *) malloc(size); - if (value == NULL) { - reply_err(req, -ENOMEM); - return; - } - res = common_getxattr(f, req, ino, name, value, size); - if (res > 0) - fuse_reply_buf(req, value, res); - else - reply_err(req, res); - free(value); - } else { - res = common_getxattr(f, req, ino, name, NULL, 0); - if (res >= 0) - fuse_reply_xattr(req, res); - else - reply_err(req, res); - } + size_t size) +{ + struct fuse *f = req_fuse_prepare(req); + int res; + + if (size) { + char *value = (char *) malloc(size); + if (value == NULL) { + reply_err(req, -ENOMEM); + return; + } + res = common_getxattr(f, req, ino, name, value, size); + if (res > 0) + fuse_reply_buf(req, value, res); + else + reply_err(req, res); + free(value); + } else { + res = common_getxattr(f, req, ino, name, NULL, 0); + if (res >= 0) + fuse_reply_xattr(req, res); + else + reply_err(req, res); + } } static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, - char *list, size_t size) + char *list, size_t size) { - char *path; - int err; + char *path; + int err; - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_listxattr(f->fs, path, list, size); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - return err; + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_listxattr(f->fs, path, list, size); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; } static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) { - struct fuse *f = req_fuse_prepare(req); - int res; - - if (size) { - char *list = (char *) malloc(size); - if (list == NULL) { - reply_err(req, -ENOMEM); - return; - } - res = common_listxattr(f, req, ino, list, size); - if (res > 0) - fuse_reply_buf(req, list, res); - else - reply_err(req, res); - free(list); - } else { - res = common_listxattr(f, req, ino, NULL, 0); - if (res >= 0) - fuse_reply_xattr(req, res); - else - reply_err(req, res); - } + struct fuse *f = req_fuse_prepare(req); + int res; + + if (size) { + char *list = (char *) malloc(size); + if (list == NULL) { + reply_err(req, -ENOMEM); + return; + } + res = common_listxattr(f, req, ino, list, size); + if (res > 0) + fuse_reply_buf(req, list, res); + else + reply_err(req, res); + free(list); + } else { + res = common_listxattr(f, req, ino, NULL, 0); + if (res >= 0) + fuse_reply_xattr(req, res); + else + reply_err(req, res); + } } static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino, - const char *name) -{ - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_removexattr(f->fs, path, name); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + const char *name) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_removexattr(f->fs, path, name); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static struct lock *locks_conflict(struct node *node, const struct lock *lock) { - struct lock *l; + struct lock *l; - for (l = node->locks; l; l = l->next) - if (l->owner != lock->owner && - lock->start <= l->end && l->start <= lock->end && - (l->type == F_WRLCK || lock->type == F_WRLCK)) - break; + for (l = node->locks; l; l = l->next) + if (l->owner != lock->owner && + lock->start <= l->end && l->start <= lock->end && + (l->type == F_WRLCK || lock->type == F_WRLCK)) + break; - return l; + return l; } static void delete_lock(struct lock **lockp) { - struct lock *l = *lockp; - *lockp = l->next; - free(l); + struct lock *l = *lockp; + *lockp = l->next; + free(l); } static void insert_lock(struct lock **pos, struct lock *lock) { - lock->next = *pos; - *pos = lock; + lock->next = *pos; + *pos = lock; } static int locks_insert(struct node *node, struct lock *lock) { - struct lock **lp; - struct lock *newl1 = NULL; - struct lock *newl2 = NULL; - - if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) { - newl1 = malloc(sizeof(struct lock)); - newl2 = malloc(sizeof(struct lock)); - - if (!newl1 || !newl2) { - free(newl1); - free(newl2); - return -ENOLCK; - } - } - - for (lp = &node->locks; *lp;) { - struct lock *l = *lp; - if (l->owner != lock->owner) - goto skip; - - if (lock->type == l->type) { - if (l->end < lock->start - 1) - goto skip; - if (lock->end < l->start - 1) - break; - if (l->start <= lock->start && lock->end <= l->end) - goto out; - if (l->start < lock->start) - lock->start = l->start; - if (lock->end < l->end) - lock->end = l->end; - goto delete; - } else { - if (l->end < lock->start) - goto skip; - if (lock->end < l->start) - break; - if (lock->start <= l->start && l->end <= lock->end) - goto delete; - if (l->end <= lock->end) { - l->end = lock->start - 1; - goto skip; - } - if (lock->start <= l->start) { - l->start = lock->end + 1; - break; - } - *newl2 = *l; - newl2->start = lock->end + 1; - l->end = lock->start - 1; - insert_lock(&l->next, newl2); - newl2 = NULL; - } - skip: - lp = &l->next; - continue; - - delete: - delete_lock(lp); - } - if (lock->type != F_UNLCK) { - *newl1 = *lock; - insert_lock(lp, newl1); - newl1 = NULL; - } + struct lock **lp; + struct lock *newl1 = NULL; + struct lock *newl2 = NULL; + + if (lock->type != F_UNLCK || lock->start != 0 || + lock->end != OFFSET_MAX) { + newl1 = malloc(sizeof(struct lock)); + newl2 = malloc(sizeof(struct lock)); + + if (!newl1 || !newl2) { + free(newl1); + free(newl2); + return -ENOLCK; + } + } + + for (lp = &node->locks; *lp;) { + struct lock *l = *lp; + if (l->owner != lock->owner) + goto skip; + + if (lock->type == l->type) { + if (l->end < lock->start - 1) + goto skip; + if (lock->end < l->start - 1) + break; + if (l->start <= lock->start && lock->end <= l->end) + goto out; + if (l->start < lock->start) + lock->start = l->start; + if (lock->end < l->end) + lock->end = l->end; + goto delete; + } else { + if (l->end < lock->start) + goto skip; + if (lock->end < l->start) + break; + if (lock->start <= l->start && l->end <= lock->end) + goto delete; + if (l->end <= lock->end) { + l->end = lock->start - 1; + goto skip; + } + if (lock->start <= l->start) { + l->start = lock->end + 1; + break; + } + *newl2 = *l; + newl2->start = lock->end + 1; + l->end = lock->start - 1; + insert_lock(&l->next, newl2); + newl2 = NULL; + } + skip: + lp = &l->next; + continue; + + delete: + delete_lock(lp); + } + if (lock->type != F_UNLCK) { + *newl1 = *lock; + insert_lock(lp, newl1); + newl1 = NULL; + } out: - free(newl1); - free(newl2); - return 0; + free(newl1); + free(newl2); + return 0; } static void flock_to_lock(struct flock *flock, struct lock *lock) { - memset(lock, 0, sizeof(struct lock)); - lock->type = flock->l_type; - lock->start = flock->l_start; - lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX; - lock->pid = flock->l_pid; + memset(lock, 0, sizeof(struct lock)); + lock->type = flock->l_type; + lock->start = flock->l_start; + lock->end = + flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX; + lock->pid = flock->l_pid; } static void lock_to_flock(struct lock *lock, struct flock *flock) { - flock->l_type = lock->type; - flock->l_start = lock->start; - flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1; - flock->l_pid = lock->pid; + flock->l_type = lock->type; + flock->l_start = lock->start; + flock->l_len = + (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1; + flock->l_pid = lock->pid; } static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino, - const char *path, struct fuse_file_info *fi) -{ - struct fuse_intr_data d; - struct flock lock; - struct lock l; - int err; - int errlock; - - fuse_prepare_interrupt(f, req, &d); - memset(&lock, 0, sizeof(lock)); - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - err = fuse_fs_flush(f->fs, path, fi); - errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock); - fuse_finish_interrupt(f, req, &d); - - if (errlock != -ENOSYS) { - flock_to_lock(&lock, &l); - l.owner = fi->lock_owner; - pthread_mutex_lock(&f->lock); - locks_insert(get_node(f, ino), &l); - pthread_mutex_unlock(&f->lock); - - /* if op.lock() is defined FLUSH is needed regardless of op.flush() */ - if (err == -ENOSYS) - err = 0; - } - return err; + const char *path, struct fuse_file_info *fi) +{ + struct fuse_intr_data d; + struct flock lock; + struct lock l; + int err; + int errlock; + + fuse_prepare_interrupt(f, req, &d); + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + err = fuse_fs_flush(f->fs, path, fi); + errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock); + fuse_finish_interrupt(f, req, &d); + + if (errlock != -ENOSYS) { + flock_to_lock(&lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + locks_insert(get_node(f, ino), &l); + pthread_mutex_unlock(&f->lock); + + /* if op.lock() is defined FLUSH is needed regardless + of op.flush() */ + if (err == -ENOSYS) + err = 0; + } + return err; } static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - char *path; - int err = 0; + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path; + int err = 0; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (f->conf.debug) - fprintf(stderr, "RELEASE%s[%llu] flags: 0x%x\n", - fi->flush ? "+FLUSH" : "", - (unsigned long long) fi->fh, fi->flags); + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (f->conf.debug) + fprintf(stderr, "RELEASE%s[%llu] flags: 0x%x\n", + fi->flush ? "+FLUSH" : "", + (unsigned long long) fi->fh, fi->flags); - if (fi->flush) { - err = fuse_flush_common(f, req, ino, path, fi); - if (err == -ENOSYS) - err = 0; - } + if (fi->flush) { + err = fuse_flush_common(f, req, ino, path, fi); + if (err == -ENOSYS) + err = 0; + } - fuse_prepare_interrupt(f, req, &d); - fuse_do_release(f, ino, path, fi); - fuse_finish_interrupt(f, req, &d); - free(path); - pthread_rwlock_unlock(&f->tree_lock); + fuse_prepare_interrupt(f, req, &d); + fuse_do_release(f, ino, path, fi); + fuse_finish_interrupt(f, req, &d); + free(path); + pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + reply_err(req, err); } static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path && f->conf.debug) - fprintf(stderr, "FLUSH[%llu]\n", (unsigned long long) fi->fh); - err = fuse_flush_common(f, req, ino, path, fi); - free(path); - pthread_rwlock_unlock(&f->tree_lock); - reply_err(req, err); + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path && f->conf.debug) + fprintf(stderr, "FLUSH[%llu]\n", (unsigned long long) fi->fh); + err = fuse_flush_common(f, req, ino, path, fi); + free(path); + pthread_rwlock_unlock(&f->tree_lock); + reply_err(req, err); } static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi, struct flock *lock, - int cmd) -{ - struct fuse *f = req_fuse_prepare(req); - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - struct fuse_intr_data d; - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_lock(f->fs, path, fi, cmd, lock); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - return err; + struct fuse_file_info *fi, struct flock *lock, + int cmd) +{ + struct fuse *f = req_fuse_prepare(req); + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + struct fuse_intr_data d; + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_lock(f->fs, path, fi, cmd, lock); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + return err; } static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi, struct flock *lock) -{ - int err; - struct lock l; - struct lock *conflict; - struct fuse *f = req_fuse(req); - - flock_to_lock(lock, &l); - l.owner = fi->lock_owner; - pthread_mutex_lock(&f->lock); - conflict = locks_conflict(get_node(f, ino), &l); - if (conflict) - lock_to_flock(conflict, lock); - pthread_mutex_unlock(&f->lock); - if (!conflict) - err = fuse_lock_common(req, ino, fi, lock, F_GETLK); - else - err = 0; - - if (!err) - fuse_reply_lock(req, lock); - else - reply_err(req, err); + struct fuse_file_info *fi, struct flock *lock) +{ + int err; + struct lock l; + struct lock *conflict; + struct fuse *f = req_fuse(req); + + flock_to_lock(lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + conflict = locks_conflict(get_node(f, ino), &l); + if (conflict) + lock_to_flock(conflict, lock); + pthread_mutex_unlock(&f->lock); + if (!conflict) + err = fuse_lock_common(req, ino, fi, lock, F_GETLK); + else + err = 0; + + if (!err) + fuse_reply_lock(req, lock); + else + reply_err(req, err); } static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *fi, struct flock *lock, - int sleep) -{ - int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK); - if (!err) { - struct fuse *f = req_fuse(req); - struct lock l; - flock_to_lock(lock, &l); - l.owner = fi->lock_owner; - pthread_mutex_lock(&f->lock); - locks_insert(get_node(f, ino), &l); - pthread_mutex_unlock(&f->lock); - } - reply_err(req, err); + struct fuse_file_info *fi, struct flock *lock, + int sleep) +{ + int err = fuse_lock_common(req, ino, fi, lock, + sleep ? F_SETLKW : F_SETLK); + if (!err) { + struct fuse *f = req_fuse(req); + struct lock l; + flock_to_lock(lock, &l); + l.owner = fi->lock_owner; + pthread_mutex_lock(&f->lock); + locks_insert(get_node(f, ino), &l); + pthread_mutex_unlock(&f->lock); + } + reply_err(req, err); } static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize, - uint64_t idx) -{ - struct fuse *f = req_fuse_prepare(req); - struct fuse_intr_data d; - char *path; - int err; - - err = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, ino); - if (path != NULL) { - fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_bmap(f->fs, path, blocksize, &idx); - fuse_finish_interrupt(f, req, &d); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - if (!err) - fuse_reply_bmap(req, idx); - else - reply_err(req, err); + uint64_t idx) +{ + struct fuse *f = req_fuse_prepare(req); + struct fuse_intr_data d; + char *path; + int err; + + err = -ENOENT; + pthread_rwlock_rdlock(&f->tree_lock); + path = get_path(f, ino); + if (path != NULL) { + fuse_prepare_interrupt(f, req, &d); + err = fuse_fs_bmap(f->fs, path, blocksize, &idx); + fuse_finish_interrupt(f, req, &d); + free(path); + } + pthread_rwlock_unlock(&f->tree_lock); + if (!err) + fuse_reply_bmap(req, idx); + else + reply_err(req, err); } static struct fuse_lowlevel_ops fuse_path_ops = { - .init = fuse_lib_init, - .destroy = fuse_lib_destroy, - .lookup = fuse_lib_lookup, - .forget = fuse_lib_forget, - .getattr = fuse_lib_getattr, - .setattr = fuse_lib_setattr, - .access = fuse_lib_access, - .readlink = fuse_lib_readlink, - .mknod = fuse_lib_mknod, - .mkdir = fuse_lib_mkdir, - .unlink = fuse_lib_unlink, - .rmdir = fuse_lib_rmdir, - .symlink = fuse_lib_symlink, - .rename = fuse_lib_rename, - .link = fuse_lib_link, - .create = fuse_lib_create, - .open = fuse_lib_open, - .read = fuse_lib_read, - .write = fuse_lib_write, - .flush = fuse_lib_flush, - .release = fuse_lib_release, - .fsync = fuse_lib_fsync, - .opendir = fuse_lib_opendir, - .readdir = fuse_lib_readdir, - .releasedir = fuse_lib_releasedir, - .fsyncdir = fuse_lib_fsyncdir, - .statfs = fuse_lib_statfs, - .setxattr = fuse_lib_setxattr, - .getxattr = fuse_lib_getxattr, - .listxattr = fuse_lib_listxattr, - .removexattr = fuse_lib_removexattr, - .getlk = fuse_lib_getlk, - .setlk = fuse_lib_setlk, - .bmap = fuse_lib_bmap, + .init = fuse_lib_init, + .destroy = fuse_lib_destroy, + .lookup = fuse_lib_lookup, + .forget = fuse_lib_forget, + .getattr = fuse_lib_getattr, + .setattr = fuse_lib_setattr, + .access = fuse_lib_access, + .readlink = fuse_lib_readlink, + .mknod = fuse_lib_mknod, + .mkdir = fuse_lib_mkdir, + .unlink = fuse_lib_unlink, + .rmdir = fuse_lib_rmdir, + .symlink = fuse_lib_symlink, + .rename = fuse_lib_rename, + .link = fuse_lib_link, + .create = fuse_lib_create, + .open = fuse_lib_open, + .read = fuse_lib_read, + .write = fuse_lib_write, + .flush = fuse_lib_flush, + .release = fuse_lib_release, + .fsync = fuse_lib_fsync, + .opendir = fuse_lib_opendir, + .readdir = fuse_lib_readdir, + .releasedir = fuse_lib_releasedir, + .fsyncdir = fuse_lib_fsyncdir, + .statfs = fuse_lib_statfs, + .setxattr = fuse_lib_setxattr, + .getxattr = fuse_lib_getxattr, + .listxattr = fuse_lib_listxattr, + .removexattr = fuse_lib_removexattr, + .getlk = fuse_lib_getlk, + .setlk = fuse_lib_setlk, + .bmap = fuse_lib_bmap, }; static void free_cmd(struct fuse_cmd *cmd) { - free(cmd->buf); - free(cmd); + free(cmd->buf); + free(cmd); } void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) { - fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch); - free_cmd(cmd); + fuse_session_process(f->se, cmd->buf, cmd->buflen, cmd->ch); + free_cmd(cmd); } int fuse_exited(struct fuse *f) { - return fuse_session_exited(f->se); + return fuse_session_exited(f->se); } struct fuse_session *fuse_get_session(struct fuse *f) { - return f->se; + return f->se; } static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize) { - struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd)); - if (cmd == NULL) { - fprintf(stderr, "fuse: failed to allocate cmd\n"); - return NULL; - } - cmd->buf = (char *) malloc(bufsize); - if (cmd->buf == NULL) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - free(cmd); - return NULL; - } - return cmd; + struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd)); + if (cmd == NULL) { + fprintf(stderr, "fuse: failed to allocate cmd\n"); + return NULL; + } + cmd->buf = (char *) malloc(bufsize); + if (cmd->buf == NULL) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + free(cmd); + return NULL; + } + return cmd; } struct fuse_cmd *fuse_read_cmd(struct fuse *f) { - struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL); - size_t bufsize = fuse_chan_bufsize(ch); - struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize); - if (cmd != NULL) { - int res = fuse_chan_recv(&ch, cmd->buf, bufsize); - if (res <= 0) { - free_cmd(cmd); - if (res < 0 && res != -EINTR && res != -EAGAIN) - fuse_exit(f); - return NULL; - } - cmd->buflen = res; - cmd->ch = ch; - } - return cmd; + struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL); + size_t bufsize = fuse_chan_bufsize(ch); + struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize); + if (cmd != NULL) { + int res = fuse_chan_recv(&ch, cmd->buf, bufsize); + if (res <= 0) { + free_cmd(cmd); + if (res < 0 && res != -EINTR && res != -EAGAIN) + fuse_exit(f); + return NULL; + } + cmd->buflen = res; + cmd->ch = ch; + } + return cmd; } int fuse_loop(struct fuse *f) { - if (f) - return fuse_session_loop(f->se); - else - return -1; + if (f) + return fuse_session_loop(f->se); + else + return -1; } int fuse_invalidate(struct fuse *f, const char *path) { - (void) f; - (void) path; - return -EINVAL; + (void) f; + (void) path; + return -EINVAL; } void fuse_exit(struct fuse *f) { - fuse_session_exit(f->se); + fuse_session_exit(f->se); } struct fuse_context *fuse_get_context(void) { - return &fuse_get_context_internal()->ctx; + return &fuse_get_context_internal()->ctx; } int fuse_interrupted(void) { - return fuse_req_interrupted(fuse_get_context_internal()->req); + return fuse_req_interrupted(fuse_get_context_internal()->req); } void fuse_set_getcontext_func(struct fuse_context *(*func)(void)) { - (void) func; - /* no-op */ + (void) func; + /* no-op */ } enum { - KEY_HELP, + KEY_HELP, }; #define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v } static const struct fuse_opt fuse_lib_opts[] = { - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - FUSE_LIB_OPT("debug", debug, 1), - FUSE_LIB_OPT("-d", debug, 1), - FUSE_LIB_OPT("hard_remove", hard_remove, 1), - FUSE_LIB_OPT("use_ino", use_ino, 1), - FUSE_LIB_OPT("readdir_ino", readdir_ino, 1), - FUSE_LIB_OPT("direct_io", direct_io, 1), - FUSE_LIB_OPT("kernel_cache", kernel_cache, 1), - FUSE_LIB_OPT("auto_cache", auto_cache, 1), - FUSE_LIB_OPT("noauto_cache", auto_cache, 0), - FUSE_LIB_OPT("umask=", set_mode, 1), - FUSE_LIB_OPT("umask=%o", umask, 0), - FUSE_LIB_OPT("uid=", set_uid, 1), - FUSE_LIB_OPT("uid=%d", uid, 0), - FUSE_LIB_OPT("gid=", set_gid, 1), - FUSE_LIB_OPT("gid=%d", gid, 0), - FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0), - FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0), - FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0), - FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1), - FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0), - FUSE_LIB_OPT("intr", intr, 1), - FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0), - FUSE_LIB_OPT("modules=%s", modules, 0), - FUSE_OPT_END + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), + FUSE_LIB_OPT("debug", debug, 1), + FUSE_LIB_OPT("-d", debug, 1), + FUSE_LIB_OPT("hard_remove", hard_remove, 1), + FUSE_LIB_OPT("use_ino", use_ino, 1), + FUSE_LIB_OPT("readdir_ino", readdir_ino, 1), + FUSE_LIB_OPT("direct_io", direct_io, 1), + FUSE_LIB_OPT("kernel_cache", kernel_cache, 1), + FUSE_LIB_OPT("auto_cache", auto_cache, 1), + FUSE_LIB_OPT("noauto_cache", auto_cache, 0), + FUSE_LIB_OPT("umask=", set_mode, 1), + FUSE_LIB_OPT("umask=%o", umask, 0), + FUSE_LIB_OPT("uid=", set_uid, 1), + FUSE_LIB_OPT("uid=%d", uid, 0), + FUSE_LIB_OPT("gid=", set_gid, 1), + FUSE_LIB_OPT("gid=%d", gid, 0), + FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0), + FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0), + FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0), + FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1), + FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0), + FUSE_LIB_OPT("intr", intr, 1), + FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0), + FUSE_LIB_OPT("modules=%s", modules, 0), + FUSE_OPT_END }; static void fuse_lib_help(void) { - fprintf(stderr, -" -o hard_remove immediate removal (don't hide files)\n" -" -o use_ino let filesystem set inode numbers\n" -" -o readdir_ino try to fill in d_ino in readdir\n" -" -o direct_io use direct I/O\n" -" -o kernel_cache cache files in kernel\n" -" -o [no]auto_cache enable caching based on modification times\n" -" -o umask=M set file permissions (octal)\n" -" -o uid=N set file owner\n" -" -o gid=N set file group\n" -" -o entry_timeout=T cache timeout for names (1.0s)\n" + fprintf(stderr, +" -o hard_remove immediate removal (don't hide files)\n" +" -o use_ino let filesystem set inode numbers\n" +" -o readdir_ino try to fill in d_ino in readdir\n" +" -o direct_io use direct I/O\n" +" -o kernel_cache cache files in kernel\n" +" -o [no]auto_cache enable caching based on modification times\n" +" -o umask=M set file permissions (octal)\n" +" -o uid=N set file owner\n" +" -o gid=N set file group\n" +" -o entry_timeout=T cache timeout for names (1.0s)\n" " -o negative_timeout=T cache timeout for deleted names (0.0s)\n" -" -o attr_timeout=T cache timeout for attributes (1.0s)\n" +" -o attr_timeout=T cache timeout for attributes (1.0s)\n" " -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n" -" -o intr allow requests to be interrupted\n" -" -o intr_signal=NUM signal to send on interrupt (%i)\n" +" -o intr allow requests to be interrupted\n" +" -o intr_signal=NUM signal to send on interrupt (%i)\n" " -o modules=M1[:M2...] names of modules to push onto filesystem stack\n" "\n", FUSE_DEFAULT_INTR_SIGNAL); } static void fuse_lib_help_modules(void) { - struct fuse_module *m; - fprintf(stderr, "\nModule options:\n"); - pthread_mutex_lock(&fuse_context_lock); - for (m = fuse_modules; m; m = m->next) { - struct fuse_fs *fs = NULL; - struct fuse_fs *newfs; - struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - if (fuse_opt_add_arg(&args, "") != -1 && - fuse_opt_add_arg(&args, "-h") != -1) { - fprintf(stderr, "\n[%s]\n", m->name); - newfs = m->factory(&args, &fs); - assert(newfs == NULL); - } - fuse_opt_free_args(&args); - } - pthread_mutex_unlock(&fuse_context_lock); + struct fuse_module *m; + fprintf(stderr, "\nModule options:\n"); + pthread_mutex_lock(&fuse_context_lock); + for (m = fuse_modules; m; m = m->next) { + struct fuse_fs *fs = NULL; + struct fuse_fs *newfs; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + if (fuse_opt_add_arg(&args, "") != -1 && + fuse_opt_add_arg(&args, "-h") != -1) { + fprintf(stderr, "\n[%s]\n", m->name); + newfs = m->factory(&args, &fs); + assert(newfs == NULL); + } + fuse_opt_free_args(&args); + } + pthread_mutex_unlock(&fuse_context_lock); } static int fuse_lib_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - (void) arg; (void) outargs; + (void) arg; (void) outargs; - if (key == KEY_HELP) { - struct fuse_config *conf = (struct fuse_config *) data; - fuse_lib_help(); - conf->help = 1; - } + if (key == KEY_HELP) { + struct fuse_config *conf = (struct fuse_config *) data; + fuse_lib_help(); + conf->help = 1; + } - return 1; + return 1; } int fuse_is_lib_option(const char *opt) { - return fuse_lowlevel_is_lib_option(opt) || - fuse_opt_match(fuse_lib_opts, opt); + return fuse_lowlevel_is_lib_option(opt) || + fuse_opt_match(fuse_lib_opts, opt); } static int fuse_init_intr_signal(int signum, int *installed) { - struct sigaction old_sa; + struct sigaction old_sa; - if (sigaction(signum, NULL, &old_sa) == -1) { - perror("fuse: cannot get old signal handler"); - return -1; - } + if (sigaction(signum, NULL, &old_sa) == -1) { + perror("fuse: cannot get old signal handler"); + return -1; + } - if (old_sa.sa_handler == SIG_DFL) { - struct sigaction sa; + if (old_sa.sa_handler == SIG_DFL) { + struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = fuse_intr_sighandler; - sigemptyset(&sa.sa_mask); + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = fuse_intr_sighandler; + sigemptyset(&sa.sa_mask); - if (sigaction(signum, &sa, NULL) == -1) { - perror("fuse: cannot set interrupt signal handler"); - return -1; - } - *installed = 1; - } - return 0; + if (sigaction(signum, &sa, NULL) == -1) { + perror("fuse: cannot set interrupt signal handler"); + return -1; + } + *installed = 1; + } + return 0; } static void fuse_restore_intr_signal(int signum) { - struct sigaction sa; + struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = SIG_DFL; - sigaction(signum, &sa, NULL); + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = SIG_DFL; + sigaction(signum, &sa, NULL); } static int fuse_push_module(struct fuse *f, const char *module, - struct fuse_args *args) + struct fuse_args *args) { - struct fuse_fs *fs[2] = { f->fs, NULL }; - struct fuse_fs *newfs; - struct fuse_module *m = fuse_get_module(module); + struct fuse_fs *fs[2] = { f->fs, NULL }; + struct fuse_fs *newfs; + struct fuse_module *m = fuse_get_module(module); - if (!m) - return -1; + if (!m) + return -1; - newfs = m->factory(args, fs); - if (!newfs) { - fuse_put_module(m); - return -1; - } - newfs->m = m; - f->fs = newfs; - return 0; + newfs = m->factory(args, fs); + if (!newfs) { + fuse_put_module(m); + return -1; + } + newfs->m = m; + f->fs = newfs; + return 0; } struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, - void *user_data) + void *user_data) { - struct fuse_fs *fs; + struct fuse_fs *fs; - if (sizeof(struct fuse_operations) < op_size) { - fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); - op_size = sizeof(struct fuse_operations); - } + if (sizeof(struct fuse_operations) < op_size) { + fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); + op_size = sizeof(struct fuse_operations); + } - fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs)); - if (!fs) { - fprintf(stderr, "fuse: failed to allocate fuse_fs object\n"); - return NULL; - } + fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs)); + if (!fs) { + fprintf(stderr, "fuse: failed to allocate fuse_fs object\n"); + return NULL; + } - fs->user_data = user_data; - if (op) - memcpy(&fs->op, op, op_size); - return fs; + fs->user_data = user_data; + if (op) + memcpy(&fs->op, op, op_size); + return fs; } struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, - size_t op_size, void *user_data, int compat) -{ - struct fuse *f; - struct node *root; - struct fuse_fs *fs; - struct fuse_lowlevel_ops llop = fuse_path_ops; - - if (fuse_create_context_key() == -1) - goto out; - - f = (struct fuse *) calloc(1, sizeof(struct fuse)); - if (f == NULL) { - fprintf(stderr, "fuse: failed to allocate fuse object\n"); - goto out_delete_context_key; - } - - fs = fuse_fs_new(op, op_size, user_data); - if (!fs) - goto out_free; - - fs->compat = compat; - f->fs = fs; - - /* Oh f**k, this is ugly! */ - if (!fs->op.lock) { - llop.getlk = NULL; - llop.setlk = NULL; - } - - f->conf.entry_timeout = 1.0; - f->conf.attr_timeout = 1.0; - f->conf.negative_timeout = 0.0; - f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL; - - if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1) - goto out_free_fs; - - if (f->conf.modules) { - char *module; - char *next; - - for (module = f->conf.modules; module; module = next) { - char *p; - for (p = module; *p && *p != ':'; p++); - next = *p ? p + 1 : NULL; - *p = '\0'; - if (module[0] && fuse_push_module(f, module, args) == -1) - goto out_free_fs; - } - } - - if (!f->conf.ac_attr_timeout_set) - f->conf.ac_attr_timeout = f->conf.attr_timeout; + const struct fuse_operations *op, + size_t op_size, void *user_data, int compat) +{ + struct fuse *f; + struct node *root; + struct fuse_fs *fs; + struct fuse_lowlevel_ops llop = fuse_path_ops; + + if (fuse_create_context_key() == -1) + goto out; + + f = (struct fuse *) calloc(1, sizeof(struct fuse)); + if (f == NULL) { + fprintf(stderr, "fuse: failed to allocate fuse object\n"); + goto out_delete_context_key; + } + + fs = fuse_fs_new(op, op_size, user_data); + if (!fs) + goto out_free; + + fs->compat = compat; + f->fs = fs; + + /* Oh f**k, this is ugly! */ + if (!fs->op.lock) { + llop.getlk = NULL; + llop.setlk = NULL; + } + + f->conf.entry_timeout = 1.0; + f->conf.attr_timeout = 1.0; + f->conf.negative_timeout = 0.0; + f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL; + + if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, + fuse_lib_opt_proc) == -1) + goto out_free_fs; + + if (f->conf.modules) { + char *module; + char *next; + + for (module = f->conf.modules; module; module = next) { + char *p; + for (p = module; *p && *p != ':'; p++); + next = *p ? p + 1 : NULL; + *p = '\0'; + if (module[0] && + fuse_push_module(f, module, args) == -1) + goto out_free_fs; + } + } + + if (!f->conf.ac_attr_timeout_set) + f->conf.ac_attr_timeout = f->conf.attr_timeout; #ifdef __FreeBSD__ - /* - * In FreeBSD, we always use these settings as inode numbers are needed to - * make getcwd(3) work. - */ - f->conf.readdir_ino = 1; + /* + * In FreeBSD, we always use these settings as inode numbers + * are needed to make getcwd(3) work. + */ + f->conf.readdir_ino = 1; #endif - if (compat && compat <= 25) { - if (fuse_sync_compat_args(args) == -1) - goto out_free_fs; - } - - f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f); - if (f->se == NULL) { - if (f->conf.help) - fuse_lib_help_modules(); - goto out_free_fs; - } - - fuse_session_add_chan(f->se, ch); - - f->ctr = 0; - f->generation = 0; - /* FIXME: Dynamic hash table */ - f->name_table_size = 14057; - f->name_table = (struct node **) - calloc(1, sizeof(struct node *) * f->name_table_size); - if (f->name_table == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - goto out_free_session; - } - - f->id_table_size = 14057; - f->id_table = (struct node **) - calloc(1, sizeof(struct node *) * f->id_table_size); - if (f->id_table == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - goto out_free_name_table; - } - - fuse_mutex_init(&f->lock); - pthread_rwlock_init(&f->tree_lock, NULL); - - root = (struct node *) calloc(1, sizeof(struct node)); - if (root == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - goto out_free_id_table; - } - - root->name = strdup("/"); - if (root->name == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - goto out_free_root; - } - - if (f->conf.intr && - fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1) - goto out_free_root_name; - - root->parent = NULL; - root->nodeid = FUSE_ROOT_ID; - root->generation = 0; - root->refctr = 1; - root->nlookup = 1; - hash_id(f, root); - - return f; - - out_free_root_name: - free(root->name); - out_free_root: - free(root); - out_free_id_table: - free(f->id_table); - out_free_name_table: - free(f->name_table); - out_free_session: - fuse_session_destroy(f->se); - out_free_fs: - /* Horrible compatibility hack to stop the destructor from being - called on the filesystem without init being called first */ - fs->op.destroy = NULL; - fuse_fs_destroy(f->fs); - free(f->conf.modules); - out_free: - free(f); - out_delete_context_key: - fuse_delete_context_key(); - out: - return NULL; + if (compat && compat <= 25) { + if (fuse_sync_compat_args(args) == -1) + goto out_free_fs; + } + + f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f); + if (f->se == NULL) { + if (f->conf.help) + fuse_lib_help_modules(); + goto out_free_fs; + } + + fuse_session_add_chan(f->se, ch); + + f->ctr = 0; + f->generation = 0; + /* FIXME: Dynamic hash table */ + f->name_table_size = 14057; + f->name_table = (struct node **) + calloc(1, sizeof(struct node *) * f->name_table_size); + if (f->name_table == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_session; + } + + f->id_table_size = 14057; + f->id_table = (struct node **) + calloc(1, sizeof(struct node *) * f->id_table_size); + if (f->id_table == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_name_table; + } + + fuse_mutex_init(&f->lock); + pthread_rwlock_init(&f->tree_lock, NULL); + + root = (struct node *) calloc(1, sizeof(struct node)); + if (root == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_id_table; + } + + root->name = strdup("/"); + if (root->name == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + goto out_free_root; + } + + if (f->conf.intr && + fuse_init_intr_signal(f->conf.intr_signal, + &f->intr_installed) == -1) + goto out_free_root_name; + + root->parent = NULL; + root->nodeid = FUSE_ROOT_ID; + root->generation = 0; + root->refctr = 1; + root->nlookup = 1; + hash_id(f, root); + + return f; + +out_free_root_name: + free(root->name); +out_free_root: + free(root); +out_free_id_table: + free(f->id_table); +out_free_name_table: + free(f->name_table); +out_free_session: + fuse_session_destroy(f->se); +out_free_fs: + /* Horrible compatibility hack to stop the destructor from being + called on the filesystem without init being called first */ + fs->op.destroy = NULL; + fuse_fs_destroy(f->fs); + free(f->conf.modules); +out_free: + free(f); +out_delete_context_key: + fuse_delete_context_key(); +out: + return NULL; } struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, size_t op_size, - void *user_data) + const struct fuse_operations *op, size_t op_size, + void *user_data) { - return fuse_new_common(ch, args, op, op_size, user_data, 0); + return fuse_new_common(ch, args, op, op_size, user_data, 0); } void fuse_destroy(struct fuse *f) { - size_t i; - - if (f->conf.intr && f->intr_installed) - fuse_restore_intr_signal(f->conf.intr_signal); - - if (f->fs) { - struct fuse_context_i *c = fuse_get_context_internal(); - - memset(c, 0, sizeof(*c)); - c->ctx.fuse = f; - - for (i = 0; i < f->id_table_size; i++) { - struct node *node; - - for (node = f->id_table[i]; node != NULL; node = node->id_next) { - if (node->is_hidden) { - char *path = get_path(f, node->nodeid); - if (path) { - fuse_fs_unlink(f->fs, path); - free(path); - } - } - } - } - } - for (i = 0; i < f->id_table_size; i++) { - struct node *node; - struct node *next; - - for (node = f->id_table[i]; node != NULL; node = next) { - next = node->id_next; - free_node(node); - } - } - free(f->id_table); - free(f->name_table); - pthread_mutex_destroy(&f->lock); - pthread_rwlock_destroy(&f->tree_lock); - fuse_session_destroy(f->se); - free(f->conf.modules); - free(f); - fuse_delete_context_key(); + size_t i; + + if (f->conf.intr && f->intr_installed) + fuse_restore_intr_signal(f->conf.intr_signal); + + if (f->fs) { + struct fuse_context_i *c = fuse_get_context_internal(); + + memset(c, 0, sizeof(*c)); + c->ctx.fuse = f; + + for (i = 0; i < f->id_table_size; i++) { + struct node *node; + + for (node = f->id_table[i]; node != NULL; + node = node->id_next) { + if (node->is_hidden) { + char *path = get_path(f, node->nodeid); + if (path) { + fuse_fs_unlink(f->fs, path); + free(path); + } + } + } + } + } + for (i = 0; i < f->id_table_size; i++) { + struct node *node; + struct node *next; + + for (node = f->id_table[i]; node != NULL; node = next) { + next = node->id_next; + free_node(node); + } + } + free(f->id_table); + free(f->name_table); + pthread_mutex_destroy(&f->lock); + pthread_rwlock_destroy(&f->tree_lock); + fuse_session_destroy(f->se); + free(f->conf.modules); + free(f); + fuse_delete_context_key(); } static struct fuse *fuse_new_common_compat25(int fd, struct fuse_args *args, - const struct fuse_operations *op, - size_t op_size, int compat) + const struct fuse_operations *op, + size_t op_size, int compat) { - struct fuse *f = NULL; - struct fuse_chan *ch = fuse_kern_chan_new(fd); + struct fuse *f = NULL; + struct fuse_chan *ch = fuse_kern_chan_new(fd); - if (ch) - f = fuse_new_common(ch, args, op, op_size, NULL, compat); + if (ch) + f = fuse_new_common(ch, args, op, op_size, NULL, compat); - return f; + return f; } /* called with fuse_context_lock held or during initialization (before main() has been called) */ void fuse_register_module(struct fuse_module *mod) { - mod->ctr = 0; - mod->so = fuse_current_so; - if (mod->so) - mod->so->ctr++; - mod->next = fuse_modules; - fuse_modules = mod; + mod->ctr = 0; + mod->so = fuse_current_so; + if (mod->so) + mod->so->ctr++; + mod->next = fuse_modules; + fuse_modules = mod; } #ifndef __FreeBSD__ static struct fuse *fuse_new_common_compat(int fd, const char *opts, - const struct fuse_operations *op, - size_t op_size, int compat) + const struct fuse_operations *op, + size_t op_size, int compat) { - struct fuse *f; - struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + struct fuse *f; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - if (fuse_opt_add_arg(&args, "") == -1) - return NULL; - if (opts && - (fuse_opt_add_arg(&args, "-o") == -1 || - fuse_opt_add_arg(&args, opts) == -1)) { - fuse_opt_free_args(&args); - return NULL; - } - f = fuse_new_common_compat25(fd, &args, op, op_size, compat); - fuse_opt_free_args(&args); + if (fuse_opt_add_arg(&args, "") == -1) + return NULL; + if (opts && + (fuse_opt_add_arg(&args, "-o") == -1 || + fuse_opt_add_arg(&args, opts) == -1)) { + fuse_opt_free_args(&args); + return NULL; + } + f = fuse_new_common_compat25(fd, &args, op, op_size, compat); + fuse_opt_free_args(&args); - return f; + return f; } struct fuse *fuse_new_compat22(int fd, const char *opts, - const struct fuse_operations_compat22 *op, - size_t op_size) + const struct fuse_operations_compat22 *op, + size_t op_size) { - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - op_size, 22); + return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, + op_size, 22); } struct fuse *fuse_new_compat2(int fd, const char *opts, - const struct fuse_operations_compat2 *op) + const struct fuse_operations_compat2 *op) { - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), 21); + return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat2), + 21); } struct fuse *fuse_new_compat1(int fd, int flags, - const struct fuse_operations_compat1 *op) + const struct fuse_operations_compat1 *op) { - const char *opts = NULL; - if (flags & FUSE_DEBUG_COMPAT1) - opts = "debug"; - return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat1), 11); + const char *opts = NULL; + if (flags & FUSE_DEBUG_COMPAT1) + opts = "debug"; + return fuse_new_common_compat(fd, opts, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat1), + 11); } FUSE_SYMVER(".symver fuse_exited,__fuse_exited@"); @@ -3300,11 +3339,11 @@ FUSE_SYMVER(".symver fuse_new_compat22,fuse_new@FUSE_2.2"); #endif /* __FreeBSD__ */ struct fuse *fuse_new_compat25(int fd, struct fuse_args *args, - const struct fuse_operations_compat25 *op, - size_t op_size) + const struct fuse_operations_compat25 *op, + size_t op_size) { - return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op, - op_size, 25); + return fuse_new_common_compat25(fd, args, (struct fuse_operations *) op, + op_size, 25); } FUSE_SYMVER(".symver fuse_new_compat25,fuse_new@FUSE_2.5"); diff --git a/lib/fuse_i.h b/lib/fuse_i.h index 55ce048..ec6e5d6 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse.h" @@ -14,22 +14,22 @@ struct fuse_lowlevel_ops; struct fuse_req; struct fuse_cmd { - char *buf; - size_t buflen; - struct fuse_chan *ch; + char *buf; + size_t buflen; + struct fuse_chan *ch; }; struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, - const struct fuse_operations *op, - size_t op_size, void *user_data, int compat); + const struct fuse_operations *op, + size_t op_size, void *user_data, int compat); int fuse_sync_compat_args(struct fuse_args *args); struct fuse_chan *fuse_kern_chan_new(int fd); struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata); + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata); void fuse_kern_unmount_compat22(const char *mountpoint); void fuse_kern_unmount(const char *mountpoint, int fd); diff --git a/lib/fuse_kern_chan.c b/lib/fuse_kern_chan.c index 49e88b7..03291c3 100644 --- a/lib/fuse_kern_chan.c +++ b/lib/fuse_kern_chan.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_lowlevel.h" @@ -16,80 +16,80 @@ #include <assert.h> static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf, - size_t size) + size_t size) { - struct fuse_chan *ch = *chp; - int err; - ssize_t res; - struct fuse_session *se = fuse_chan_session(ch); - assert(se != NULL); + struct fuse_chan *ch = *chp; + int err; + ssize_t res; + struct fuse_session *se = fuse_chan_session(ch); + assert(se != NULL); - restart: - res = read(fuse_chan_fd(ch), buf, size); - err = errno; +restart: + res = read(fuse_chan_fd(ch), buf, size); + err = errno; - if (fuse_session_exited(se)) - return 0; - if (res == -1) { - /* ENOENT means the operation was interrupted, it's safe - to restart */ - if (err == ENOENT) - goto restart; + if (fuse_session_exited(se)) + return 0; + if (res == -1) { + /* ENOENT means the operation was interrupted, it's safe + to restart */ + if (err == ENOENT) + goto restart; - if (err == ENODEV) { - fuse_session_exit(se); - return 0; - } - /* Errors occuring during normal operation: EINTR (read - interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem - umounted) */ - if (err != EINTR && err != EAGAIN) - perror("fuse: reading device"); - return -err; - } - if ((size_t) res < sizeof(struct fuse_in_header)) { - fprintf(stderr, "short read on fuse device\n"); - return -EIO; - } - return res; + if (err == ENODEV) { + fuse_session_exit(se); + return 0; + } + /* Errors occuring during normal operation: EINTR (read + interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem + umounted) */ + if (err != EINTR && err != EAGAIN) + perror("fuse: reading device"); + return -err; + } + if ((size_t) res < sizeof(struct fuse_in_header)) { + fprintf(stderr, "short read on fuse device\n"); + return -EIO; + } + return res; } static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[], - size_t count) + size_t count) { - if (iov) { - ssize_t res = writev(fuse_chan_fd(ch), iov, count); - int err = errno; + if (iov) { + ssize_t res = writev(fuse_chan_fd(ch), iov, count); + int err = errno; - if (res == -1) { - struct fuse_session *se = fuse_chan_session(ch); + if (res == -1) { + struct fuse_session *se = fuse_chan_session(ch); - assert(se != NULL); + assert(se != NULL); - /* ENOENT means the operation was interrupted */ - if (!fuse_session_exited(se) && err != ENOENT) - perror("fuse: writing device"); - return -err; - } - } - return 0; + /* ENOENT means the operation was interrupted */ + if (!fuse_session_exited(se) && err != ENOENT) + perror("fuse: writing device"); + return -err; + } + } + return 0; } static void fuse_kern_chan_destroy(struct fuse_chan *ch) { - close(fuse_chan_fd(ch)); + close(fuse_chan_fd(ch)); } #define MIN_BUFSIZE 0x21000 struct fuse_chan *fuse_kern_chan_new(int fd) { - struct fuse_chan_ops op = { - .receive = fuse_kern_chan_receive, - .send = fuse_kern_chan_send, - .destroy = fuse_kern_chan_destroy, - }; - size_t bufsize = getpagesize() + 0x1000; - bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize; - return fuse_chan_new(&op, fd, bufsize, NULL); + struct fuse_chan_ops op = { + .receive = fuse_kern_chan_receive, + .send = fuse_kern_chan_send, + .destroy = fuse_kern_chan_destroy, + }; + size_t bufsize = getpagesize() + 0x1000; + bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize; + return fuse_chan_new(&op, fd, bufsize, NULL); } diff --git a/lib/fuse_loop.c b/lib/fuse_loop.c index f7c17fa..104c5d4 100644 --- a/lib/fuse_loop.c +++ b/lib/fuse_loop.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_lowlevel.h" @@ -14,26 +14,26 @@ int fuse_session_loop(struct fuse_session *se) { - int res = 0; - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - size_t bufsize = fuse_chan_bufsize(ch); - char *buf = (char *) malloc(bufsize); - if (!buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - return -1; - } + int res = 0; + struct fuse_chan *ch = fuse_session_next_chan(se, NULL); + size_t bufsize = fuse_chan_bufsize(ch); + char *buf = (char *) malloc(bufsize); + if (!buf) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + return -1; + } - while (!fuse_session_exited(se)) { - struct fuse_chan *tmpch = ch; - res = fuse_chan_recv(&tmpch, buf, bufsize); - if (res == -EINTR) - continue; - if (res <= 0) - break; - fuse_session_process(se, buf, res, tmpch); - } + while (!fuse_session_exited(se)) { + struct fuse_chan *tmpch = ch; + res = fuse_chan_recv(&tmpch, buf, bufsize); + if (res == -EINTR) + continue; + if (res <= 0) + break; + fuse_session_process(se, buf, res, tmpch); + } - free(buf); - fuse_session_reset(se); - return res < 0 ? -1 : 0; + free(buf); + fuse_session_reset(se); + return res < 0 ? -1 : 0; } diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c index 533d9c3..dba8dbc 100644 --- a/lib/fuse_loop_mt.c +++ b/lib/fuse_loop_mt.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "fuse_lowlevel.h" @@ -20,202 +20,203 @@ #include <sys/time.h> struct fuse_worker { - struct fuse_worker *prev; - struct fuse_worker *next; - pthread_t thread_id; - size_t bufsize; - char *buf; - struct fuse_mt *mt; + struct fuse_worker *prev; + struct fuse_worker *next; + pthread_t thread_id; + size_t bufsize; + char *buf; + struct fuse_mt *mt; }; struct fuse_mt { - pthread_mutex_t lock; - int numworker; - int numavail; - struct fuse_session *se; - struct fuse_chan *prevch; - struct fuse_worker main; - sem_t finish; - int exit; - int error; + pthread_mutex_t lock; + int numworker; + int numavail; + struct fuse_session *se; + struct fuse_chan *prevch; + struct fuse_worker main; + sem_t finish; + int exit; + int error; }; static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next) { - struct fuse_worker *prev = next->prev; - w->next = next; - w->prev = prev; - prev->next = w; - next->prev = w; + struct fuse_worker *prev = next->prev; + w->next = next; + w->prev = prev; + prev->next = w; + next->prev = w; } static void list_del_worker(struct fuse_worker *w) { - struct fuse_worker *prev = w->prev; - struct fuse_worker *next = w->next; - prev->next = next; - next->prev = prev; + struct fuse_worker *prev = w->prev; + struct fuse_worker *next = w->next; + prev->next = next; + next->prev = prev; } static int fuse_start_thread(struct fuse_mt *mt); static void *fuse_do_work(void *data) { - struct fuse_worker *w = (struct fuse_worker *) data; - struct fuse_mt *mt = w->mt; - - while (!fuse_session_exited(mt->se)) { - int isforget = 0; - struct fuse_chan *ch = mt->prevch; - int res = fuse_chan_recv(&ch, w->buf, w->bufsize); - if (res == -EINTR) - continue; - if (res <= 0) { - if (res < 0) { - fuse_session_exit(mt->se); - mt->error = -1; - } - break; - } - - pthread_mutex_lock(&mt->lock); - if (mt->exit) { - pthread_mutex_unlock(&mt->lock); - return NULL; - } - - /* - * This disgusting hack is needed so that zillions of threads - * are not created on a burst of FORGET messages - */ - if (((struct fuse_in_header *) w->buf)->opcode == FUSE_FORGET) - isforget = 1; - - if (!isforget) - mt->numavail--; - if (mt->numavail == 0) - fuse_start_thread(mt); - pthread_mutex_unlock(&mt->lock); - - fuse_session_process(mt->se, w->buf, res, ch); - - pthread_mutex_lock(&mt->lock); - if (!isforget) - mt->numavail++; - if (mt->numavail > 10) { - if (mt->exit) { - pthread_mutex_unlock(&mt->lock); - return NULL; - } - list_del_worker(w); - mt->numavail--; - mt->numworker--; - pthread_mutex_unlock(&mt->lock); - - pthread_detach(w->thread_id); - free(w->buf); - free(w); - return NULL; - } - pthread_mutex_unlock(&mt->lock); - } - - sem_post(&mt->finish); - pause(); - - return NULL; + struct fuse_worker *w = (struct fuse_worker *) data; + struct fuse_mt *mt = w->mt; + + while (!fuse_session_exited(mt->se)) { + int isforget = 0; + struct fuse_chan *ch = mt->prevch; + int res = fuse_chan_recv(&ch, w->buf, w->bufsize); + if (res == -EINTR) + continue; + if (res <= 0) { + if (res < 0) { + fuse_session_exit(mt->se); + mt->error = -1; + } + break; + } + + pthread_mutex_lock(&mt->lock); + if (mt->exit) { + pthread_mutex_unlock(&mt->lock); + return NULL; + } + + /* + * This disgusting hack is needed so that zillions of threads + * are not created on a burst of FORGET messages + */ + if (((struct fuse_in_header *) w->buf)->opcode == FUSE_FORGET) + isforget = 1; + + if (!isforget) + mt->numavail--; + if (mt->numavail == 0) + fuse_start_thread(mt); + pthread_mutex_unlock(&mt->lock); + + fuse_session_process(mt->se, w->buf, res, ch); + + pthread_mutex_lock(&mt->lock); + if (!isforget) + mt->numavail++; + if (mt->numavail > 10) { + if (mt->exit) { + pthread_mutex_unlock(&mt->lock); + return NULL; + } + list_del_worker(w); + mt->numavail--; + mt->numworker--; + pthread_mutex_unlock(&mt->lock); + + pthread_detach(w->thread_id); + free(w->buf); + free(w); + return NULL; + } + pthread_mutex_unlock(&mt->lock); + } + + sem_post(&mt->finish); + pause(); + + return NULL; } static int fuse_start_thread(struct fuse_mt *mt) { - sigset_t oldset; - sigset_t newset; - int res; - struct fuse_worker *w = malloc(sizeof(struct fuse_worker)); - if (!w) { - fprintf(stderr, "fuse: failed to allocate worker structure\n"); - return -1; - } - memset(w, 0, sizeof(struct fuse_worker)); - w->bufsize = fuse_chan_bufsize(mt->prevch); - w->buf = malloc(w->bufsize); - w->mt = mt; - if (!w->buf) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - free(w); - return -1; - } - - /* Disallow signal reception in worker threads */ - sigemptyset(&newset); - sigaddset(&newset, SIGTERM); - sigaddset(&newset, SIGINT); - sigaddset(&newset, SIGHUP); - sigaddset(&newset, SIGQUIT); - pthread_sigmask(SIG_BLOCK, &newset, &oldset); - res = pthread_create(&w->thread_id, NULL, fuse_do_work, w); - pthread_sigmask(SIG_SETMASK, &oldset, NULL); - if (res != 0) { - fprintf(stderr, "fuse: error creating thread: %s\n", strerror(res)); - free(w->buf); - free(w); - return -1; - } - list_add_worker(w, &mt->main); - mt->numavail ++; - mt->numworker ++; - - return 0; + sigset_t oldset; + sigset_t newset; + int res; + struct fuse_worker *w = malloc(sizeof(struct fuse_worker)); + if (!w) { + fprintf(stderr, "fuse: failed to allocate worker structure\n"); + return -1; + } + memset(w, 0, sizeof(struct fuse_worker)); + w->bufsize = fuse_chan_bufsize(mt->prevch); + w->buf = malloc(w->bufsize); + w->mt = mt; + if (!w->buf) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + free(w); + return -1; + } + + /* Disallow signal reception in worker threads */ + sigemptyset(&newset); + sigaddset(&newset, SIGTERM); + sigaddset(&newset, SIGINT); + sigaddset(&newset, SIGHUP); + sigaddset(&newset, SIGQUIT); + pthread_sigmask(SIG_BLOCK, &newset, &oldset); + res = pthread_create(&w->thread_id, NULL, fuse_do_work, w); + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + if (res != 0) { + fprintf(stderr, "fuse: error creating thread: %s\n", + strerror(res)); + free(w->buf); + free(w); + return -1; + } + list_add_worker(w, &mt->main); + mt->numavail ++; + mt->numworker ++; + + return 0; } static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w) { - pthread_join(w->thread_id, NULL); - pthread_mutex_lock(&mt->lock); - list_del_worker(w); - pthread_mutex_unlock(&mt->lock); - free(w->buf); - free(w); + pthread_join(w->thread_id, NULL); + pthread_mutex_lock(&mt->lock); + list_del_worker(w); + pthread_mutex_unlock(&mt->lock); + free(w->buf); + free(w); } int fuse_session_loop_mt(struct fuse_session *se) { - int err; - struct fuse_mt mt; - struct fuse_worker *w; - - memset(&mt, 0, sizeof(struct fuse_mt)); - mt.se = se; - mt.prevch = fuse_session_next_chan(se, NULL); - mt.error = 0; - mt.numworker = 0; - mt.numavail = 0; - mt.main.thread_id = pthread_self(); - mt.main.prev = mt.main.next = &mt.main; - sem_init(&mt.finish, 0, 0); - fuse_mutex_init(&mt.lock); - - pthread_mutex_lock(&mt.lock); - err = fuse_start_thread(&mt); - pthread_mutex_unlock(&mt.lock); - if (!err) { - /* sem_wait() is interruptible */ - while (!fuse_session_exited(se)) - sem_wait(&mt.finish); - - for (w = mt.main.next; w != &mt.main; w = w->next) - pthread_cancel(w->thread_id); - mt.exit = 1; - pthread_mutex_unlock(&mt.lock); - - while (mt.main.next != &mt.main) - fuse_join_worker(&mt, mt.main.next); - - err = mt.error; - } - - pthread_mutex_destroy(&mt.lock); - sem_destroy(&mt.finish); - fuse_session_reset(se); - return err; + int err; + struct fuse_mt mt; + struct fuse_worker *w; + + memset(&mt, 0, sizeof(struct fuse_mt)); + mt.se = se; + mt.prevch = fuse_session_next_chan(se, NULL); + mt.error = 0; + mt.numworker = 0; + mt.numavail = 0; + mt.main.thread_id = pthread_self(); + mt.main.prev = mt.main.next = &mt.main; + sem_init(&mt.finish, 0, 0); + fuse_mutex_init(&mt.lock); + + pthread_mutex_lock(&mt.lock); + err = fuse_start_thread(&mt); + pthread_mutex_unlock(&mt.lock); + if (!err) { + /* sem_wait() is interruptible */ + while (!fuse_session_exited(se)) + sem_wait(&mt.finish); + + for (w = mt.main.next; w != &mt.main; w = w->next) + pthread_cancel(w->thread_id); + mt.exit = 1; + pthread_mutex_unlock(&mt.lock); + + while (mt.main.next != &mt.main) + fuse_join_worker(&mt, mt.main.next); + + err = mt.error; + } + + pthread_mutex_destroy(&mt.lock); + sem_destroy(&mt.finish); + fuse_session_reset(se); + return err; } diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index d39a4a1..5c9dc56 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_lowlevel.h" @@ -28,1225 +28,1234 @@ struct fuse_ll; struct fuse_req { - struct fuse_ll *f; - uint64_t unique; - int ctr; - pthread_mutex_t lock; - struct fuse_ctx ctx; - struct fuse_chan *ch; - int interrupted; - union { - struct { - uint64_t unique; - } i; - struct { - fuse_interrupt_func_t func; - void *data; - } ni; - } u; - struct fuse_req *next; - struct fuse_req *prev; + struct fuse_ll *f; + uint64_t unique; + int ctr; + pthread_mutex_t lock; + struct fuse_ctx ctx; + struct fuse_chan *ch; + int interrupted; + union { + struct { + uint64_t unique; + } i; + struct { + fuse_interrupt_func_t func; + void *data; + } ni; + } u; + struct fuse_req *next; + struct fuse_req *prev; }; struct fuse_ll { - int debug; - int allow_root; - struct fuse_lowlevel_ops op; - int got_init; - void *userdata; - uid_t owner; - struct fuse_conn_info conn; - struct fuse_req list; - struct fuse_req interrupts; - pthread_mutex_t lock; - int got_destroy; + int debug; + int allow_root; + struct fuse_lowlevel_ops op; + int got_init; + void *userdata; + uid_t owner; + struct fuse_conn_info conn; + struct fuse_req list; + struct fuse_req interrupts; + pthread_mutex_t lock; + int got_destroy; }; static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr) { - attr->ino = stbuf->st_ino; - attr->mode = stbuf->st_mode; - attr->nlink = stbuf->st_nlink; - attr->uid = stbuf->st_uid; - attr->gid = stbuf->st_gid; - attr->rdev = stbuf->st_rdev; - attr->size = stbuf->st_size; - attr->blocks = stbuf->st_blocks; - attr->atime = stbuf->st_atime; - attr->mtime = stbuf->st_mtime; - attr->ctime = stbuf->st_ctime; - attr->atimensec = ST_ATIM_NSEC(stbuf); - attr->mtimensec = ST_MTIM_NSEC(stbuf); - attr->ctimensec = ST_CTIM_NSEC(stbuf); + attr->ino = stbuf->st_ino; + attr->mode = stbuf->st_mode; + attr->nlink = stbuf->st_nlink; + attr->uid = stbuf->st_uid; + attr->gid = stbuf->st_gid; + attr->rdev = stbuf->st_rdev; + attr->size = stbuf->st_size; + attr->blocks = stbuf->st_blocks; + attr->atime = stbuf->st_atime; + attr->mtime = stbuf->st_mtime; + attr->ctime = stbuf->st_ctime; + attr->atimensec = ST_ATIM_NSEC(stbuf); + attr->mtimensec = ST_MTIM_NSEC(stbuf); + attr->ctimensec = ST_CTIM_NSEC(stbuf); } static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf) { - stbuf->st_mode = attr->mode; - stbuf->st_uid = attr->uid; - stbuf->st_gid = attr->gid; - stbuf->st_size = attr->size; - stbuf->st_atime = attr->atime; - stbuf->st_mtime = attr->mtime; - ST_ATIM_NSEC_SET(stbuf, attr->atimensec); - ST_MTIM_NSEC_SET(stbuf, attr->mtimensec); + stbuf->st_mode = attr->mode; + stbuf->st_uid = attr->uid; + stbuf->st_gid = attr->gid; + stbuf->st_size = attr->size; + stbuf->st_atime = attr->atime; + stbuf->st_mtime = attr->mtime; + ST_ATIM_NSEC_SET(stbuf, attr->atimensec); + ST_MTIM_NSEC_SET(stbuf, attr->mtimensec); } -static size_t iov_length(const struct iovec *iov, size_t count) +static size_t iov_length(const struct iovec *iov, size_t count) { - size_t seg; - size_t ret = 0; + size_t seg; + size_t ret = 0; - for (seg = 0; seg < count; seg++) - ret += iov[seg].iov_len; - return ret; + for (seg = 0; seg < count; seg++) + ret += iov[seg].iov_len; + return ret; } static void list_init_req(struct fuse_req *req) { - req->next = req; - req->prev = req; + req->next = req; + req->prev = req; } static void list_del_req(struct fuse_req *req) { - struct fuse_req *prev = req->prev; - struct fuse_req *next = req->next; - prev->next = next; - next->prev = prev; + struct fuse_req *prev = req->prev; + struct fuse_req *next = req->next; + prev->next = next; + next->prev = prev; } static void list_add_req(struct fuse_req *req, struct fuse_req *next) { - struct fuse_req *prev = next->prev; - req->next = next; - req->prev = prev; - prev->next = req; - next->prev = req; + struct fuse_req *prev = next->prev; + req->next = next; + req->prev = prev; + prev->next = req; + next->prev = req; } static void destroy_req(fuse_req_t req) { - pthread_mutex_destroy(&req->lock); - free(req); + pthread_mutex_destroy(&req->lock); + free(req); } static void free_req(fuse_req_t req) { - int ctr; - struct fuse_ll *f = req->f; + int ctr; + struct fuse_ll *f = req->f; - pthread_mutex_lock(&req->lock); - req->u.ni.func = NULL; - req->u.ni.data = NULL; - pthread_mutex_unlock(&req->lock); + pthread_mutex_lock(&req->lock); + req->u.ni.func = NULL; + req->u.ni.data = NULL; + pthread_mutex_unlock(&req->lock); - pthread_mutex_lock(&f->lock); - list_del_req(req); - ctr = --req->ctr; - pthread_mutex_unlock(&f->lock); - if (!ctr) - destroy_req(req); + pthread_mutex_lock(&f->lock); + list_del_req(req); + ctr = --req->ctr; + pthread_mutex_unlock(&f->lock); + if (!ctr) + destroy_req(req); } static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, - int count) + int count) { - struct fuse_out_header out; - int res; + struct fuse_out_header out; + int res; - if (error <= -1000 || error > 0) { - fprintf(stderr, "fuse: bad error value: %i\n", error); - error = -ERANGE; - } + if (error <= -1000 || error > 0) { + fprintf(stderr, "fuse: bad error value: %i\n", error); + error = -ERANGE; + } - out.unique = req->unique; - out.error = error; - iov[0].iov_base = &out; - iov[0].iov_len = sizeof(struct fuse_out_header); - out.len = iov_length(iov, count); + out.unique = req->unique; + out.error = error; + iov[0].iov_base = &out; + iov[0].iov_len = sizeof(struct fuse_out_header); + out.len = iov_length(iov, count); - if (req->f->debug) - fprintf(stderr, " unique: %llu, error: %i (%s), outsize: %i\n", - (unsigned long long) out.unique, out.error, - strerror(-out.error), out.len); - res = fuse_chan_send(req->ch, iov, count); - free_req(req); + if (req->f->debug) + fprintf(stderr, + " unique: %llu, error: %i (%s), outsize: %i\n", + (unsigned long long) out.unique, out.error, + strerror(-out.error), out.len); + res = fuse_chan_send(req->ch, iov, count); + free_req(req); - return res; + return res; } static int send_reply(fuse_req_t req, int error, const void *arg, - size_t argsize) + size_t argsize) { - struct iovec iov[2]; - int count = 1; - if (argsize) { - iov[1].iov_base = (void *) arg; - iov[1].iov_len = argsize; - count++; - } - return send_reply_iov(req, error, iov, count); + struct iovec iov[2]; + int count = 1; + if (argsize) { + iov[1].iov_base = (void *) arg; + iov[1].iov_len = argsize; + count++; + } + return send_reply_iov(req, error, iov, count); } int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count) { - int res; - struct iovec *padded_iov; + int res; + struct iovec *padded_iov; - padded_iov = malloc((count + 1) * sizeof(struct iovec)); - if (padded_iov == NULL) - return fuse_reply_err(req, -ENOMEM); + padded_iov = malloc((count + 1) * sizeof(struct iovec)); + if (padded_iov == NULL) + return fuse_reply_err(req, -ENOMEM); - memcpy(padded_iov + 1, iov, count * sizeof(struct iovec)); - count++; + memcpy(padded_iov + 1, iov, count * sizeof(struct iovec)); + count++; - res = send_reply_iov(req, 0, padded_iov, count); - free(padded_iov); + res = send_reply_iov(req, 0, padded_iov, count); + free(padded_iov); - return res; + return res; } size_t fuse_dirent_size(size_t namelen) { - return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); + return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); } char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, - off_t off) + off_t off) { - unsigned namelen = strlen(name); - unsigned entlen = FUSE_NAME_OFFSET + namelen; - unsigned entsize = fuse_dirent_size(namelen); - unsigned padlen = entsize - entlen; - struct fuse_dirent *dirent = (struct fuse_dirent *) buf; + unsigned namelen = strlen(name); + unsigned entlen = FUSE_NAME_OFFSET + namelen; + unsigned entsize = fuse_dirent_size(namelen); + unsigned padlen = entsize - entlen; + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; - dirent->ino = stbuf->st_ino; - dirent->off = off; - dirent->namelen = namelen; - dirent->type = (stbuf->st_mode & 0170000) >> 12; - strncpy(dirent->name, name, namelen); - if (padlen) - memset(buf + entlen, 0, padlen); + dirent->ino = stbuf->st_ino; + dirent->off = off; + dirent->namelen = namelen; + dirent->type = (stbuf->st_mode & 0170000) >> 12; + strncpy(dirent->name, name, namelen); + if (padlen) + memset(buf + entlen, 0, padlen); - return buf + entsize; + return buf + entsize; } size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, - const char *name, const struct stat *stbuf, off_t off) + const char *name, const struct stat *stbuf, off_t off) { - size_t entsize; + size_t entsize; - (void) req; - entsize = fuse_dirent_size(strlen(name)); - if (entsize <= bufsize && buf) - fuse_add_dirent(buf, name, stbuf, off); - return entsize; + (void) req; + entsize = fuse_dirent_size(strlen(name)); + if (entsize <= bufsize && buf) + fuse_add_dirent(buf, name, stbuf, off); + return entsize; } static void convert_statfs(const struct statvfs *stbuf, - struct fuse_kstatfs *kstatfs) + struct fuse_kstatfs *kstatfs) { - kstatfs->bsize = stbuf->f_bsize; - kstatfs->frsize = stbuf->f_frsize; - kstatfs->blocks = stbuf->f_blocks; - kstatfs->bfree = stbuf->f_bfree; - kstatfs->bavail = stbuf->f_bavail; - kstatfs->files = stbuf->f_files; - kstatfs->ffree = stbuf->f_ffree; - kstatfs->namelen = stbuf->f_namemax; + kstatfs->bsize = stbuf->f_bsize; + kstatfs->frsize = stbuf->f_frsize; + kstatfs->blocks = stbuf->f_blocks; + kstatfs->bfree = stbuf->f_bfree; + kstatfs->bavail = stbuf->f_bavail; + kstatfs->files = stbuf->f_files; + kstatfs->ffree = stbuf->f_ffree; + kstatfs->namelen = stbuf->f_namemax; } static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize) { - return send_reply(req, 0, arg, argsize); + return send_reply(req, 0, arg, argsize); } int fuse_reply_err(fuse_req_t req, int err) { - return send_reply(req, -err, NULL, 0); + return send_reply(req, -err, NULL, 0); } void fuse_reply_none(fuse_req_t req) { - fuse_chan_send(req->ch, NULL, 0); - free_req(req); + fuse_chan_send(req->ch, NULL, 0); + free_req(req); } static unsigned long calc_timeout_sec(double t) { - if (t > (double) ULONG_MAX) - return ULONG_MAX; - else if (t < 0.0) - return 0; - else - return (unsigned long) t; + if (t > (double) ULONG_MAX) + return ULONG_MAX; + else if (t < 0.0) + return 0; + else + return (unsigned long) t; } static unsigned int calc_timeout_nsec(double t) { - double f = t - (double) calc_timeout_sec(t); - if (f < 0.0) - return 0; - else if (f >= 0.999999999) - return 999999999; - else - return (unsigned int) (f * 1.0e9); + double f = t - (double) calc_timeout_sec(t); + if (f < 0.0) + return 0; + else if (f >= 0.999999999) + return 999999999; + else + return (unsigned int) (f * 1.0e9); } static void fill_entry(struct fuse_entry_out *arg, - const struct fuse_entry_param *e) + const struct fuse_entry_param *e) { - arg->nodeid = e->ino; - arg->generation = e->generation; - arg->entry_valid = calc_timeout_sec(e->entry_timeout); - arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout); - arg->attr_valid = calc_timeout_sec(e->attr_timeout); - arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout); - convert_stat(&e->attr, &arg->attr); + arg->nodeid = e->ino; + arg->generation = e->generation; + arg->entry_valid = calc_timeout_sec(e->entry_timeout); + arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout); + arg->attr_valid = calc_timeout_sec(e->attr_timeout); + arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout); + convert_stat(&e->attr, &arg->attr); } static void fill_open(struct fuse_open_out *arg, - const struct fuse_file_info *f) + const struct fuse_file_info *f) { - arg->fh = f->fh; - if (f->direct_io) - arg->open_flags |= FOPEN_DIRECT_IO; - if (f->keep_cache) - arg->open_flags |= FOPEN_KEEP_CACHE; + arg->fh = f->fh; + if (f->direct_io) + arg->open_flags |= FOPEN_DIRECT_IO; + if (f->keep_cache) + arg->open_flags |= FOPEN_KEEP_CACHE; } int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e) { - struct fuse_entry_out arg; + struct fuse_entry_out arg; - /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant - negative entry */ - if (!e->ino && req->f->conn.proto_minor < 4) - return fuse_reply_err(req, ENOENT); + /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant + negative entry */ + if (!e->ino && req->f->conn.proto_minor < 4) + return fuse_reply_err(req, ENOENT); - memset(&arg, 0, sizeof(arg)); - fill_entry(&arg, e); - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + fill_entry(&arg, e); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, - const struct fuse_file_info *f) + const struct fuse_file_info *f) { - struct { - struct fuse_entry_out e; - struct fuse_open_out o; - } arg; + struct { + struct fuse_entry_out e; + struct fuse_open_out o; + } arg; - memset(&arg, 0, sizeof(arg)); - fill_entry(&arg.e, e); - fill_open(&arg.o, f); - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + fill_entry(&arg.e, e); + fill_open(&arg.o, f); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_attr(fuse_req_t req, const struct stat *attr, - double attr_timeout) + double attr_timeout) { - struct fuse_attr_out arg; + struct fuse_attr_out arg; - memset(&arg, 0, sizeof(arg)); - arg.attr_valid = calc_timeout_sec(attr_timeout); - arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); - convert_stat(attr, &arg.attr); + memset(&arg, 0, sizeof(arg)); + arg.attr_valid = calc_timeout_sec(attr_timeout); + arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); + convert_stat(attr, &arg.attr); - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_readlink(fuse_req_t req, const char *linkname) { - return send_reply_ok(req, linkname, strlen(linkname)); + return send_reply_ok(req, linkname, strlen(linkname)); } int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f) { - struct fuse_open_out arg; + struct fuse_open_out arg; - memset(&arg, 0, sizeof(arg)); - fill_open(&arg, f); - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + fill_open(&arg, f); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_write(fuse_req_t req, size_t count) { - struct fuse_write_out arg; + struct fuse_write_out arg; - memset(&arg, 0, sizeof(arg)); - arg.size = count; + memset(&arg, 0, sizeof(arg)); + arg.size = count; - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size) { - return send_reply_ok(req, buf, size); + return send_reply_ok(req, buf, size); } int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf) { - struct fuse_statfs_out arg; - size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg); + struct fuse_statfs_out arg; + size_t size = req->f->conn.proto_minor < 4 ? + FUSE_COMPAT_STATFS_SIZE : sizeof(arg); - memset(&arg, 0, sizeof(arg)); - convert_statfs(stbuf, &arg.st); + memset(&arg, 0, sizeof(arg)); + convert_statfs(stbuf, &arg.st); - return send_reply_ok(req, &arg, size); + return send_reply_ok(req, &arg, size); } int fuse_reply_xattr(fuse_req_t req, size_t count) { - struct fuse_getxattr_out arg; + struct fuse_getxattr_out arg; - memset(&arg, 0, sizeof(arg)); - arg.size = count; + memset(&arg, 0, sizeof(arg)); + arg.size = count; - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_lock(fuse_req_t req, struct flock *lock) { - struct fuse_lk_out arg; + struct fuse_lk_out arg; - memset(&arg, 0, sizeof(arg)); - arg.lk.type = lock->l_type; - if (lock->l_type != F_UNLCK) { - arg.lk.start = lock->l_start; - if (lock->l_len == 0) - arg.lk.end = OFFSET_MAX; - else - arg.lk.end = lock->l_start + lock->l_len - 1; - } - arg.lk.pid = lock->l_pid; - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + arg.lk.type = lock->l_type; + if (lock->l_type != F_UNLCK) { + arg.lk.start = lock->l_start; + if (lock->l_len == 0) + arg.lk.end = OFFSET_MAX; + else + arg.lk.end = lock->l_start + lock->l_len - 1; + } + arg.lk.pid = lock->l_pid; + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_bmap(fuse_req_t req, uint64_t idx) { - struct fuse_bmap_out arg; + struct fuse_bmap_out arg; - memset(&arg, 0, sizeof(arg)); - arg.block = idx; + memset(&arg, 0, sizeof(arg)); + arg.block = idx; - return send_reply_ok(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.lookup) - req->f->op.lookup(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.lookup) + req->f->op.lookup(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg; + struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg; - if (req->f->op.forget) - req->f->op.forget(req, nodeid, arg->nlookup); - else - fuse_reply_none(req); + if (req->f->op.forget) + req->f->op.forget(req, nodeid, arg->nlookup); + else + fuse_reply_none(req); } static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - (void) inarg; + (void) inarg; - if (req->f->op.getattr) - req->f->op.getattr(req, nodeid, NULL); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.getattr) + req->f->op.getattr(req, nodeid, NULL); + else + fuse_reply_err(req, ENOSYS); } static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg; - - if (req->f->op.setattr) { - struct fuse_file_info *fi = NULL; - struct fuse_file_info fi_store; - struct stat stbuf; - memset(&stbuf, 0, sizeof(stbuf)); - convert_attr(arg, &stbuf); - if (arg->valid & FATTR_FH) { - arg->valid &= ~FATTR_FH; - memset(&fi_store, 0, sizeof(fi_store)); - fi = &fi_store; - fi->fh = arg->fh; - fi->fh_old = fi->fh; - } - req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi); - } else - fuse_reply_err(req, ENOSYS); + struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg; + + if (req->f->op.setattr) { + struct fuse_file_info *fi = NULL; + struct fuse_file_info fi_store; + struct stat stbuf; + memset(&stbuf, 0, sizeof(stbuf)); + convert_attr(arg, &stbuf); + if (arg->valid & FATTR_FH) { + arg->valid &= ~FATTR_FH; + memset(&fi_store, 0, sizeof(fi_store)); + fi = &fi_store; + fi->fh = arg->fh; + fi->fh_old = fi->fh; + } + req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi); + } else + fuse_reply_err(req, ENOSYS); } static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_access_in *arg = (struct fuse_access_in *) inarg; + struct fuse_access_in *arg = (struct fuse_access_in *) inarg; - if (req->f->op.access) - req->f->op.access(req, nodeid, arg->mask); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.access) + req->f->op.access(req, nodeid, arg->mask); + else + fuse_reply_err(req, ENOSYS); } static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - (void) inarg; + (void) inarg; - if (req->f->op.readlink) - req->f->op.readlink(req, nodeid); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.readlink) + req->f->op.readlink(req, nodeid); + else + fuse_reply_err(req, ENOSYS); } static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg; + struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg; - if (req->f->op.mknod) - req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.mknod) + req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev); + else + fuse_reply_err(req, ENOSYS); } static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg; + struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg; - if (req->f->op.mkdir) - req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.mkdir) + req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode); + else + fuse_reply_err(req, ENOSYS); } static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.unlink) - req->f->op.unlink(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.unlink) + req->f->op.unlink(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.rmdir) - req->f->op.rmdir(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.rmdir) + req->f->op.rmdir(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; - char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1; + char *name = (char *) inarg; + char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1; - if (req->f->op.symlink) - req->f->op.symlink(req, linkname, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.symlink) + req->f->op.symlink(req, linkname, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg; - char *oldname = PARAM(arg); - char *newname = oldname + strlen(oldname) + 1; + struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg; + char *oldname = PARAM(arg); + char *newname = oldname + strlen(oldname) + 1; - if (req->f->op.rename) - req->f->op.rename(req, nodeid, oldname, arg->newdir, newname); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.rename) + req->f->op.rename(req, nodeid, oldname, arg->newdir, newname); + else + fuse_reply_err(req, ENOSYS); } static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_link_in *arg = (struct fuse_link_in *) inarg; + struct fuse_link_in *arg = (struct fuse_link_in *) inarg; - if (req->f->op.link) - req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg)); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.link) + req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg)); + else + fuse_reply_err(req, ENOSYS); } static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_open_in *arg = (struct fuse_open_in *) inarg; + struct fuse_open_in *arg = (struct fuse_open_in *) inarg; - if (req->f->op.create) { - struct fuse_file_info fi; + if (req->f->op.create) { + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; - req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi); - } else - fuse_reply_err(req, ENOSYS); + req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi); + } else + fuse_reply_err(req, ENOSYS); } static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_open_in *arg = (struct fuse_open_in *) inarg; - struct fuse_file_info fi; + struct fuse_open_in *arg = (struct fuse_open_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; - if (req->f->op.open) - req->f->op.open(req, nodeid, &fi); - else - fuse_reply_open(req, &fi); + if (req->f->op.open) + req->f->op.open(req, nodeid, &fi); + else + fuse_reply_open(req, &fi); } static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_read_in *arg = (struct fuse_read_in *) inarg; + struct fuse_read_in *arg = (struct fuse_read_in *) inarg; - if (req->f->op.read) { - struct fuse_file_info fi; + if (req->f->op.read) { + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; - req->f->op.read(req, nodeid, arg->size, arg->offset, &fi); - } else - fuse_reply_err(req, ENOSYS); + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + req->f->op.read(req, nodeid, arg->size, arg->offset, &fi); + } else + fuse_reply_err(req, ENOSYS); } static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_write_in *arg = (struct fuse_write_in *) inarg; - struct fuse_file_info fi; + struct fuse_write_in *arg = (struct fuse_write_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; - fi.writepage = arg->write_flags & 1; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + fi.writepage = arg->write_flags & 1; - if (req->f->op.write) - req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.write) + req->f->op.write(req, nodeid, PARAM(arg), arg->size, + arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg; - struct fuse_file_info fi; + struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; - fi.flush = 1; - if (req->f->conn.proto_minor >= 7) - fi.lock_owner = arg->lock_owner; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + fi.flush = 1; + if (req->f->conn.proto_minor >= 7) + fi.lock_owner = arg->lock_owner; - if (req->f->op.flush) - req->f->op.flush(req, nodeid, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.flush) + req->f->op.flush(req, nodeid, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_release_in *arg = (struct fuse_release_in *) inarg; - struct fuse_file_info fi; + struct fuse_release_in *arg = (struct fuse_release_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - fi.fh = arg->fh; - fi.fh_old = fi.fh; - if (req->f->conn.proto_minor >= 8) { - fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; - fi.lock_owner = arg->lock_owner; - } + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + fi.fh = arg->fh; + fi.fh_old = fi.fh; + if (req->f->conn.proto_minor >= 8) { + fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; + fi.lock_owner = arg->lock_owner; + } - if (req->f->op.release) - req->f->op.release(req, nodeid, &fi); - else - fuse_reply_err(req, 0); + if (req->f->op.release) + req->f->op.release(req, nodeid, &fi); + else + fuse_reply_err(req, 0); } static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; - struct fuse_file_info fi; + struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; - if (req->f->op.fsync) - req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.fsync) + req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_open_in *arg = (struct fuse_open_in *) inarg; - struct fuse_file_info fi; + struct fuse_open_in *arg = (struct fuse_open_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; - if (req->f->op.opendir) - req->f->op.opendir(req, nodeid, &fi); - else - fuse_reply_open(req, &fi); + if (req->f->op.opendir) + req->f->op.opendir(req, nodeid, &fi); + else + fuse_reply_open(req, &fi); } static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_read_in *arg = (struct fuse_read_in *) inarg; - struct fuse_file_info fi; + struct fuse_read_in *arg = (struct fuse_read_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; - if (req->f->op.readdir) - req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.readdir) + req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_release_in *arg = (struct fuse_release_in *) inarg; - struct fuse_file_info fi; + struct fuse_release_in *arg = (struct fuse_release_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - fi.fh = arg->fh; - fi.fh_old = fi.fh; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + fi.fh = arg->fh; + fi.fh_old = fi.fh; - if (req->f->op.releasedir) - req->f->op.releasedir(req, nodeid, &fi); - else - fuse_reply_err(req, 0); + if (req->f->op.releasedir) + req->f->op.releasedir(req, nodeid, &fi); + else + fuse_reply_err(req, 0); } static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; - struct fuse_file_info fi; + struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg; + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.fh_old = fi.fh; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; - if (req->f->op.fsyncdir) - req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.fsyncdir) + req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi); + else + fuse_reply_err(req, ENOSYS); } static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - (void) nodeid; - (void) inarg; + (void) nodeid; + (void) inarg; - if (req->f->op.statfs) - req->f->op.statfs(req, nodeid); - else { - struct statvfs buf = { - .f_namemax = 255, - .f_bsize = 512, - }; - fuse_reply_statfs(req, &buf); - } + if (req->f->op.statfs) + req->f->op.statfs(req, nodeid); + else { + struct statvfs buf = { + .f_namemax = 255, + .f_bsize = 512, + }; + fuse_reply_statfs(req, &buf); + } } static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg; - char *name = PARAM(arg); - char *value = name + strlen(name) + 1; + struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg; + char *name = PARAM(arg); + char *value = name + strlen(name) + 1; - if (req->f->op.setxattr) - req->f->op.setxattr(req, nodeid, name, value, arg->size, arg->flags); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.setxattr) + req->f->op.setxattr(req, nodeid, name, value, arg->size, + arg->flags); + else + fuse_reply_err(req, ENOSYS); } static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; + struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; - if (req->f->op.getxattr) - req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.getxattr) + req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size); + else + fuse_reply_err(req, ENOSYS); } static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; + struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg; - if (req->f->op.listxattr) - req->f->op.listxattr(req, nodeid, arg->size); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.listxattr) + req->f->op.listxattr(req, nodeid, arg->size); + else + fuse_reply_err(req, ENOSYS); } static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - char *name = (char *) inarg; + char *name = (char *) inarg; - if (req->f->op.removexattr) - req->f->op.removexattr(req, nodeid, name); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.removexattr) + req->f->op.removexattr(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } static void convert_fuse_file_lock(struct fuse_file_lock *fl, - struct flock *flock) + struct flock *flock) { - memset(flock, 0, sizeof(struct flock)); - flock->l_type = fl->type; - flock->l_whence = SEEK_SET; - flock->l_start = fl->start; - if (fl->end == OFFSET_MAX) - flock->l_len = 0; - else - flock->l_len = fl->end - fl->start + 1; - flock->l_pid = fl->pid; + memset(flock, 0, sizeof(struct flock)); + flock->l_type = fl->type; + flock->l_whence = SEEK_SET; + flock->l_start = fl->start; + if (fl->end == OFFSET_MAX) + flock->l_len = 0; + else + flock->l_len = fl->end - fl->start + 1; + flock->l_pid = fl->pid; } static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; - struct fuse_file_info fi; - struct flock flock; + struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; + struct fuse_file_info fi; + struct flock flock; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.lock_owner = arg->owner; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.lock_owner = arg->owner; - convert_fuse_file_lock(&arg->lk, &flock); - if (req->f->op.getlk) - req->f->op.getlk(req, nodeid, &fi, &flock); - else - fuse_reply_err(req, ENOSYS); + convert_fuse_file_lock(&arg->lk, &flock); + if (req->f->op.getlk) + req->f->op.getlk(req, nodeid, &fi, &flock); + else + fuse_reply_err(req, ENOSYS); } static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid, - const void *inarg, int sleep) + const void *inarg, int sleep) { - struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; - struct fuse_file_info fi; - struct flock flock; + struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg; + struct fuse_file_info fi; + struct flock flock; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - fi.lock_owner = arg->owner; + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.lock_owner = arg->owner; - convert_fuse_file_lock(&arg->lk, &flock); - if (req->f->op.setlk) - req->f->op.setlk(req, nodeid, &fi, &flock, sleep); - else - fuse_reply_err(req, ENOSYS); + convert_fuse_file_lock(&arg->lk, &flock); + if (req->f->op.setlk) + req->f->op.setlk(req, nodeid, &fi, &flock, sleep); + else + fuse_reply_err(req, ENOSYS); } static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - do_setlk_common(req, nodeid, inarg, 0); + do_setlk_common(req, nodeid, inarg, 0); } static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - do_setlk_common(req, nodeid, inarg, 1); + do_setlk_common(req, nodeid, inarg, 1); } static int find_interrupted(struct fuse_ll *f, struct fuse_req *req) { - struct fuse_req *curr; - - for (curr = f->list.next; curr != &f->list; curr = curr->next) { - if (curr->unique == req->u.i.unique) { - curr->ctr++; - pthread_mutex_unlock(&f->lock); - - /* Ugh, ugly locking */ - pthread_mutex_lock(&curr->lock); - pthread_mutex_lock(&f->lock); - curr->interrupted = 1; - pthread_mutex_unlock(&f->lock); - if (curr->u.ni.func) - curr->u.ni.func(curr, curr->u.ni.data); - pthread_mutex_unlock(&curr->lock); - - pthread_mutex_lock(&f->lock); - curr->ctr--; - if (!curr->ctr) - destroy_req(curr); - - return 1; - } - } - for (curr = f->interrupts.next; curr != &f->interrupts; - curr = curr->next) { - if (curr->u.i.unique == req->u.i.unique) - return 1; - } - return 0; + struct fuse_req *curr; + + for (curr = f->list.next; curr != &f->list; curr = curr->next) { + if (curr->unique == req->u.i.unique) { + curr->ctr++; + pthread_mutex_unlock(&f->lock); + + /* Ugh, ugly locking */ + pthread_mutex_lock(&curr->lock); + pthread_mutex_lock(&f->lock); + curr->interrupted = 1; + pthread_mutex_unlock(&f->lock); + if (curr->u.ni.func) + curr->u.ni.func(curr, curr->u.ni.data); + pthread_mutex_unlock(&curr->lock); + + pthread_mutex_lock(&f->lock); + curr->ctr--; + if (!curr->ctr) + destroy_req(curr); + + return 1; + } + } + for (curr = f->interrupts.next; curr != &f->interrupts; + curr = curr->next) { + if (curr->u.i.unique == req->u.i.unique) + return 1; + } + return 0; } static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg; - struct fuse_ll *f = req->f; + struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg; + struct fuse_ll *f = req->f; - (void) nodeid; - if (f->debug) - fprintf(stderr, "INTERRUPT: %llu\n", (unsigned long long) arg->unique); + (void) nodeid; + if (f->debug) + fprintf(stderr, "INTERRUPT: %llu\n", + (unsigned long long) arg->unique); - req->u.i.unique = arg->unique; + req->u.i.unique = arg->unique; - pthread_mutex_lock(&f->lock); - if (find_interrupted(f, req)) - destroy_req(req); - else - list_add_req(req, &f->interrupts); - pthread_mutex_unlock(&f->lock); + pthread_mutex_lock(&f->lock); + if (find_interrupted(f, req)) + destroy_req(req); + else + list_add_req(req, &f->interrupts); + pthread_mutex_unlock(&f->lock); } static struct fuse_req *check_interrupt(struct fuse_ll *f, struct fuse_req *req) { - struct fuse_req *curr; - - for (curr = f->interrupts.next; curr != &f->interrupts; curr = curr->next) { - if (curr->u.i.unique == req->unique) { - req->interrupted = 1; - list_del_req(curr); - free(curr); - return NULL; - } - } - curr = f->interrupts.next; - if (curr != &f->interrupts) { - list_del_req(curr); - list_init_req(curr); - return curr; - } else - return NULL; + struct fuse_req *curr; + + for (curr = f->interrupts.next; curr != &f->interrupts; + curr = curr->next) { + if (curr->u.i.unique == req->unique) { + req->interrupted = 1; + list_del_req(curr); + free(curr); + return NULL; + } + } + curr = f->interrupts.next; + if (curr != &f->interrupts) { + list_del_req(curr); + list_init_req(curr); + return curr; + } else + return NULL; } static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg; + struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg; - if (req->f->op.bmap) - req->f->op.bmap(req, nodeid, arg->blocksize, arg->block); - else - fuse_reply_err(req, ENOSYS); + if (req->f->op.bmap) + req->f->op.bmap(req, nodeid, arg->blocksize, arg->block); + else + fuse_reply_err(req, ENOSYS); } static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_init_in *arg = (struct fuse_init_in *) inarg; - struct fuse_init_out outarg; - struct fuse_ll *f = req->f; - size_t bufsize = fuse_chan_bufsize(req->ch); - - (void) nodeid; - if (f->debug) { - fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor); - if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { - fprintf(stderr, "flags=0x%08x\n", arg->flags); - fprintf(stderr, "max_readahead=0x%08x\n", arg->max_readahead); - } - } - f->conn.proto_major = arg->major; - f->conn.proto_minor = arg->minor; - - if (arg->major < 7) { - fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n", - arg->major, arg->minor); - fuse_reply_err(req, EPROTO); - return; - } - - if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { - if (f->conn.async_read) - f->conn.async_read = arg->flags & FUSE_ASYNC_READ; - if (arg->max_readahead < f->conn.max_readahead) - f->conn.max_readahead = arg->max_readahead; - } else { - f->conn.async_read = 0; - f->conn.max_readahead = 0; - } - - if (bufsize < FUSE_MIN_READ_BUFFER) { - fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", - bufsize); - bufsize = FUSE_MIN_READ_BUFFER; - } - - bufsize -= 4096; - if (bufsize < f->conn.max_write) - f->conn.max_write = bufsize; - - f->got_init = 1; - if (f->op.init) - f->op.init(f->userdata, &f->conn); - - memset(&outarg, 0, sizeof(outarg)); - outarg.major = FUSE_KERNEL_VERSION; - outarg.minor = FUSE_KERNEL_MINOR_VERSION; - if (f->conn.async_read) - outarg.flags |= FUSE_ASYNC_READ; - if (f->op.getlk && f->op.setlk) - outarg.flags |= FUSE_POSIX_LOCKS; - outarg.max_readahead = f->conn.max_readahead; - outarg.max_write = f->conn.max_write; - - if (f->debug) { - fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor); - fprintf(stderr, " flags=0x%08x\n", outarg.flags); - fprintf(stderr, " max_readahead=0x%08x\n", outarg.max_readahead); - fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); - } - - send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg)); + struct fuse_init_in *arg = (struct fuse_init_in *) inarg; + struct fuse_init_out outarg; + struct fuse_ll *f = req->f; + size_t bufsize = fuse_chan_bufsize(req->ch); + + (void) nodeid; + if (f->debug) { + fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor); + if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { + fprintf(stderr, "flags=0x%08x\n", arg->flags); + fprintf(stderr, "max_readahead=0x%08x\n", + arg->max_readahead); + } + } + f->conn.proto_major = arg->major; + f->conn.proto_minor = arg->minor; + + if (arg->major < 7) { + fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n", + arg->major, arg->minor); + fuse_reply_err(req, EPROTO); + return; + } + + if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { + if (f->conn.async_read) + f->conn.async_read = arg->flags & FUSE_ASYNC_READ; + if (arg->max_readahead < f->conn.max_readahead) + f->conn.max_readahead = arg->max_readahead; + } else { + f->conn.async_read = 0; + f->conn.max_readahead = 0; + } + + if (bufsize < FUSE_MIN_READ_BUFFER) { + fprintf(stderr, "fuse: warning: buffer size too small: %zu\n", + bufsize); + bufsize = FUSE_MIN_READ_BUFFER; + } + + bufsize -= 4096; + if (bufsize < f->conn.max_write) + f->conn.max_write = bufsize; + + f->got_init = 1; + if (f->op.init) + f->op.init(f->userdata, &f->conn); + + memset(&outarg, 0, sizeof(outarg)); + outarg.major = FUSE_KERNEL_VERSION; + outarg.minor = FUSE_KERNEL_MINOR_VERSION; + if (f->conn.async_read) + outarg.flags |= FUSE_ASYNC_READ; + if (f->op.getlk && f->op.setlk) + outarg.flags |= FUSE_POSIX_LOCKS; + outarg.max_readahead = f->conn.max_readahead; + outarg.max_write = f->conn.max_write; + + if (f->debug) { + fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor); + fprintf(stderr, " flags=0x%08x\n", outarg.flags); + fprintf(stderr, " max_readahead=0x%08x\n", + outarg.max_readahead); + fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); + } + + send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg)); } static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { - struct fuse_ll *f = req->f; + struct fuse_ll *f = req->f; - (void) nodeid; - (void) inarg; + (void) nodeid; + (void) inarg; - f->got_destroy = 1; - if (f->op.destroy) - f->op.destroy(f->userdata); + f->got_destroy = 1; + if (f->op.destroy) + f->op.destroy(f->userdata); - send_reply_ok(req, NULL, 0); + send_reply_ok(req, NULL, 0); } void *fuse_req_userdata(fuse_req_t req) { - return req->f->userdata; + return req->f->userdata; } const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) { - return &req->ctx; + return &req->ctx; } void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, - void *data) + void *data) { - pthread_mutex_lock(&req->lock); - req->u.ni.func = func; - req->u.ni.data = data; - if (req->interrupted && func) - func(req, data); - pthread_mutex_unlock(&req->lock); + pthread_mutex_lock(&req->lock); + req->u.ni.func = func; + req->u.ni.data = data; + if (req->interrupted && func) + func(req, data); + pthread_mutex_unlock(&req->lock); } int fuse_req_interrupted(fuse_req_t req) { - int interrupted; + int interrupted; - pthread_mutex_lock(&req->f->lock); - interrupted = req->interrupted; - pthread_mutex_unlock(&req->f->lock); + pthread_mutex_lock(&req->f->lock); + interrupted = req->interrupted; + pthread_mutex_unlock(&req->f->lock); - return interrupted; + return interrupted; } static struct { - void (*func)(fuse_req_t, fuse_ino_t, const void *); - const char *name; + void (*func)(fuse_req_t, fuse_ino_t, const void *); + const char *name; } fuse_ll_ops[] = { - [FUSE_LOOKUP] = { do_lookup, "LOOKUP" }, - [FUSE_FORGET] = { do_forget, "FORGET" }, - [FUSE_GETATTR] = { do_getattr, "GETATTR" }, - [FUSE_SETATTR] = { do_setattr, "SETATTR" }, - [FUSE_READLINK] = { do_readlink, "READLINK" }, - [FUSE_SYMLINK] = { do_symlink, "SYMLINK" }, - [FUSE_MKNOD] = { do_mknod, "MKNOD" }, - [FUSE_MKDIR] = { do_mkdir, "MKDIR" }, - [FUSE_UNLINK] = { do_unlink, "UNLINK" }, - [FUSE_RMDIR] = { do_rmdir, "RMDIR" }, - [FUSE_RENAME] = { do_rename, "RENAME" }, - [FUSE_LINK] = { do_link, "LINK" }, - [FUSE_OPEN] = { do_open, "OPEN" }, - [FUSE_READ] = { do_read, "READ" }, - [FUSE_WRITE] = { do_write, "WRITE" }, - [FUSE_STATFS] = { do_statfs, "STATFS" }, - [FUSE_RELEASE] = { do_release, "RELEASE" }, - [FUSE_FSYNC] = { do_fsync, "FSYNC" }, - [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" }, - [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" }, - [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" }, - [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" }, - [FUSE_FLUSH] = { do_flush, "FLUSH" }, - [FUSE_INIT] = { do_init, "INIT" }, - [FUSE_OPENDIR] = { do_opendir, "OPENDIR" }, - [FUSE_READDIR] = { do_readdir, "READDIR" }, - [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" }, - [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" }, - [FUSE_GETLK] = { do_getlk, "GETLK" }, - [FUSE_SETLK] = { do_setlk, "SETLK" }, - [FUSE_SETLKW] = { do_setlkw, "SETLKW" }, - [FUSE_ACCESS] = { do_access, "ACCESS" }, - [FUSE_CREATE] = { do_create, "CREATE" }, - [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" }, - [FUSE_BMAP] = { do_bmap, "BMAP" }, - [FUSE_DESTROY] = { do_destroy, "DESTROY" }, + [FUSE_LOOKUP] = { do_lookup, "LOOKUP" }, + [FUSE_FORGET] = { do_forget, "FORGET" }, + [FUSE_GETATTR] = { do_getattr, "GETATTR" }, + [FUSE_SETATTR] = { do_setattr, "SETATTR" }, + [FUSE_READLINK] = { do_readlink, "READLINK" }, + [FUSE_SYMLINK] = { do_symlink, "SYMLINK" }, + [FUSE_MKNOD] = { do_mknod, "MKNOD" }, + [FUSE_MKDIR] = { do_mkdir, "MKDIR" }, + [FUSE_UNLINK] = { do_unlink, "UNLINK" }, + [FUSE_RMDIR] = { do_rmdir, "RMDIR" }, + [FUSE_RENAME] = { do_rename, "RENAME" }, + [FUSE_LINK] = { do_link, "LINK" }, + [FUSE_OPEN] = { do_open, "OPEN" }, + [FUSE_READ] = { do_read, "READ" }, + [FUSE_WRITE] = { do_write, "WRITE" }, + [FUSE_STATFS] = { do_statfs, "STATFS" }, + [FUSE_RELEASE] = { do_release, "RELEASE" }, + [FUSE_FSYNC] = { do_fsync, "FSYNC" }, + [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" }, + [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" }, + [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" }, + [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" }, + [FUSE_FLUSH] = { do_flush, "FLUSH" }, + [FUSE_INIT] = { do_init, "INIT" }, + [FUSE_OPENDIR] = { do_opendir, "OPENDIR" }, + [FUSE_READDIR] = { do_readdir, "READDIR" }, + [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" }, + [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" }, + [FUSE_GETLK] = { do_getlk, "GETLK" }, + [FUSE_SETLK] = { do_setlk, "SETLK" }, + [FUSE_SETLKW] = { do_setlkw, "SETLKW" }, + [FUSE_ACCESS] = { do_access, "ACCESS" }, + [FUSE_CREATE] = { do_create, "CREATE" }, + [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" }, + [FUSE_BMAP] = { do_bmap, "BMAP" }, + [FUSE_DESTROY] = { do_destroy, "DESTROY" }, }; #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) static const char *opname(enum fuse_opcode opcode) { - if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) - return "???"; - else - return fuse_ll_ops[opcode].name; + if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) + return "???"; + else + return fuse_ll_ops[opcode].name; } static void fuse_ll_process(void *data, const char *buf, size_t len, - struct fuse_chan *ch) -{ - struct fuse_ll *f = (struct fuse_ll *) data; - struct fuse_in_header *in = (struct fuse_in_header *) buf; - const void *inarg = buf + sizeof(struct fuse_in_header); - struct fuse_req *req; - - if (f->debug) - fprintf(stderr, "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n", - (unsigned long long) in->unique, - opname((enum fuse_opcode) in->opcode), in->opcode, - (unsigned long) in->nodeid, len); - - req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req)); - if (req == NULL) { - fprintf(stderr, "fuse: failed to allocate request\n"); - return; - } - - req->f = f; - req->unique = in->unique; - req->ctx.uid = in->uid; - req->ctx.gid = in->gid; - req->ctx.pid = in->pid; - req->ch = ch; - req->ctr = 1; - list_init_req(req); - fuse_mutex_init(&req->lock); - - if (!f->got_init && in->opcode != FUSE_INIT) - fuse_reply_err(req, EIO); - else if (f->allow_root && in->uid != f->owner && in->uid != 0 && - in->opcode != FUSE_INIT && in->opcode != FUSE_READ && - in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC && - in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR && - in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) { - fuse_reply_err(req, EACCES); - } else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) - fuse_reply_err(req, ENOSYS); - else { - if (in->opcode != FUSE_INTERRUPT) { - struct fuse_req *intr; - pthread_mutex_lock(&f->lock); - intr = check_interrupt(f, req); - list_add_req(req, &f->list); - pthread_mutex_unlock(&f->lock); - if (intr) - fuse_reply_err(intr, EAGAIN); - } - fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); - } + struct fuse_chan *ch) +{ + struct fuse_ll *f = (struct fuse_ll *) data; + struct fuse_in_header *in = (struct fuse_in_header *) buf; + const void *inarg = buf + sizeof(struct fuse_in_header); + struct fuse_req *req; + + if (f->debug) + fprintf(stderr, + "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n", + (unsigned long long) in->unique, + opname((enum fuse_opcode) in->opcode), in->opcode, + (unsigned long) in->nodeid, len); + + req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req)); + if (req == NULL) { + fprintf(stderr, "fuse: failed to allocate request\n"); + return; + } + + req->f = f; + req->unique = in->unique; + req->ctx.uid = in->uid; + req->ctx.gid = in->gid; + req->ctx.pid = in->pid; + req->ch = ch; + req->ctr = 1; + list_init_req(req); + fuse_mutex_init(&req->lock); + + if (!f->got_init && in->opcode != FUSE_INIT) + fuse_reply_err(req, EIO); + else if (f->allow_root && in->uid != f->owner && in->uid != 0 && + in->opcode != FUSE_INIT && in->opcode != FUSE_READ && + in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC && + in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR && + in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) { + fuse_reply_err(req, EACCES); + } else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) + fuse_reply_err(req, ENOSYS); + else { + if (in->opcode != FUSE_INTERRUPT) { + struct fuse_req *intr; + pthread_mutex_lock(&f->lock); + intr = check_interrupt(f, req); + list_add_req(req, &f->list); + pthread_mutex_unlock(&f->lock); + if (intr) + fuse_reply_err(intr, EAGAIN); + } + fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); + } } enum { - KEY_HELP, - KEY_VERSION, + KEY_HELP, + KEY_VERSION, }; static struct fuse_opt fuse_ll_opts[] = { - { "debug", offsetof(struct fuse_ll, debug), 1 }, - { "-d", offsetof(struct fuse_ll, debug), 1 }, - { "allow_root", offsetof(struct fuse_ll, allow_root), 1 }, - { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 }, - { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 }, - { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 }, - { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 }, - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_END + { "debug", offsetof(struct fuse_ll, debug), 1 }, + { "-d", offsetof(struct fuse_ll, debug), 1 }, + { "allow_root", offsetof(struct fuse_ll, allow_root), 1 }, + { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 }, + { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 }, + { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 }, + { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 }, + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_END }; static void fuse_ll_version(void) { - fprintf(stderr, "using FUSE kernel interface version %i.%i\n", - FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); + fprintf(stderr, "using FUSE kernel interface version %i.%i\n", + FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); } static void fuse_ll_help(void) { - fprintf(stderr, -" -o max_write=N set maximum size of write requests\n" -" -o max_readahead=N set maximum readahead\n" -" -o async_read perform reads asynchronously (default)\n" -" -o sync_read perform reads synchronously\n"); + fprintf(stderr, +" -o max_write=N set maximum size of write requests\n" +" -o max_readahead=N set maximum readahead\n" +" -o async_read perform reads asynchronously (default)\n" +" -o sync_read perform reads synchronously\n"); } static int fuse_ll_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - (void) data; (void) outargs; + (void) data; (void) outargs; - switch (key) { - case KEY_HELP: - fuse_ll_help(); - break; + switch (key) { + case KEY_HELP: + fuse_ll_help(); + break; - case KEY_VERSION: - fuse_ll_version(); - break; + case KEY_VERSION: + fuse_ll_version(); + break; - default: - fprintf(stderr, "fuse: unknown option `%s'\n", arg); - } + default: + fprintf(stderr, "fuse: unknown option `%s'\n", arg); + } - return -1; + return -1; } int fuse_lowlevel_is_lib_option(const char *opt) { - return fuse_opt_match(fuse_ll_opts, opt); + return fuse_opt_match(fuse_ll_opts, opt); } static void fuse_ll_destroy(void *data) { - struct fuse_ll *f = (struct fuse_ll *) data; + struct fuse_ll *f = (struct fuse_ll *) data; - if (f->got_init && !f->got_destroy) { - if (f->op.destroy) - f->op.destroy(f->userdata); - } + if (f->got_init && !f->got_destroy) { + if (f->op.destroy) + f->op.destroy(f->userdata); + } - pthread_mutex_destroy(&f->lock); - free(f); + pthread_mutex_destroy(&f->lock); + free(f); } /* @@ -1255,158 +1264,158 @@ static void fuse_ll_destroy(void *data) * version of a symbol to internal references. */ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata) { - struct fuse_ll *f; - struct fuse_session *se; - struct fuse_session_ops sop = { - .process = fuse_ll_process, - .destroy = fuse_ll_destroy, - }; + struct fuse_ll *f; + struct fuse_session *se; + struct fuse_session_ops sop = { + .process = fuse_ll_process, + .destroy = fuse_ll_destroy, + }; - if (sizeof(struct fuse_lowlevel_ops) < op_size) { - fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); - op_size = sizeof(struct fuse_lowlevel_ops); - } + if (sizeof(struct fuse_lowlevel_ops) < op_size) { + fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); + op_size = sizeof(struct fuse_lowlevel_ops); + } - f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); - if (f == NULL) { - fprintf(stderr, "fuse: failed to allocate fuse object\n"); - goto out; - } + f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); + if (f == NULL) { + fprintf(stderr, "fuse: failed to allocate fuse object\n"); + goto out; + } - f->conn.async_read = 1; - f->conn.max_write = UINT_MAX; - f->conn.max_readahead = UINT_MAX; - list_init_req(&f->list); - list_init_req(&f->interrupts); - fuse_mutex_init(&f->lock); + f->conn.async_read = 1; + f->conn.max_write = UINT_MAX; + f->conn.max_readahead = UINT_MAX; + list_init_req(&f->list); + list_init_req(&f->interrupts); + fuse_mutex_init(&f->lock); - if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) - goto out_free; + if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) + goto out_free; - memcpy(&f->op, op, op_size); - f->owner = getuid(); - f->userdata = userdata; + memcpy(&f->op, op, op_size); + f->owner = getuid(); + f->userdata = userdata; - se = fuse_session_new(&sop, f); - if (!se) - goto out_free; + se = fuse_session_new(&sop, f); + if (!se) + goto out_free; - return se; + return se; - out_free: - free(f); - out: - return NULL; +out_free: + free(f); +out: + return NULL; } struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, - const struct fuse_lowlevel_ops *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata) { - return fuse_lowlevel_new_common(args, op, op_size, userdata); + return fuse_lowlevel_new_common(args, op, op_size, userdata); } #ifndef __FreeBSD__ static void fill_open_compat(struct fuse_open_out *arg, - const struct fuse_file_info_compat *f) + const struct fuse_file_info_compat *f) { - arg->fh = f->fh; - if (f->direct_io) - arg->open_flags |= FOPEN_DIRECT_IO; - if (f->keep_cache) - arg->open_flags |= FOPEN_KEEP_CACHE; + arg->fh = f->fh; + if (f->direct_io) + arg->open_flags |= FOPEN_DIRECT_IO; + if (f->keep_cache) + arg->open_flags |= FOPEN_KEEP_CACHE; } static void convert_statfs_compat(const struct statfs *compatbuf, - struct statvfs *buf) + struct statvfs *buf) { - buf->f_bsize = compatbuf->f_bsize; - buf->f_blocks = compatbuf->f_blocks; - buf->f_bfree = compatbuf->f_bfree; - buf->f_bavail = compatbuf->f_bavail; - buf->f_files = compatbuf->f_files; - buf->f_ffree = compatbuf->f_ffree; - buf->f_namemax = compatbuf->f_namelen; + buf->f_bsize = compatbuf->f_bsize; + buf->f_blocks = compatbuf->f_blocks; + buf->f_bfree = compatbuf->f_bfree; + buf->f_bavail = compatbuf->f_bavail; + buf->f_files = compatbuf->f_files; + buf->f_ffree = compatbuf->f_ffree; + buf->f_namemax = compatbuf->f_namelen; } int fuse_reply_open_compat(fuse_req_t req, - const struct fuse_file_info_compat *f) + const struct fuse_file_info_compat *f) { - struct fuse_open_out arg; + struct fuse_open_out arg; - memset(&arg, 0, sizeof(arg)); - fill_open_compat(&arg, f); - return send_reply_ok(req, &arg, sizeof(arg)); + memset(&arg, 0, sizeof(arg)); + fill_open_compat(&arg, f); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf) { - struct statvfs newbuf; + struct statvfs newbuf; - memset(&newbuf, 0, sizeof(newbuf)); - convert_statfs_compat(stbuf, &newbuf); + memset(&newbuf, 0, sizeof(newbuf)); + convert_statfs_compat(stbuf, &newbuf); - return fuse_reply_statfs(req, &newbuf); + return fuse_reply_statfs(req, &newbuf); } struct fuse_session *fuse_lowlevel_new_compat(const char *opts, - const struct fuse_lowlevel_ops_compat *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops_compat *op, + size_t op_size, void *userdata) { - struct fuse_session *se; - struct fuse_args args = FUSE_ARGS_INIT(0, NULL); + struct fuse_session *se; + struct fuse_args args = FUSE_ARGS_INIT(0, NULL); - if (opts && - (fuse_opt_add_arg(&args, "") == -1 || - fuse_opt_add_arg(&args, "-o") == -1 || - fuse_opt_add_arg(&args, opts) == -1)) { - fuse_opt_free_args(&args); - return NULL; - } - se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op, - op_size, userdata); - fuse_opt_free_args(&args); + if (opts && + (fuse_opt_add_arg(&args, "") == -1 || + fuse_opt_add_arg(&args, "-o") == -1 || + fuse_opt_add_arg(&args, opts) == -1)) { + fuse_opt_free_args(&args); + return NULL; + } + se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op, + op_size, userdata); + fuse_opt_free_args(&args); - return se; + return se; } struct fuse_ll_compat_conf { - unsigned max_read; - int set_max_read; + unsigned max_read; + int set_max_read; }; static const struct fuse_opt fuse_ll_opts_compat[] = { - { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 }, - { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 }, - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_END + { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 }, + { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 }, + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_END }; int fuse_sync_compat_args(struct fuse_args *args) { - struct fuse_ll_compat_conf conf; + struct fuse_ll_compat_conf conf; - memset(&conf, 0, sizeof(conf)); - if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1) - return -1; + memset(&conf, 0, sizeof(conf)); + if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1) + return -1; - if (fuse_opt_insert_arg(args, 1, "-osync_read")) - return -1; + if (fuse_opt_insert_arg(args, 1, "-osync_read")) + return -1; - if (conf.set_max_read) { - char tmpbuf[64]; + if (conf.set_max_read) { + char tmpbuf[64]; - sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read); - if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1) - return -1; - } - return 0; + sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read); + if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1) + return -1; + } + return 0; } FUSE_SYMVER(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4"); @@ -1417,22 +1426,22 @@ FUSE_SYMVER(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4"); int fuse_sync_compat_args(struct fuse_args *args) { - (void) args; - return 0; + (void) args; + return 0; } #endif /* __FreeBSD__ */ struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, - const struct fuse_lowlevel_ops_compat25 *op, - size_t op_size, void *userdata) + const struct fuse_lowlevel_ops_compat25 *op, + size_t op_size, void *userdata) { - if (fuse_sync_compat_args(args) == -1) - return NULL; + if (fuse_sync_compat_args(args) == -1) + return NULL; - return fuse_lowlevel_new_common(args, - (const struct fuse_lowlevel_ops *) op, - op_size, userdata); + return fuse_lowlevel_new_common(args, + (const struct fuse_lowlevel_ops *) op, + op_size, userdata); } FUSE_SYMVER(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5"); diff --git a/lib/fuse_misc.h b/lib/fuse_misc.h index 4f5236a..c2cfee1 100644 --- a/lib/fuse_misc.h +++ b/lib/fuse_misc.h @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "config.h" @@ -22,11 +22,11 @@ /* Is this hack still needed? */ static inline void fuse_mutex_init(pthread_mutex_t *mut) { - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); - pthread_mutex_init(mut, &attr); - pthread_mutexattr_destroy(&attr); + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); + pthread_mutex_init(mut, &attr); + pthread_mutexattr_destroy(&attr); } #endif diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c index cbdc1a3..95c3a5c 100644 --- a/lib/fuse_mt.c +++ b/lib/fuse_mt.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "fuse_i.h" @@ -17,100 +17,100 @@ #include <assert.h> struct procdata { - struct fuse *f; - struct fuse_chan *prevch; - struct fuse_session *prevse; - fuse_processor_t proc; - void *data; + struct fuse *f; + struct fuse_chan *prevch; + struct fuse_session *prevse; + fuse_processor_t proc; + void *data; }; static void mt_session_proc(void *data, const char *buf, size_t len, - struct fuse_chan *ch) + struct fuse_chan *ch) { - struct procdata *pd = (struct procdata *) data; - struct fuse_cmd *cmd = *(struct fuse_cmd **) buf; + struct procdata *pd = (struct procdata *) data; + struct fuse_cmd *cmd = *(struct fuse_cmd **) buf; - (void) len; - (void) ch; - pd->proc(pd->f, cmd, pd->data); + (void) len; + (void) ch; + pd->proc(pd->f, cmd, pd->data); } static void mt_session_exit(void *data, int val) { - struct procdata *pd = (struct procdata *) data; - if (val) - fuse_session_exit(pd->prevse); - else - fuse_session_reset(pd->prevse); + struct procdata *pd = (struct procdata *) data; + if (val) + fuse_session_exit(pd->prevse); + else + fuse_session_reset(pd->prevse); } static int mt_session_exited(void *data) { - struct procdata *pd = (struct procdata *) data; - return fuse_session_exited(pd->prevse); + struct procdata *pd = (struct procdata *) data; + return fuse_session_exited(pd->prevse); } static int mt_chan_receive(struct fuse_chan **chp, char *buf, size_t size) { - struct fuse_cmd *cmd; - struct procdata *pd = (struct procdata *) fuse_chan_data(*chp); + struct fuse_cmd *cmd; + struct procdata *pd = (struct procdata *) fuse_chan_data(*chp); - assert(size >= sizeof(cmd)); + assert(size >= sizeof(cmd)); - cmd = fuse_read_cmd(pd->f); - if (cmd == NULL) - return 0; + cmd = fuse_read_cmd(pd->f); + if (cmd == NULL) + return 0; - *(struct fuse_cmd **) buf = cmd; + *(struct fuse_cmd **) buf = cmd; - return sizeof(cmd); + return sizeof(cmd); } int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data) { - int res; - struct procdata pd; - struct fuse_session *prevse = fuse_get_session(f); - struct fuse_session *se; - struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL); - struct fuse_chan *ch; - struct fuse_session_ops sop = { - .exit = mt_session_exit, - .exited = mt_session_exited, - .process = mt_session_proc, - }; - struct fuse_chan_ops cop = { - .receive = mt_chan_receive, - }; - - pd.f = f; - pd.prevch = prevch; - pd.prevse = prevse; - pd.proc = proc; - pd.data = data; - - se = fuse_session_new(&sop, &pd); - if (se == NULL) - return -1; - - ch = fuse_chan_new(&cop, fuse_chan_fd(prevch), sizeof(struct fuse_cmd *), - &pd); - if (ch == NULL) { - fuse_session_destroy(se); - return -1; - } - fuse_session_add_chan(se, ch); - res = fuse_session_loop_mt(se); - fuse_session_destroy(se); - return res; + int res; + struct procdata pd; + struct fuse_session *prevse = fuse_get_session(f); + struct fuse_session *se; + struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL); + struct fuse_chan *ch; + struct fuse_session_ops sop = { + .exit = mt_session_exit, + .exited = mt_session_exited, + .process = mt_session_proc, + }; + struct fuse_chan_ops cop = { + .receive = mt_chan_receive, + }; + + pd.f = f; + pd.prevch = prevch; + pd.prevse = prevse; + pd.proc = proc; + pd.data = data; + + se = fuse_session_new(&sop, &pd); + if (se == NULL) + return -1; + + ch = fuse_chan_new(&cop, fuse_chan_fd(prevch), + sizeof(struct fuse_cmd *), &pd); + if (ch == NULL) { + fuse_session_destroy(se); + return -1; + } + fuse_session_add_chan(se, ch); + res = fuse_session_loop_mt(se); + fuse_session_destroy(se); + return res; } int fuse_loop_mt(struct fuse *f) { - if (f == NULL) - return -1; + if (f == NULL) + return -1; - return fuse_session_loop_mt(fuse_get_session(f)); + return fuse_session_loop_mt(fuse_get_session(f)); } FUSE_SYMVER(".symver fuse_loop_mt_proc,__fuse_loop_mt@"); diff --git a/lib/fuse_opt.c b/lib/fuse_opt.c index d10e624..8a9019b 100644 --- a/lib/fuse_opt.c +++ b/lib/fuse_opt.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_opt.h" @@ -15,71 +15,71 @@ #include <assert.h> struct fuse_opt_context { - void *data; - const struct fuse_opt *opt; - fuse_opt_proc_t proc; - int argctr; - int argc; - char **argv; - struct fuse_args outargs; - char *opts; - int nonopt; + void *data; + const struct fuse_opt *opt; + fuse_opt_proc_t proc; + int argctr; + int argc; + char **argv; + struct fuse_args outargs; + char *opts; + int nonopt; }; void fuse_opt_free_args(struct fuse_args *args) { - if (args) { - if (args->argv && args->allocated) { - int i; - for (i = 0; i < args->argc; i++) - free(args->argv[i]); - free(args->argv); - } - args->argc = 0; - args->argv = NULL; - args->allocated = 0; - } + if (args) { + if (args->argv && args->allocated) { + int i; + for (i = 0; i < args->argc; i++) + free(args->argv[i]); + free(args->argv); + } + args->argc = 0; + args->argv = NULL; + args->allocated = 0; + } } static int alloc_failed(void) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; } int fuse_opt_add_arg(struct fuse_args *args, const char *arg) { - char **newargv; - char *newarg; + char **newargv; + char *newarg; - assert(!args->argv || args->allocated); + assert(!args->argv || args->allocated); - newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *)); - newarg = newargv ? strdup(arg) : NULL; - if (!newargv || !newarg) - return alloc_failed(); + newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *)); + newarg = newargv ? strdup(arg) : NULL; + if (!newargv || !newarg) + return alloc_failed(); - args->argv = newargv; - args->allocated = 1; - args->argv[args->argc++] = newarg; - args->argv[args->argc] = NULL; - return 0; + args->argv = newargv; + args->allocated = 1; + args->argv[args->argc++] = newarg; + args->argv[args->argc] = NULL; + return 0; } static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos, const char *arg) { - assert(pos <= args->argc); - if (fuse_opt_add_arg(args, arg) == -1) - return -1; - - if (pos != args->argc - 1) { - char *newarg = args->argv[args->argc - 1]; - memmove(&args->argv[pos + 1], &args->argv[pos], - sizeof(char *) * (args->argc - pos - 1)); - args->argv[pos] = newarg; - } - return 0; + assert(pos <= args->argc); + if (fuse_opt_add_arg(args, arg) == -1) + return -1; + + if (pos != args->argc - 1) { + char *newarg = args->argv[args->argc - 1]; + memmove(&args->argv[pos + 1], &args->argv[pos], + sizeof(char *) * (args->argc - pos - 1)); + args->argv[pos] = newarg; + } + return 0; } int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) @@ -96,288 +96,290 @@ int fuse_opt_insert_arg_compat(struct fuse_args *args, int pos, const char *arg) static int next_arg(struct fuse_opt_context *ctx, const char *opt) { - if (ctx->argctr + 1 >= ctx->argc) { - fprintf(stderr, "fuse: missing argument after `%s'\n", opt); - return -1; - } - ctx->argctr++; - return 0; + if (ctx->argctr + 1 >= ctx->argc) { + fprintf(stderr, "fuse: missing argument after `%s'\n", opt); + return -1; + } + ctx->argctr++; + return 0; } static int add_arg(struct fuse_opt_context *ctx, const char *arg) { - return fuse_opt_add_arg(&ctx->outargs, arg); + return fuse_opt_add_arg(&ctx->outargs, arg); } int fuse_opt_add_opt(char **opts, const char *opt) { - char *newopts; - if (!*opts) - newopts = strdup(opt); - else { - unsigned oldlen = strlen(*opts); - newopts = realloc(*opts, oldlen + 1 + strlen(opt) + 1); - if (newopts) { - newopts[oldlen] = ','; - strcpy(newopts + oldlen + 1, opt); - } - } - if (!newopts) - return alloc_failed(); - - *opts = newopts; - return 0; + char *newopts; + if (!*opts) + newopts = strdup(opt); + else { + unsigned oldlen = strlen(*opts); + newopts = realloc(*opts, oldlen + 1 + strlen(opt) + 1); + if (newopts) { + newopts[oldlen] = ','; + strcpy(newopts + oldlen + 1, opt); + } + } + if (!newopts) + return alloc_failed(); + + *opts = newopts; + return 0; } static int add_opt(struct fuse_opt_context *ctx, const char *opt) { - return fuse_opt_add_opt(&ctx->opts, opt); + return fuse_opt_add_opt(&ctx->opts, opt); } static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key, - int iso) + int iso) { - if (key == FUSE_OPT_KEY_DISCARD) - return 0; - - if (key != FUSE_OPT_KEY_KEEP && ctx->proc) { - int res = ctx->proc(ctx->data, arg, key, &ctx->outargs); - if (res == -1 || !res) - return res; - } - if (iso) - return add_opt(ctx, arg); - else - return add_arg(ctx, arg); + if (key == FUSE_OPT_KEY_DISCARD) + return 0; + + if (key != FUSE_OPT_KEY_KEEP && ctx->proc) { + int res = ctx->proc(ctx->data, arg, key, &ctx->outargs); + if (res == -1 || !res) + return res; + } + if (iso) + return add_opt(ctx, arg); + else + return add_arg(ctx, arg); } static int match_template(const char *t, const char *arg, unsigned *sepp) { - int arglen = strlen(arg); - const char *sep = strchr(t, '='); - sep = sep ? sep : strchr(t, ' '); - if (sep && (!sep[1] || sep[1] == '%')) { - int tlen = sep - t; - if (sep[0] == '=') - tlen ++; - if (arglen >= tlen && strncmp(arg, t, tlen) == 0) { - *sepp = sep - t; - return 1; - } - } - if (strcmp(t, arg) == 0) { - *sepp = 0; - return 1; - } - return 0; + int arglen = strlen(arg); + const char *sep = strchr(t, '='); + sep = sep ? sep : strchr(t, ' '); + if (sep && (!sep[1] || sep[1] == '%')) { + int tlen = sep - t; + if (sep[0] == '=') + tlen ++; + if (arglen >= tlen && strncmp(arg, t, tlen) == 0) { + *sepp = sep - t; + return 1; + } + } + if (strcmp(t, arg) == 0) { + *sepp = 0; + return 1; + } + return 0; } static const struct fuse_opt *find_opt(const struct fuse_opt *opt, - const char *arg, unsigned *sepp) + const char *arg, unsigned *sepp) { - for (; opt && opt->templ; opt++) - if (match_template(opt->templ, arg, sepp)) - return opt; - return NULL; + for (; opt && opt->templ; opt++) + if (match_template(opt->templ, arg, sepp)) + return opt; + return NULL; } int fuse_opt_match(const struct fuse_opt *opts, const char *opt) { - unsigned dummy; - return find_opt(opts, opt, &dummy) ? 1 : 0; + unsigned dummy; + return find_opt(opts, opt, &dummy) ? 1 : 0; } static int process_opt_param(void *var, const char *format, const char *param, - const char *arg) + const char *arg) { - assert(format[0] == '%'); - if (format[1] == 's') { - char *copy = strdup(param); - if (!copy) - return alloc_failed(); - - *(char **) var = copy; - } else { - if (sscanf(param, format, var) != 1) { - fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg); - return -1; - } - } - return 0; + assert(format[0] == '%'); + if (format[1] == 's') { + char *copy = strdup(param); + if (!copy) + return alloc_failed(); + + *(char **) var = copy; + } else { + if (sscanf(param, format, var) != 1) { + fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg); + return -1; + } + } + return 0; } static int process_opt(struct fuse_opt_context *ctx, - const struct fuse_opt *opt, unsigned sep, - const char *arg, int iso) + const struct fuse_opt *opt, unsigned sep, + const char *arg, int iso) { - if (opt->offset == -1U) { - if (call_proc(ctx, arg, opt->value, iso) == -1) - return -1; - } else { - void *var = ctx->data + opt->offset; - if (sep && opt->templ[sep + 1]) { - const char *param = arg + sep; - if (opt->templ[sep] == '=') - param ++; - if (process_opt_param(var, opt->templ + sep + 1, - param, arg) == -1) - return -1; - } else - *(int *)var = opt->value; - } - return 0; + if (opt->offset == -1U) { + if (call_proc(ctx, arg, opt->value, iso) == -1) + return -1; + } else { + void *var = ctx->data + opt->offset; + if (sep && opt->templ[sep + 1]) { + const char *param = arg + sep; + if (opt->templ[sep] == '=') + param ++; + if (process_opt_param(var, opt->templ + sep + 1, + param, arg) == -1) + return -1; + } else + *(int *)var = opt->value; + } + return 0; } static int process_opt_sep_arg(struct fuse_opt_context *ctx, - const struct fuse_opt *opt, unsigned sep, - const char *arg, int iso) + const struct fuse_opt *opt, unsigned sep, + const char *arg, int iso) { - int res; - char *newarg; - char *param; + int res; + char *newarg; + char *param; - if (next_arg(ctx, arg) == -1) - return -1; + if (next_arg(ctx, arg) == -1) + return -1; - param = ctx->argv[ctx->argctr]; - newarg = malloc(sep + strlen(param) + 1); - if (!newarg) - return alloc_failed(); + param = ctx->argv[ctx->argctr]; + newarg = malloc(sep + strlen(param) + 1); + if (!newarg) + return alloc_failed(); - memcpy(newarg, arg, sep); - strcpy(newarg + sep, param); - res = process_opt(ctx, opt, sep, newarg, iso); - free(newarg); + memcpy(newarg, arg, sep); + strcpy(newarg + sep, param); + res = process_opt(ctx, opt, sep, newarg, iso); + free(newarg); - return res; + return res; } static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso) { - unsigned sep; - const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep); - if (opt) { - for (; opt; opt = find_opt(opt + 1, arg, &sep)) { - int res; - if (sep && opt->templ[sep] == ' ' && !arg[sep]) - res = process_opt_sep_arg(ctx, opt, sep, arg, iso); - else - res = process_opt(ctx, opt, sep, arg, iso); - if (res == -1) - return -1; - } - return 0; - } else - return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso); + unsigned sep; + const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep); + if (opt) { + for (; opt; opt = find_opt(opt + 1, arg, &sep)) { + int res; + if (sep && opt->templ[sep] == ' ' && !arg[sep]) + res = process_opt_sep_arg(ctx, opt, sep, arg, + iso); + else + res = process_opt(ctx, opt, sep, arg, iso); + if (res == -1) + return -1; + } + return 0; + } else + return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso); } static int process_real_option_group(struct fuse_opt_context *ctx, char *opts) { - char *sep; - - do { - int res; - sep = strchr(opts, ','); - if (sep) - *sep = '\0'; - res = process_gopt(ctx, opts, 1); - if (res == -1) - return -1; - opts = sep + 1; - } while (sep); - - return 0; + char *sep; + + do { + int res; + sep = strchr(opts, ','); + if (sep) + *sep = '\0'; + res = process_gopt(ctx, opts, 1); + if (res == -1) + return -1; + opts = sep + 1; + } while (sep); + + return 0; } static int process_option_group(struct fuse_opt_context *ctx, const char *opts) { - int res; - char *copy; - const char *sep = strchr(opts, ','); - if (!sep) - return process_gopt(ctx, opts, 1); - - copy = strdup(opts); - if (!copy) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - res = process_real_option_group(ctx, copy); - free(copy); - return res; + int res; + char *copy; + const char *sep = strchr(opts, ','); + if (!sep) + return process_gopt(ctx, opts, 1); + + copy = strdup(opts); + if (!copy) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + res = process_real_option_group(ctx, copy); + free(copy); + return res; } static int process_one(struct fuse_opt_context *ctx, const char *arg) { - if (ctx->nonopt || arg[0] != '-') - return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0); - else if (arg[1] == 'o') { - if (arg[2]) - return process_option_group(ctx, arg + 2); - else { - if (next_arg(ctx, arg) == -1) - return -1; - - return process_option_group(ctx, ctx->argv[ctx->argctr]); - } - } else if (arg[1] == '-' && !arg[2]) { - if (add_arg(ctx, arg) == -1) - return -1; - ctx->nonopt = ctx->outargs.argc; - return 0; - } else - return process_gopt(ctx, arg, 0); + if (ctx->nonopt || arg[0] != '-') + return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0); + else if (arg[1] == 'o') { + if (arg[2]) + return process_option_group(ctx, arg + 2); + else { + if (next_arg(ctx, arg) == -1) + return -1; + + return process_option_group(ctx, + ctx->argv[ctx->argctr]); + } + } else if (arg[1] == '-' && !arg[2]) { + if (add_arg(ctx, arg) == -1) + return -1; + ctx->nonopt = ctx->outargs.argc; + return 0; + } else + return process_gopt(ctx, arg, 0); } static int opt_parse(struct fuse_opt_context *ctx) { - if (ctx->argc) { - if (add_arg(ctx, ctx->argv[0]) == -1) - return -1; - } - - for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++) - if (process_one(ctx, ctx->argv[ctx->argctr]) == -1) - return -1; - - if (ctx->opts) { - if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 || - fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) - return -1; - } - if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) { - free(ctx->outargs.argv[ctx->outargs.argc - 1]); - ctx->outargs.argv[--ctx->outargs.argc] = NULL; - } - - return 0; + if (ctx->argc) { + if (add_arg(ctx, ctx->argv[0]) == -1) + return -1; + } + + for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++) + if (process_one(ctx, ctx->argv[ctx->argctr]) == -1) + return -1; + + if (ctx->opts) { + if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 || + fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) + return -1; + } + if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) { + free(ctx->outargs.argv[ctx->outargs.argc - 1]); + ctx->outargs.argv[--ctx->outargs.argc] = NULL; + } + + return 0; } int fuse_opt_parse(struct fuse_args *args, void *data, - const struct fuse_opt opts[], fuse_opt_proc_t proc) + const struct fuse_opt opts[], fuse_opt_proc_t proc) { - int res; - struct fuse_opt_context ctx = { - .data = data, - .opt = opts, - .proc = proc, - }; - - if (!args || !args->argv || !args->argc) - return 0; - - ctx.argc = args->argc; - ctx.argv = args->argv; - - res = opt_parse(&ctx); - if (res != -1) { - struct fuse_args tmp = *args; - *args = ctx.outargs; - ctx.outargs = tmp; - } - free(ctx.opts); - fuse_opt_free_args(&ctx.outargs); - return res; + int res; + struct fuse_opt_context ctx = { + .data = data, + .opt = opts, + .proc = proc, + }; + + if (!args || !args->argv || !args->argc) + return 0; + + ctx.argc = args->argc; + ctx.argv = args->argv; + + res = opt_parse(&ctx); + if (res != -1) { + struct fuse_args tmp = *args; + *args = ctx.outargs; + ctx.outargs = tmp; + } + free(ctx.opts); + fuse_opt_free_args(&ctx.outargs); + return res; } /* This symbol version was mistakenly added to the version script */ diff --git a/lib/fuse_session.c b/lib/fuse_session.c index cf2e20b..5efedd9 100644 --- a/lib/fuse_session.c +++ b/lib/fuse_session.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_lowlevel.h" @@ -18,190 +18,191 @@ #include <errno.h> struct fuse_session { - struct fuse_session_ops op; + struct fuse_session_ops op; - void *data; + void *data; - volatile int exited; + volatile int exited; - struct fuse_chan *ch; + struct fuse_chan *ch; }; struct fuse_chan { - struct fuse_chan_ops op; + struct fuse_chan_ops op; - struct fuse_session *se; + struct fuse_session *se; - int fd; + int fd; - size_t bufsize; + size_t bufsize; - void *data; + void *data; - int compat; + int compat; }; struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data) { - struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se)); - if (se == NULL) { - fprintf(stderr, "fuse: failed to allocate session\n"); - return NULL; - } + struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se)); + if (se == NULL) { + fprintf(stderr, "fuse: failed to allocate session\n"); + return NULL; + } - memset(se, 0, sizeof(*se)); - se->op = *op; - se->data = data; + memset(se, 0, sizeof(*se)); + se->op = *op; + se->data = data; - return se; + return se; } void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch) { - assert(se->ch == NULL); - assert(ch->se == NULL); - se->ch = ch; - ch->se = se; + assert(se->ch == NULL); + assert(ch->se == NULL); + se->ch = ch; + ch->se = se; } void fuse_session_remove_chan(struct fuse_chan *ch) { - struct fuse_session *se = ch->se; - if (se) { - assert(se->ch == ch); - se->ch = NULL; - ch->se = NULL; - } + struct fuse_session *se = ch->se; + if (se) { + assert(se->ch == ch); + se->ch = NULL; + ch->se = NULL; + } } struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, - struct fuse_chan *ch) + struct fuse_chan *ch) { - assert(ch == NULL || ch == se->ch); - if (ch == NULL) - return se->ch; - else - return NULL; + assert(ch == NULL || ch == se->ch); + if (ch == NULL) + return se->ch; + else + return NULL; } void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, - struct fuse_chan *ch) + struct fuse_chan *ch) { - se->op.process(se->data, buf, len, ch); + se->op.process(se->data, buf, len, ch); } void fuse_session_destroy(struct fuse_session *se) { - if (se->op.destroy) - se->op.destroy(se->data); - if (se->ch != NULL) - fuse_chan_destroy(se->ch); - free(se); + if (se->op.destroy) + se->op.destroy(se->data); + if (se->ch != NULL) + fuse_chan_destroy(se->ch); + free(se); } void fuse_session_exit(struct fuse_session *se) { - if (se->op.exit) - se->op.exit(se->data, 1); - se->exited = 1; + if (se->op.exit) + se->op.exit(se->data, 1); + se->exited = 1; } void fuse_session_reset(struct fuse_session *se) { - if (se->op.exit) - se->op.exit(se->data, 0); - se->exited = 0; + if (se->op.exit) + se->op.exit(se->data, 0); + se->exited = 0; } int fuse_session_exited(struct fuse_session *se) { - if (se->op.exited) - return se->op.exited(se->data); - else - return se->exited; + if (se->op.exited) + return se->op.exited(se->data); + else + return se->exited; } static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd, - size_t bufsize, void *data, int compat) + size_t bufsize, void *data, + int compat) { - struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); - if (ch == NULL) { - fprintf(stderr, "fuse: failed to allocate channel\n"); - return NULL; - } + struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); + if (ch == NULL) { + fprintf(stderr, "fuse: failed to allocate channel\n"); + return NULL; + } - memset(ch, 0, sizeof(*ch)); - ch->op = *op; - ch->fd = fd; - ch->bufsize = bufsize; - ch->data = data; - ch->compat = compat; + memset(ch, 0, sizeof(*ch)); + ch->op = *op; + ch->fd = fd; + ch->bufsize = bufsize; + ch->data = data; + ch->compat = compat; - return ch; + return ch; } struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, - size_t bufsize, void *data) + size_t bufsize, void *data) { - return fuse_chan_new_common(op, fd, bufsize, data, 0); + return fuse_chan_new_common(op, fd, bufsize, data, 0); } struct fuse_chan *fuse_chan_new_compat24(struct fuse_chan_ops_compat24 *op, - int fd, size_t bufsize, void *data) + int fd, size_t bufsize, void *data) { - return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize, - data, 24); + return fuse_chan_new_common((struct fuse_chan_ops *) op, fd, bufsize, + data, 24); } int fuse_chan_fd(struct fuse_chan *ch) { - return ch->fd; + return ch->fd; } size_t fuse_chan_bufsize(struct fuse_chan *ch) { - return ch->bufsize; + return ch->bufsize; } void *fuse_chan_data(struct fuse_chan *ch) { - return ch->data; + return ch->data; } struct fuse_session *fuse_chan_session(struct fuse_chan *ch) { - return ch->se; + return ch->se; } int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size) { - struct fuse_chan *ch = *chp; - if (ch->compat) - return ((struct fuse_chan_ops_compat24 *) &ch->op) - ->receive(ch, buf, size); - else - return ch->op.receive(chp, buf, size); + struct fuse_chan *ch = *chp; + if (ch->compat) + return ((struct fuse_chan_ops_compat24 *) &ch->op) + ->receive(ch, buf, size); + else + return ch->op.receive(chp, buf, size); } int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size) { - int res; + int res; - res = fuse_chan_recv(&ch, buf, size); - return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0; + res = fuse_chan_recv(&ch, buf, size); + return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0; } int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count) { - return ch->op.send(ch, iov, count); + return ch->op.send(ch, iov, count); } void fuse_chan_destroy(struct fuse_chan *ch) { - fuse_session_remove_chan(ch); - if (ch->op.destroy) - ch->op.destroy(ch); - free(ch); + fuse_session_remove_chan(ch); + if (ch->op.destroy) + ch->op.destroy(ch); + free(ch); } #ifndef __FreeBSD__ diff --git a/lib/fuse_signals.c b/lib/fuse_signals.c index 25998bf..88ac39e 100644 --- a/lib/fuse_signals.c +++ b/lib/fuse_signals.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #include "fuse_lowlevel.h" @@ -16,57 +16,57 @@ static struct fuse_session *fuse_instance; static void exit_handler(int sig) { - (void) sig; - if (fuse_instance) - fuse_session_exit(fuse_instance); + (void) sig; + if (fuse_instance) + fuse_session_exit(fuse_instance); } static int set_one_signal_handler(int sig, void (*handler)(int)) { - struct sigaction sa; - struct sigaction old_sa; + struct sigaction sa; + struct sigaction old_sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = handler; - sigemptyset(&(sa.sa_mask)); - sa.sa_flags = 0; + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = handler; + sigemptyset(&(sa.sa_mask)); + sa.sa_flags = 0; - if (sigaction(sig, NULL, &old_sa) == -1) { - perror("fuse: cannot get old signal handler"); - return -1; - } + if (sigaction(sig, NULL, &old_sa) == -1) { + perror("fuse: cannot get old signal handler"); + return -1; + } - if (old_sa.sa_handler == SIG_DFL && - sigaction(sig, &sa, NULL) == -1) { - perror("fuse: cannot set signal handler"); - return -1; - } - return 0; + if (old_sa.sa_handler == SIG_DFL && + sigaction(sig, &sa, NULL) == -1) { + perror("fuse: cannot set signal handler"); + return -1; + } + return 0; } int fuse_set_signal_handlers(struct fuse_session *se) { - if (set_one_signal_handler(SIGHUP, exit_handler) == -1 || - set_one_signal_handler(SIGINT, exit_handler) == -1 || - set_one_signal_handler(SIGTERM, exit_handler) == -1 || - set_one_signal_handler(SIGPIPE, SIG_IGN) == -1) - return -1; + if (set_one_signal_handler(SIGHUP, exit_handler) == -1 || + set_one_signal_handler(SIGINT, exit_handler) == -1 || + set_one_signal_handler(SIGTERM, exit_handler) == -1 || + set_one_signal_handler(SIGPIPE, SIG_IGN) == -1) + return -1; - fuse_instance = se; - return 0; + fuse_instance = se; + return 0; } void fuse_remove_signal_handlers(struct fuse_session *se) { - if (fuse_instance != se) - fprintf(stderr, - "fuse: fuse_remove_signal_handlers: unknown session\n"); - else - fuse_instance = NULL; + if (fuse_instance != se) + fprintf(stderr, + "fuse: fuse_remove_signal_handlers: unknown session\n"); + else + fuse_instance = NULL; - set_one_signal_handler(SIGHUP, SIG_DFL); - set_one_signal_handler(SIGINT, SIG_DFL); - set_one_signal_handler(SIGTERM, SIG_DFL); - set_one_signal_handler(SIGPIPE, SIG_DFL); + set_one_signal_handler(SIGHUP, SIG_DFL); + set_one_signal_handler(SIGINT, SIG_DFL); + set_one_signal_handler(SIGTERM, SIG_DFL); + set_one_signal_handler(SIGPIPE, SIG_DFL); } diff --git a/lib/helper.c b/lib/helper.c index fbbf4b2..a175ee9 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "config.h" @@ -22,333 +22,336 @@ #include <errno.h> enum { - KEY_HELP, - KEY_HELP_NOHEADER, - KEY_VERSION, + KEY_HELP, + KEY_HELP_NOHEADER, + KEY_VERSION, }; struct helper_opts { - int singlethread; - int foreground; - int nodefault_subtype; - char *mountpoint; + int singlethread; + int foreground; + int nodefault_subtype; + char *mountpoint; }; #define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 } static const struct fuse_opt fuse_helper_opts[] = { - FUSE_HELPER_OPT("-d", foreground), - FUSE_HELPER_OPT("debug", foreground), - FUSE_HELPER_OPT("-f", foreground), - FUSE_HELPER_OPT("-s", singlethread), - FUSE_HELPER_OPT("fsname=", nodefault_subtype), - FUSE_HELPER_OPT("subtype=", nodefault_subtype), - - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_END + FUSE_HELPER_OPT("-d", foreground), + FUSE_HELPER_OPT("debug", foreground), + FUSE_HELPER_OPT("-f", foreground), + FUSE_HELPER_OPT("-s", singlethread), + FUSE_HELPER_OPT("fsname=", nodefault_subtype), + FUSE_HELPER_OPT("subtype=", nodefault_subtype), + + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_END }; static void usage(const char *progname) { - fprintf(stderr, - "usage: %s mountpoint [options]\n\n", progname); - fprintf(stderr, - "general options:\n" - " -o opt,[opt...] mount options\n" - " -h --help print help\n" - " -V --version print version\n" - "\n"); + fprintf(stderr, + "usage: %s mountpoint [options]\n\n", progname); + fprintf(stderr, + "general options:\n" + " -o opt,[opt...] mount options\n" + " -h --help print help\n" + " -V --version print version\n" + "\n"); } static void helper_help(void) { - fprintf(stderr, - "FUSE options:\n" - " -d -o debug enable debug output (implies -f)\n" - " -f foreground operation\n" - " -s disable multi-threaded operation\n" - "\n" - ); + fprintf(stderr, + "FUSE options:\n" + " -d -o debug enable debug output (implies -f)\n" + " -f foreground operation\n" + " -s disable multi-threaded operation\n" + "\n" + ); } static void helper_version(void) { - fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); + fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); } static int fuse_helper_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - struct helper_opts *hopts = data; - - switch (key) { - case KEY_HELP: - usage(outargs->argv[0]); - /* fall through */ - - case KEY_HELP_NOHEADER: - helper_help(); - return fuse_opt_add_arg(outargs, "-h"); - - case KEY_VERSION: - helper_version(); - return 1; - - case FUSE_OPT_KEY_NONOPT: - if (!hopts->mountpoint) { - char mountpoint[PATH_MAX]; - if (realpath(arg, mountpoint) == NULL) { - fprintf(stderr, "fuse: bad mount point `%s': %s\n", arg, strerror(errno)); - return -1; - } - return fuse_opt_add_opt(&hopts->mountpoint, mountpoint); - } else { - fprintf(stderr, "fuse: invalid argument `%s'\n", arg); - return -1; - } - - default: - return 1; - } + struct helper_opts *hopts = data; + + switch (key) { + case KEY_HELP: + usage(outargs->argv[0]); + /* fall through */ + + case KEY_HELP_NOHEADER: + helper_help(); + return fuse_opt_add_arg(outargs, "-h"); + + case KEY_VERSION: + helper_version(); + return 1; + + case FUSE_OPT_KEY_NONOPT: + if (!hopts->mountpoint) { + char mountpoint[PATH_MAX]; + if (realpath(arg, mountpoint) == NULL) { + fprintf(stderr, + "fuse: bad mount point `%s': %s\n", + arg, strerror(errno)); + return -1; + } + return fuse_opt_add_opt(&hopts->mountpoint, mountpoint); + } else { + fprintf(stderr, "fuse: invalid argument `%s'\n", arg); + return -1; + } + + default: + return 1; + } } static int add_default_subtype(const char *progname, struct fuse_args *args) { - int res; - char *subtype_opt; - const char *basename = strrchr(progname, '/'); - if (basename == NULL) - basename = progname; - else if (basename[1] != '\0') - basename++; - - subtype_opt = (char *) malloc(strlen(basename) + 64); - if (subtype_opt == NULL) { - fprintf(stderr, "fuse: memory allocation failed\n"); - return -1; - } - sprintf(subtype_opt, "-osubtype=%s", basename); - res = fuse_opt_add_arg(args, subtype_opt); - free(subtype_opt); - return res; + int res; + char *subtype_opt; + const char *basename = strrchr(progname, '/'); + if (basename == NULL) + basename = progname; + else if (basename[1] != '\0') + basename++; + + subtype_opt = (char *) malloc(strlen(basename) + 64); + if (subtype_opt == NULL) { + fprintf(stderr, "fuse: memory allocation failed\n"); + return -1; + } + sprintf(subtype_opt, "-osubtype=%s", basename); + res = fuse_opt_add_arg(args, subtype_opt); + free(subtype_opt); + return res; } int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, - int *multithreaded, int *foreground) + int *multithreaded, int *foreground) { - int res; - struct helper_opts hopts; - - memset(&hopts, 0, sizeof(hopts)); - res = fuse_opt_parse(args, &hopts, fuse_helper_opts, fuse_helper_opt_proc); - if (res == -1) - return -1; - - if (!hopts.nodefault_subtype) { - res = add_default_subtype(args->argv[0], args); - if (res == -1) - goto err; - } - if (mountpoint) - *mountpoint = hopts.mountpoint; - else - free(hopts.mountpoint); - - if (multithreaded) - *multithreaded = !hopts.singlethread; - if (foreground) - *foreground = hopts.foreground; - return 0; - - err: - free(hopts.mountpoint); - return -1; + int res; + struct helper_opts hopts; + + memset(&hopts, 0, sizeof(hopts)); + res = fuse_opt_parse(args, &hopts, fuse_helper_opts, + fuse_helper_opt_proc); + if (res == -1) + return -1; + + if (!hopts.nodefault_subtype) { + res = add_default_subtype(args->argv[0], args); + if (res == -1) + goto err; + } + if (mountpoint) + *mountpoint = hopts.mountpoint; + else + free(hopts.mountpoint); + + if (multithreaded) + *multithreaded = !hopts.singlethread; + if (foreground) + *foreground = hopts.foreground; + return 0; + +err: + free(hopts.mountpoint); + return -1; } int fuse_daemonize(int foreground) { - int res; - - if (!foreground) { - res = daemon(0, 0); - if (res == -1) { - perror("fuse: failed to daemonize program\n"); - return -1; - } - } - return 0; + int res; + + if (!foreground) { + res = daemon(0, 0); + if (res == -1) { + perror("fuse: failed to daemonize program\n"); + return -1; + } + } + return 0; } static struct fuse_chan *fuse_mount_common(const char *mountpoint, - struct fuse_args *args) + struct fuse_args *args) { - struct fuse_chan *ch; - int fd; - - /* - * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos - * would ensue. - */ - do { - fd = open("/dev/null", O_RDWR); - if (fd > 2) - close(fd); - } while (fd >= 0 && fd <= 2); - - fd = fuse_mount_compat25(mountpoint, args); - if (fd == -1) - return NULL; - - ch = fuse_kern_chan_new(fd); - if (!ch) - fuse_kern_unmount(mountpoint, fd); - - return ch; + struct fuse_chan *ch; + int fd; + + /* + * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos + * would ensue. + */ + do { + fd = open("/dev/null", O_RDWR); + if (fd > 2) + close(fd); + } while (fd >= 0 && fd <= 2); + + fd = fuse_mount_compat25(mountpoint, args); + if (fd == -1) + return NULL; + + ch = fuse_kern_chan_new(fd); + if (!ch) + fuse_kern_unmount(mountpoint, fd); + + return ch; } struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args) { - return fuse_mount_common(mountpoint, args); + return fuse_mount_common(mountpoint, args); } static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch) { - int fd = ch ? fuse_chan_fd(ch) : -1; - fuse_kern_unmount(mountpoint, fd); - fuse_chan_destroy(ch); + int fd = ch ? fuse_chan_fd(ch) : -1; + fuse_kern_unmount(mountpoint, fd); + fuse_chan_destroy(ch); } void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) { - fuse_unmount_common(mountpoint, ch); + fuse_unmount_common(mountpoint, ch); } static struct fuse *fuse_setup_common(int argc, char *argv[], - const struct fuse_operations *op, - size_t op_size, - char **mountpoint, - int *multithreaded, - int *fd, - void *user_data, - int compat) + const struct fuse_operations *op, + size_t op_size, + char **mountpoint, + int *multithreaded, + int *fd, + void *user_data, + int compat) { - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse_chan *ch; - struct fuse *fuse; - int foreground; - int res; - - res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground); - if (res == -1) - return NULL; - - ch = fuse_mount_common(*mountpoint, &args); - if (!ch) { - fuse_opt_free_args(&args); - goto err_free; - } - - fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat); - fuse_opt_free_args(&args); - if (fuse == NULL) - goto err_unmount; - - res = fuse_daemonize(foreground); - if (res == -1) - goto err_unmount; - - res = fuse_set_signal_handlers(fuse_get_session(fuse)); - if (res == -1) - goto err_unmount; - - if (fd) - *fd = fuse_chan_fd(ch); - - return fuse; - - err_unmount: - fuse_unmount_common(*mountpoint, ch); - if (fuse) - fuse_destroy(fuse); - err_free: - free(*mountpoint); - return NULL; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + struct fuse_chan *ch; + struct fuse *fuse; + int foreground; + int res; + + res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground); + if (res == -1) + return NULL; + + ch = fuse_mount_common(*mountpoint, &args); + if (!ch) { + fuse_opt_free_args(&args); + goto err_free; + } + + fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat); + fuse_opt_free_args(&args); + if (fuse == NULL) + goto err_unmount; + + res = fuse_daemonize(foreground); + if (res == -1) + goto err_unmount; + + res = fuse_set_signal_handlers(fuse_get_session(fuse)); + if (res == -1) + goto err_unmount; + + if (fd) + *fd = fuse_chan_fd(ch); + + return fuse; + +err_unmount: + fuse_unmount_common(*mountpoint, ch); + if (fuse) + fuse_destroy(fuse); +err_free: + free(*mountpoint); + return NULL; } struct fuse *fuse_setup(int argc, char *argv[], - const struct fuse_operations *op, size_t op_size, - char **mountpoint, int *multithreaded, void *user_data) + const struct fuse_operations *op, size_t op_size, + char **mountpoint, int *multithreaded, void *user_data) { - return fuse_setup_common(argc, argv, op, op_size, mountpoint, - multithreaded, NULL, user_data, 0); + return fuse_setup_common(argc, argv, op, op_size, mountpoint, + multithreaded, NULL, user_data, 0); } static void fuse_teardown_common(struct fuse *fuse, char *mountpoint) { - struct fuse_session *se = fuse_get_session(fuse); - struct fuse_chan *ch = fuse_session_next_chan(se, NULL); - fuse_remove_signal_handlers(se); - fuse_unmount_common(mountpoint, ch); - fuse_destroy(fuse); - free(mountpoint); + struct fuse_session *se = fuse_get_session(fuse); + struct fuse_chan *ch = fuse_session_next_chan(se, NULL); + fuse_remove_signal_handlers(se); + fuse_unmount_common(mountpoint, ch); + fuse_destroy(fuse); + free(mountpoint); } void fuse_teardown(struct fuse *fuse, char *mountpoint) { - fuse_teardown_common(fuse, mountpoint); + fuse_teardown_common(fuse, mountpoint); } static int fuse_main_common(int argc, char *argv[], - const struct fuse_operations *op, size_t op_size, - void *user_data, int compat) + const struct fuse_operations *op, size_t op_size, + void *user_data, int compat) { - struct fuse *fuse; - char *mountpoint; - int multithreaded; - int res; - - fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, - &multithreaded, NULL, user_data, compat); - if (fuse == NULL) - return 1; - - if (multithreaded) - res = fuse_loop_mt(fuse); - else - res = fuse_loop(fuse); - - fuse_teardown_common(fuse, mountpoint); - if (res == -1) - return 1; - - return 0; + struct fuse *fuse; + char *mountpoint; + int multithreaded; + int res; + + fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, + &multithreaded, NULL, user_data, compat); + if (fuse == NULL) + return 1; + + if (multithreaded) + res = fuse_loop_mt(fuse); + else + res = fuse_loop(fuse); + + fuse_teardown_common(fuse, mountpoint); + if (res == -1) + return 1; + + return 0; } int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, - size_t op_size, void *user_data) + size_t op_size, void *user_data) { - return fuse_main_common(argc, argv, op, op_size, user_data, 0); + return fuse_main_common(argc, argv, op, op_size, user_data, 0); } #undef fuse_main int fuse_main(void); int fuse_main(void) { - fprintf(stderr, "fuse_main(): This function does not exist\n"); - return -1; + fprintf(stderr, "fuse_main(): This function does not exist\n"); + return -1; } int fuse_version(void) { - return FUSE_VERSION; + return FUSE_VERSION; } #include "fuse_compat.h" @@ -356,51 +359,53 @@ int fuse_version(void) #ifndef __FreeBSD__ struct fuse *fuse_setup_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd) + const struct fuse_operations_compat22 *op, + size_t op_size, char **mountpoint, + int *multithreaded, int *fd) { - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - op_size, mountpoint, multithreaded, fd, NULL, 22); + return fuse_setup_common(argc, argv, (struct fuse_operations *) op, + op_size, mountpoint, multithreaded, fd, NULL, + 22); } struct fuse *fuse_setup_compat2(int argc, char *argv[], - const struct fuse_operations_compat2 *op, - char **mountpoint, int *multithreaded, - int *fd) + const struct fuse_operations_compat2 *op, + char **mountpoint, int *multithreaded, + int *fd) { - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), - mountpoint, multithreaded, fd, NULL, 21); + return fuse_setup_common(argc, argv, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat2), + mountpoint, multithreaded, fd, NULL, 21); } int fuse_main_real_compat22(int argc, char *argv[], - const struct fuse_operations_compat22 *op, - size_t op_size) + const struct fuse_operations_compat22 *op, + size_t op_size) { - return fuse_main_common(argc, argv, (struct fuse_operations *) op, op_size, - NULL, 22); + return fuse_main_common(argc, argv, (struct fuse_operations *) op, + op_size, NULL, 22); } void fuse_main_compat1(int argc, char *argv[], - const struct fuse_operations_compat1 *op) + const struct fuse_operations_compat1 *op) { - fuse_main_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat1), NULL, 11); + fuse_main_common(argc, argv, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat1), NULL, 11); } int fuse_main_compat2(int argc, char *argv[], - const struct fuse_operations_compat2 *op) + const struct fuse_operations_compat2 *op) { - return fuse_main_common(argc, argv, (struct fuse_operations *) op, - sizeof(struct fuse_operations_compat2), NULL, 21); + return fuse_main_common(argc, argv, (struct fuse_operations *) op, + sizeof(struct fuse_operations_compat2), NULL, + 21); } int fuse_mount_compat1(const char *mountpoint, const char *args[]) { - /* just ignore mount args for now */ - (void) args; - return fuse_mount_compat22(mountpoint, NULL); + /* just ignore mount args for now */ + (void) args; + return fuse_mount_compat22(mountpoint, NULL); } FUSE_SYMVER(".symver fuse_setup_compat2,__fuse_setup@"); @@ -413,31 +418,32 @@ FUSE_SYMVER(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2"); struct fuse *fuse_setup_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size, char **mountpoint, - int *multithreaded, int *fd) + const struct fuse_operations_compat25 *op, + size_t op_size, char **mountpoint, + int *multithreaded, int *fd) { - return fuse_setup_common(argc, argv, (struct fuse_operations *) op, - op_size, mountpoint, multithreaded, fd, NULL, 25); + return fuse_setup_common(argc, argv, (struct fuse_operations *) op, + op_size, mountpoint, multithreaded, fd, NULL, + 25); } int fuse_main_real_compat25(int argc, char *argv[], - const struct fuse_operations_compat25 *op, - size_t op_size) + const struct fuse_operations_compat25 *op, + size_t op_size) { - return fuse_main_common(argc, argv, (struct fuse_operations *) op, op_size, - NULL, 25); + return fuse_main_common(argc, argv, (struct fuse_operations *) op, + op_size, NULL, 25); } void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint) { - (void) fd; - fuse_teardown_common(fuse, mountpoint); + (void) fd; + fuse_teardown_common(fuse, mountpoint); } int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args) { - return fuse_kern_mount(mountpoint, args); + return fuse_kern_mount(mountpoint, args); } FUSE_SYMVER(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5"); diff --git a/lib/modules/iconv.c b/lib/modules/iconv.c index 350a472..c0e2b80 100644 --- a/lib/modules/iconv.c +++ b/lib/modules/iconv.c @@ -1,9 +1,9 @@ /* - fuse iconv module: file name charset conversion - Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu> + fuse iconv module: file name charset conversion + Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #define FUSE_USE_VERSION 26 @@ -20,689 +20,690 @@ #include <langinfo.h> struct iconv { - struct fuse_fs *next; - pthread_mutex_t lock; - char *from_code; - char *to_code; - iconv_t tofs; - iconv_t fromfs; + struct fuse_fs *next; + pthread_mutex_t lock; + char *from_code; + char *to_code; + iconv_t tofs; + iconv_t fromfs; }; struct iconv_dh { - struct iconv *ic; - void *prev_buf; - fuse_fill_dir_t prev_filler; + struct iconv *ic; + void *prev_buf; + fuse_fill_dir_t prev_filler; }; static struct iconv *iconv_get(void) { - return fuse_get_context()->private_data; + return fuse_get_context()->private_data; } static int iconv_convpath(struct iconv *ic, const char *path, char **newpathp, - int fromfs) -{ - size_t pathlen = strlen(path); - size_t newpathlen = pathlen * 4; - char *newpath = malloc(newpathlen + 1); - size_t plen = newpathlen; - char *p = newpath; - size_t res; - int err; - - if (!newpath) - return -ENOMEM; - - pthread_mutex_lock(&ic->lock); - do { - res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path, &pathlen, - &p, &plen); - if (res == (size_t) -1) { - char *tmp; - size_t inc; - - err = -EILSEQ; - if (errno != E2BIG) - goto err; - - inc = (pathlen + 1) * 4; - newpathlen += inc; - tmp = realloc(newpath, newpathlen + 1); - err = -ENOMEM; - if (!tmp) - goto err; - - p = tmp + (p - newpath); - plen += inc; - newpath = tmp; - } - } while (res == (size_t) -1); - pthread_mutex_unlock(&ic->lock); - *p = '\0'; - *newpathp = newpath; - return 0; - - err: - iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL); - pthread_mutex_unlock(&ic->lock); - free(newpath); - return err; + int fromfs) +{ + size_t pathlen = strlen(path); + size_t newpathlen = pathlen * 4; + char *newpath = malloc(newpathlen + 1); + size_t plen = newpathlen; + char *p = newpath; + size_t res; + int err; + + if (!newpath) + return -ENOMEM; + + pthread_mutex_lock(&ic->lock); + do { + res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path, + &pathlen, &p, &plen); + if (res == (size_t) -1) { + char *tmp; + size_t inc; + + err = -EILSEQ; + if (errno != E2BIG) + goto err; + + inc = (pathlen + 1) * 4; + newpathlen += inc; + tmp = realloc(newpath, newpathlen + 1); + err = -ENOMEM; + if (!tmp) + goto err; + + p = tmp + (p - newpath); + plen += inc; + newpath = tmp; + } + } while (res == (size_t) -1); + pthread_mutex_unlock(&ic->lock); + *p = '\0'; + *newpathp = newpath; + return 0; + +err: + iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL); + pthread_mutex_unlock(&ic->lock); + free(newpath); + return err; } static int iconv_getattr(const char *path, struct stat *stbuf) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_getattr(ic->next, newpath, stbuf); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_getattr(ic->next, newpath, stbuf); + free(newpath); + } + return err; } static int iconv_fgetattr(const char *path, struct stat *stbuf, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_fgetattr(ic->next, newpath, stbuf, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_fgetattr(ic->next, newpath, stbuf, fi); + free(newpath); + } + return err; } static int iconv_access(const char *path, int mask) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_access(ic->next, newpath, mask); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_access(ic->next, newpath, mask); + free(newpath); + } + return err; } static int iconv_readlink(const char *path, char *buf, size_t size) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_readlink(ic->next, newpath, buf, size); - if (!err) { - char *newlink; - err = iconv_convpath(ic, buf, &newlink, 1); - if (!err) { - strncpy(buf, newlink, size - 1); - buf[size - 1] = '\0'; - free(newlink); - } - } - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_readlink(ic->next, newpath, buf, size); + if (!err) { + char *newlink; + err = iconv_convpath(ic, buf, &newlink, 1); + if (!err) { + strncpy(buf, newlink, size - 1); + buf[size - 1] = '\0'; + free(newlink); + } + } + free(newpath); + } + return err; } static int iconv_opendir(const char *path, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_opendir(ic->next, newpath, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_opendir(ic->next, newpath, fi); + free(newpath); + } + return err; } static int iconv_dir_fill(void *buf, const char *name, - const struct stat *stbuf, off_t off) + const struct stat *stbuf, off_t off) { - struct iconv_dh *dh = buf; - char *newname; - int res = 0; - if (iconv_convpath(dh->ic, name, &newname, 1) == 0) { - res = dh->prev_filler(dh->prev_buf, newname, stbuf, off); - free(newname); - } - return res; + struct iconv_dh *dh = buf; + char *newname; + int res = 0; + if (iconv_convpath(dh->ic, name, &newname, 1) == 0) { + res = dh->prev_filler(dh->prev_buf, newname, stbuf, off); + free(newname); + } + return res; } static int iconv_readdir(const char *path, void *buf, fuse_fill_dir_t filler, - off_t offset, struct fuse_file_info *fi) -{ - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - struct iconv_dh dh; - dh.ic = ic; - dh.prev_buf = buf; - dh.prev_filler = filler; - err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill, offset, - fi); - free(newpath); - } - return err; + off_t offset, struct fuse_file_info *fi) +{ + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + struct iconv_dh dh; + dh.ic = ic; + dh.prev_buf = buf; + dh.prev_filler = filler; + err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill, + offset, fi); + free(newpath); + } + return err; } static int iconv_releasedir(const char *path, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_releasedir(ic->next, newpath, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_releasedir(ic->next, newpath, fi); + free(newpath); + } + return err; } static int iconv_mknod(const char *path, mode_t mode, dev_t rdev) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_mknod(ic->next, newpath, mode, rdev); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_mknod(ic->next, newpath, mode, rdev); + free(newpath); + } + return err; } static int iconv_mkdir(const char *path, mode_t mode) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_mkdir(ic->next, newpath, mode); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_mkdir(ic->next, newpath, mode); + free(newpath); + } + return err; } static int iconv_unlink(const char *path) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_unlink(ic->next, newpath); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_unlink(ic->next, newpath); + free(newpath); + } + return err; } static int iconv_rmdir(const char *path) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_rmdir(ic->next, newpath); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_rmdir(ic->next, newpath); + free(newpath); + } + return err; } static int iconv_symlink(const char *from, const char *to) { - struct iconv *ic = iconv_get(); - char *newfrom; - char *newto; - int err = iconv_convpath(ic, from, &newfrom, 0); - if (!err) { - err = iconv_convpath(ic, to, &newto, 0); - if (!err) { - err = fuse_fs_symlink(ic->next, newfrom, newto); - free(newto); - } - free(newfrom); - } - return err; + struct iconv *ic = iconv_get(); + char *newfrom; + char *newto; + int err = iconv_convpath(ic, from, &newfrom, 0); + if (!err) { + err = iconv_convpath(ic, to, &newto, 0); + if (!err) { + err = fuse_fs_symlink(ic->next, newfrom, newto); + free(newto); + } + free(newfrom); + } + return err; } static int iconv_rename(const char *from, const char *to) { - struct iconv *ic = iconv_get(); - char *newfrom; - char *newto; - int err = iconv_convpath(ic, from, &newfrom, 0); - if (!err) { - err = iconv_convpath(ic, to, &newto, 0); - if (!err) { - err = fuse_fs_rename(ic->next, newfrom, newto); - free(newto); - } - free(newfrom); - } - return err; + struct iconv *ic = iconv_get(); + char *newfrom; + char *newto; + int err = iconv_convpath(ic, from, &newfrom, 0); + if (!err) { + err = iconv_convpath(ic, to, &newto, 0); + if (!err) { + err = fuse_fs_rename(ic->next, newfrom, newto); + free(newto); + } + free(newfrom); + } + return err; } static int iconv_link(const char *from, const char *to) { - struct iconv *ic = iconv_get(); - char *newfrom; - char *newto; - int err = iconv_convpath(ic, from, &newfrom, 0); - if (!err) { - err = iconv_convpath(ic, to, &newto, 0); - if (!err) { - err = fuse_fs_link(ic->next, newfrom, newto); - free(newto); - } - free(newfrom); - } - return err; + struct iconv *ic = iconv_get(); + char *newfrom; + char *newto; + int err = iconv_convpath(ic, from, &newfrom, 0); + if (!err) { + err = iconv_convpath(ic, to, &newto, 0); + if (!err) { + err = fuse_fs_link(ic->next, newfrom, newto); + free(newto); + } + free(newfrom); + } + return err; } static int iconv_chmod(const char *path, mode_t mode) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_chmod(ic->next, newpath, mode); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_chmod(ic->next, newpath, mode); + free(newpath); + } + return err; } static int iconv_chown(const char *path, uid_t uid, gid_t gid) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_chown(ic->next, newpath, uid, gid); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_chown(ic->next, newpath, uid, gid); + free(newpath); + } + return err; } static int iconv_truncate(const char *path, off_t size) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_truncate(ic->next, newpath, size); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_truncate(ic->next, newpath, size); + free(newpath); + } + return err; } static int iconv_ftruncate(const char *path, off_t size, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_ftruncate(ic->next, newpath, size, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_ftruncate(ic->next, newpath, size, fi); + free(newpath); + } + return err; } static int iconv_utimens(const char *path, const struct timespec ts[2]) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_utimens(ic->next, newpath, ts); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_utimens(ic->next, newpath, ts); + free(newpath); + } + return err; } static int iconv_create(const char *path, mode_t mode, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_create(ic->next, newpath, mode, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_create(ic->next, newpath, mode, fi); + free(newpath); + } + return err; } static int iconv_open_file(const char *path, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_open(ic->next, newpath, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_open(ic->next, newpath, fi); + free(newpath); + } + return err; } static int iconv_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_read(ic->next, newpath, buf, size, offset, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_read(ic->next, newpath, buf, size, offset, fi); + free(newpath); + } + return err; } static int iconv_write(const char *path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) + off_t offset, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_write(ic->next, newpath, buf, size, offset, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_write(ic->next, newpath, buf, size, offset, fi); + free(newpath); + } + return err; } static int iconv_statfs(const char *path, struct statvfs *stbuf) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_statfs(ic->next, newpath, stbuf); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_statfs(ic->next, newpath, stbuf); + free(newpath); + } + return err; } static int iconv_flush(const char *path, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_flush(ic->next, newpath, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_flush(ic->next, newpath, fi); + free(newpath); + } + return err; } static int iconv_release(const char *path, struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_release(ic->next, newpath, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_release(ic->next, newpath, fi); + free(newpath); + } + return err; } static int iconv_fsync(const char *path, int isdatasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi); + free(newpath); + } + return err; } static int iconv_fsyncdir(const char *path, int isdatasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi); + free(newpath); + } + return err; } static int iconv_setxattr(const char *path, const char *name, - const char *value, size_t size, int flags) + const char *value, size_t size, int flags) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_setxattr(ic->next, newpath, name, value, size, flags); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_setxattr(ic->next, newpath, name, value, size, + flags); + free(newpath); + } + return err; } static int iconv_getxattr(const char *path, const char *name, char *value, - size_t size) + size_t size) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_getxattr(ic->next, newpath, name, value, size); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_getxattr(ic->next, newpath, name, value, size); + free(newpath); + } + return err; } static int iconv_listxattr(const char *path, char *list, size_t size) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_listxattr(ic->next, newpath, list, size); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_listxattr(ic->next, newpath, list, size); + free(newpath); + } + return err; } static int iconv_removexattr(const char *path, const char *name) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_removexattr(ic->next, newpath, name); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_removexattr(ic->next, newpath, name); + free(newpath); + } + return err; } static int iconv_lock(const char *path, struct fuse_file_info *fi, int cmd, - struct flock *lock) + struct flock *lock) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock); + free(newpath); + } + return err; } static int iconv_bmap(const char *path, size_t blocksize, uint64_t *idx) { - struct iconv *ic = iconv_get(); - char *newpath; - int err = iconv_convpath(ic, path, &newpath, 0); - if (!err) { - err = fuse_fs_bmap(ic->next, newpath, blocksize, idx); - free(newpath); - } - return err; + struct iconv *ic = iconv_get(); + char *newpath; + int err = iconv_convpath(ic, path, &newpath, 0); + if (!err) { + err = fuse_fs_bmap(ic->next, newpath, blocksize, idx); + free(newpath); + } + return err; } static void *iconv_init(struct fuse_conn_info *conn) { - struct iconv *ic = iconv_get(); - fuse_fs_init(ic->next, conn); - return ic; + struct iconv *ic = iconv_get(); + fuse_fs_init(ic->next, conn); + return ic; } static void iconv_destroy(void *data) { - struct iconv *ic = data; - fuse_fs_destroy(ic->next); - iconv_close(ic->tofs); - iconv_close(ic->fromfs); - pthread_mutex_destroy(&ic->lock); - free(ic->from_code); - free(ic->to_code); - free(ic); + struct iconv *ic = data; + fuse_fs_destroy(ic->next); + iconv_close(ic->tofs); + iconv_close(ic->fromfs); + pthread_mutex_destroy(&ic->lock); + free(ic->from_code); + free(ic->to_code); + free(ic); } static struct fuse_operations iconv_oper = { - .destroy = iconv_destroy, - .init = iconv_init, - .getattr = iconv_getattr, - .fgetattr = iconv_fgetattr, - .access = iconv_access, - .readlink = iconv_readlink, - .opendir = iconv_opendir, - .readdir = iconv_readdir, - .releasedir = iconv_releasedir, - .mknod = iconv_mknod, - .mkdir = iconv_mkdir, - .symlink = iconv_symlink, - .unlink = iconv_unlink, - .rmdir = iconv_rmdir, - .rename = iconv_rename, - .link = iconv_link, - .chmod = iconv_chmod, - .chown = iconv_chown, - .truncate = iconv_truncate, - .ftruncate = iconv_ftruncate, - .utimens = iconv_utimens, - .create = iconv_create, - .open = iconv_open_file, - .read = iconv_read, - .write = iconv_write, - .statfs = iconv_statfs, - .flush = iconv_flush, - .release = iconv_release, - .fsync = iconv_fsync, - .fsyncdir = iconv_fsyncdir, - .setxattr = iconv_setxattr, - .getxattr = iconv_getxattr, - .listxattr = iconv_listxattr, - .removexattr= iconv_removexattr, - .lock = iconv_lock, - .bmap = iconv_bmap, + .destroy = iconv_destroy, + .init = iconv_init, + .getattr = iconv_getattr, + .fgetattr = iconv_fgetattr, + .access = iconv_access, + .readlink = iconv_readlink, + .opendir = iconv_opendir, + .readdir = iconv_readdir, + .releasedir = iconv_releasedir, + .mknod = iconv_mknod, + .mkdir = iconv_mkdir, + .symlink = iconv_symlink, + .unlink = iconv_unlink, + .rmdir = iconv_rmdir, + .rename = iconv_rename, + .link = iconv_link, + .chmod = iconv_chmod, + .chown = iconv_chown, + .truncate = iconv_truncate, + .ftruncate = iconv_ftruncate, + .utimens = iconv_utimens, + .create = iconv_create, + .open = iconv_open_file, + .read = iconv_read, + .write = iconv_write, + .statfs = iconv_statfs, + .flush = iconv_flush, + .release = iconv_release, + .fsync = iconv_fsync, + .fsyncdir = iconv_fsyncdir, + .setxattr = iconv_setxattr, + .getxattr = iconv_getxattr, + .listxattr = iconv_listxattr, + .removexattr = iconv_removexattr, + .lock = iconv_lock, + .bmap = iconv_bmap, }; static struct fuse_opt iconv_opts[] = { - FUSE_OPT_KEY("-h", 0), - FUSE_OPT_KEY("--help", 0), - { "from_code=%s", offsetof(struct iconv, from_code), 0 }, - { "to_code=%s", offsetof(struct iconv, to_code), 1 }, - FUSE_OPT_END + FUSE_OPT_KEY("-h", 0), + FUSE_OPT_KEY("--help", 0), + { "from_code=%s", offsetof(struct iconv, from_code), 0 }, + { "to_code=%s", offsetof(struct iconv, to_code), 1 }, + FUSE_OPT_END }; static void iconv_help(void) { - char *old = strdup(setlocale(LC_CTYPE, "")); - char *charmap = strdup(nl_langinfo(CODESET)); - setlocale(LC_CTYPE, old); - free(old); - fprintf(stderr, + char *old = strdup(setlocale(LC_CTYPE, "")); + char *charmap = strdup(nl_langinfo(CODESET)); + setlocale(LC_CTYPE, old); + free(old); + fprintf(stderr, " -o from_code=CHARSET original encoding of file names (default: UTF-8)\n" -" -o to_code=CHARSET new encoding of the file names (default: %s)\n", - charmap); - free(charmap); +" -o to_code=CHARSET new encoding of the file names (default: %s)\n", + charmap); + free(charmap); } static int iconv_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - (void) data; (void) arg; (void) outargs; + (void) data; (void) arg; (void) outargs; - if (!key) { - iconv_help(); - return -1; - } + if (!key) { + iconv_help(); + return -1; + } - return 1; + return 1; } static struct fuse_fs *iconv_new(struct fuse_args *args, - struct fuse_fs *next[]) -{ - struct fuse_fs *fs; - struct iconv *ic; - char *old = NULL; - const char *from; - const char *to; - - ic = calloc(1, sizeof(struct iconv)); - if (ic == NULL) { - fprintf(stderr, "fuse-iconv: memory allocation failed\n"); - return NULL; - } - - if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1) - goto out_free; - - if (!next[0] || next[1]) { - fprintf(stderr, "fuse-iconv: exactly one next filesystem required\n"); - goto out_free; - } - - from = ic->from_code ? ic->from_code : "UTF-8"; - to = ic->to_code ? ic->to_code : ""; - /* FIXME: detect charset equivalence? */ - if (!to[0]) - old = strdup(setlocale(LC_CTYPE, "")); - ic->tofs = iconv_open(from, to); - if (ic->tofs == (iconv_t) -1) { - fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n", - to, from); - goto out_free; - } - ic->fromfs = iconv_open(to, from); - if (ic->tofs == (iconv_t) -1) { - fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n", - from, to); - goto out_iconv_close_to; - } - if (old) { - setlocale(LC_CTYPE, old); - free(old); - } - - ic->next = next[0]; - fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic); - if (!fs) - goto out_iconv_close_from; - - return fs; - - out_iconv_close_from: - iconv_close(ic->fromfs); - out_iconv_close_to: - iconv_close(ic->tofs); - out_free: - free(ic->from_code); - free(ic->to_code); - free(ic); - return NULL; + struct fuse_fs *next[]) +{ + struct fuse_fs *fs; + struct iconv *ic; + char *old = NULL; + const char *from; + const char *to; + + ic = calloc(1, sizeof(struct iconv)); + if (ic == NULL) { + fprintf(stderr, "fuse-iconv: memory allocation failed\n"); + return NULL; + } + + if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1) + goto out_free; + + if (!next[0] || next[1]) { + fprintf(stderr, "fuse-iconv: exactly one next filesystem required\n"); + goto out_free; + } + + from = ic->from_code ? ic->from_code : "UTF-8"; + to = ic->to_code ? ic->to_code : ""; + /* FIXME: detect charset equivalence? */ + if (!to[0]) + old = strdup(setlocale(LC_CTYPE, "")); + ic->tofs = iconv_open(from, to); + if (ic->tofs == (iconv_t) -1) { + fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n", + to, from); + goto out_free; + } + ic->fromfs = iconv_open(to, from); + if (ic->tofs == (iconv_t) -1) { + fprintf(stderr, "fuse-iconv: cannot convert from %s to %s\n", + from, to); + goto out_iconv_close_to; + } + if (old) { + setlocale(LC_CTYPE, old); + free(old); + } + + ic->next = next[0]; + fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic); + if (!fs) + goto out_iconv_close_from; + + return fs; + +out_iconv_close_from: + iconv_close(ic->fromfs); +out_iconv_close_to: + iconv_close(ic->tofs); +out_free: + free(ic->from_code); + free(ic->to_code); + free(ic); + return NULL; } FUSE_REGISTER_MODULE(iconv, iconv_new); diff --git a/lib/modules/subdir.c b/lib/modules/subdir.c index f22c023..6f7b187 100644 --- a/lib/modules/subdir.c +++ b/lib/modules/subdir.c @@ -1,9 +1,9 @@ /* - fuse subdir module: offset paths with a base directory - Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu> + fuse subdir module: offset paths with a base directory + Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ #define FUSE_USE_VERSION 26 @@ -16,647 +16,650 @@ #include <errno.h> struct subdir { - char *base; - size_t baselen; - int rellinks; - struct fuse_fs *next; + char *base; + size_t baselen; + int rellinks; + struct fuse_fs *next; }; static struct subdir *subdir_get(void) { - return fuse_get_context()->private_data; + return fuse_get_context()->private_data; } static char *subdir_addpath(struct subdir *d, const char *path) { - unsigned newlen = d->baselen + strlen(path); - char *newpath = malloc(newlen + 2); - if (newpath) { - if (path[0] == '/') - path++; - strcpy(newpath, d->base); - strcpy(newpath + d->baselen, path); - if (!newpath[0]) - strcpy(newpath, "."); - } - return newpath; + unsigned newlen = d->baselen + strlen(path); + char *newpath = malloc(newlen + 2); + if (newpath) { + if (path[0] == '/') + path++; + strcpy(newpath, d->base); + strcpy(newpath + d->baselen, path); + if (!newpath[0]) + strcpy(newpath, "."); + } + return newpath; } static int subdir_getattr(const char *path, struct stat *stbuf) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_getattr(d->next, newpath, stbuf); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_getattr(d->next, newpath, stbuf); + free(newpath); + } + return err; } static int subdir_fgetattr(const char *path, struct stat *stbuf, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_fgetattr(d->next, newpath, stbuf, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_fgetattr(d->next, newpath, stbuf, fi); + free(newpath); + } + return err; } static int subdir_access(const char *path, int mask) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_access(d->next, newpath, mask); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_access(d->next, newpath, mask); + free(newpath); + } + return err; } static int count_components(const char *p) { - int ctr; + int ctr; - for (; *p == '/'; p++); - for (ctr = 0; *p; ctr++) { - for (; *p && *p != '/'; p++); - for (; *p == '/'; p++); - } - return ctr; + for (; *p == '/'; p++); + for (ctr = 0; *p; ctr++) { + for (; *p && *p != '/'; p++); + for (; *p == '/'; p++); + } + return ctr; } static void strip_common(const char **sp, const char **tp) { - const char *s = *sp; - const char *t = *tp; - do { - for (; *s == '/'; s++); - for (; *t == '/'; t++); - *tp = t; - *sp = s; - for (; *s == *t && *s && *s != '/'; s++, t++); - } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t)); + const char *s = *sp; + const char *t = *tp; + do { + for (; *s == '/'; s++); + for (; *t == '/'; t++); + *tp = t; + *sp = s; + for (; *s == *t && *s && *s != '/'; s++, t++); + } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t)); } static void transform_symlink(struct subdir *d, const char *path, - char *buf, size_t size) + char *buf, size_t size) { - const char *l = buf; - size_t llen; - char *s; - int dotdots; - int i; + const char *l = buf; + size_t llen; + char *s; + int dotdots; + int i; - if (l[0] != '/' || d->base[0] != '/') - return; + if (l[0] != '/' || d->base[0] != '/') + return; - strip_common(&l, &path); - if (l - buf < (long) d->baselen) - return; + strip_common(&l, &path); + if (l - buf < (long) d->baselen) + return; - dotdots = count_components(path); - if (!dotdots) - return; - dotdots--; + dotdots = count_components(path); + if (!dotdots) + return; + dotdots--; - llen = strlen(l); - if (dotdots * 3 + llen + 2 > size) - return; + llen = strlen(l); + if (dotdots * 3 + llen + 2 > size) + return; - s = buf + dotdots * 3; - if (llen) - memmove(s, l, llen + 1); - else if (!dotdots) - strcpy(s, "."); - else - *s = '\0'; + s = buf + dotdots * 3; + if (llen) + memmove(s, l, llen + 1); + else if (!dotdots) + strcpy(s, "."); + else + *s = '\0'; - for (s = buf, i = 0; i < dotdots; i++, s += 3) - memcpy(s, "../", 3); + for (s = buf, i = 0; i < dotdots; i++, s += 3) + memcpy(s, "../", 3); } static int subdir_readlink(const char *path, char *buf, size_t size) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_readlink(d->next, newpath, buf, size); - if (!err && d->rellinks) - transform_symlink(d, newpath, buf, size); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_readlink(d->next, newpath, buf, size); + if (!err && d->rellinks) + transform_symlink(d, newpath, buf, size); + free(newpath); + } + return err; } static int subdir_opendir(const char *path, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_opendir(d->next, newpath, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_opendir(d->next, newpath, fi); + free(newpath); + } + return err; } static int subdir_readdir(const char *path, void *buf, - fuse_fill_dir_t filler, off_t offset, - struct fuse_file_info *fi) + fuse_fill_dir_t filler, off_t offset, + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_readdir(d->next, newpath, buf, filler, offset, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_readdir(d->next, newpath, buf, filler, offset, + fi); + free(newpath); + } + return err; } static int subdir_releasedir(const char *path, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_releasedir(d->next, newpath, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_releasedir(d->next, newpath, fi); + free(newpath); + } + return err; } static int subdir_mknod(const char *path, mode_t mode, dev_t rdev) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_mknod(d->next, newpath, mode, rdev); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_mknod(d->next, newpath, mode, rdev); + free(newpath); + } + return err; } static int subdir_mkdir(const char *path, mode_t mode) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_mkdir(d->next, newpath, mode); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_mkdir(d->next, newpath, mode); + free(newpath); + } + return err; } static int subdir_unlink(const char *path) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_unlink(d->next, newpath); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_unlink(d->next, newpath); + free(newpath); + } + return err; } static int subdir_rmdir(const char *path) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_rmdir(d->next, newpath); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_rmdir(d->next, newpath); + free(newpath); + } + return err; } static int subdir_symlink(const char *from, const char *path) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_symlink(d->next, from, newpath); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_symlink(d->next, from, newpath); + free(newpath); + } + return err; } static int subdir_rename(const char *from, const char *to) { - struct subdir *d = subdir_get(); - char *newfrom = subdir_addpath(d, from); - char *newto = subdir_addpath(d, to); - int err = -ENOMEM; - if (newfrom && newto) - err = fuse_fs_rename(d->next, newfrom, newto); - free(newfrom); - free(newto); - return err; + struct subdir *d = subdir_get(); + char *newfrom = subdir_addpath(d, from); + char *newto = subdir_addpath(d, to); + int err = -ENOMEM; + if (newfrom && newto) + err = fuse_fs_rename(d->next, newfrom, newto); + free(newfrom); + free(newto); + return err; } static int subdir_link(const char *from, const char *to) { - struct subdir *d = subdir_get(); - char *newfrom = subdir_addpath(d, from); - char *newto = subdir_addpath(d, to); - int err = -ENOMEM; - if (newfrom && newto) - err = fuse_fs_link(d->next, newfrom, newto); - free(newfrom); - free(newto); - return err; + struct subdir *d = subdir_get(); + char *newfrom = subdir_addpath(d, from); + char *newto = subdir_addpath(d, to); + int err = -ENOMEM; + if (newfrom && newto) + err = fuse_fs_link(d->next, newfrom, newto); + free(newfrom); + free(newto); + return err; } static int subdir_chmod(const char *path, mode_t mode) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_chmod(d->next, newpath, mode); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_chmod(d->next, newpath, mode); + free(newpath); + } + return err; } static int subdir_chown(const char *path, uid_t uid, gid_t gid) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_chown(d->next, newpath, uid, gid); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_chown(d->next, newpath, uid, gid); + free(newpath); + } + return err; } static int subdir_truncate(const char *path, off_t size) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_truncate(d->next, newpath, size); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_truncate(d->next, newpath, size); + free(newpath); + } + return err; } static int subdir_ftruncate(const char *path, off_t size, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_ftruncate(d->next, newpath, size, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_ftruncate(d->next, newpath, size, fi); + free(newpath); + } + return err; } static int subdir_utimens(const char *path, const struct timespec ts[2]) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_utimens(d->next, newpath, ts); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_utimens(d->next, newpath, ts); + free(newpath); + } + return err; } -static int subdir_create(const char *path, mode_t mode, struct fuse_file_info *fi) +static int subdir_create(const char *path, mode_t mode, + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_create(d->next, newpath, mode, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_create(d->next, newpath, mode, fi); + free(newpath); + } + return err; } static int subdir_open(const char *path, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_open(d->next, newpath, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_open(d->next, newpath, fi); + free(newpath); + } + return err; } static int subdir_read(const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_read(d->next, newpath, buf, size, offset, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_read(d->next, newpath, buf, size, offset, fi); + free(newpath); + } + return err; } static int subdir_write(const char *path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) + off_t offset, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_write(d->next, newpath, buf, size, offset, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_write(d->next, newpath, buf, size, offset, fi); + free(newpath); + } + return err; } static int subdir_statfs(const char *path, struct statvfs *stbuf) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_statfs(d->next, newpath, stbuf); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_statfs(d->next, newpath, stbuf); + free(newpath); + } + return err; } static int subdir_flush(const char *path, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_flush(d->next, newpath, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_flush(d->next, newpath, fi); + free(newpath); + } + return err; } static int subdir_release(const char *path, struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_release(d->next, newpath, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_release(d->next, newpath, fi); + free(newpath); + } + return err; } static int subdir_fsync(const char *path, int isdatasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_fsync(d->next, newpath, isdatasync, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_fsync(d->next, newpath, isdatasync, fi); + free(newpath); + } + return err; } static int subdir_fsyncdir(const char *path, int isdatasync, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi); + free(newpath); + } + return err; } -static int subdir_setxattr(const char *path, const char *name, const char *value, - size_t size, int flags) +static int subdir_setxattr(const char *path, const char *name, + const char *value, size_t size, int flags) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_setxattr(d->next, newpath, name, value, size, flags); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_setxattr(d->next, newpath, name, value, size, + flags); + free(newpath); + } + return err; } static int subdir_getxattr(const char *path, const char *name, char *value, - size_t size) + size_t size) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_getxattr(d->next, newpath, name, value, size); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_getxattr(d->next, newpath, name, value, size); + free(newpath); + } + return err; } static int subdir_listxattr(const char *path, char *list, size_t size) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_listxattr(d->next, newpath, list, size); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_listxattr(d->next, newpath, list, size); + free(newpath); + } + return err; } static int subdir_removexattr(const char *path, const char *name) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_removexattr(d->next, newpath, name); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_removexattr(d->next, newpath, name); + free(newpath); + } + return err; } static int subdir_lock(const char *path, struct fuse_file_info *fi, int cmd, - struct flock *lock) + struct flock *lock) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_lock(d->next, newpath, fi, cmd, lock); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_lock(d->next, newpath, fi, cmd, lock); + free(newpath); + } + return err; } static int subdir_bmap(const char *path, size_t blocksize, uint64_t *idx) { - struct subdir *d = subdir_get(); - char *newpath = subdir_addpath(d, path); - int err = -ENOMEM; - if (newpath) { - err = fuse_fs_bmap(d->next, newpath, blocksize, idx); - free(newpath); - } - return err; + struct subdir *d = subdir_get(); + char *newpath = subdir_addpath(d, path); + int err = -ENOMEM; + if (newpath) { + err = fuse_fs_bmap(d->next, newpath, blocksize, idx); + free(newpath); + } + return err; } static void *subdir_init(struct fuse_conn_info *conn) { - struct subdir *d = subdir_get(); - fuse_fs_init(d->next, conn); - return d; + struct subdir *d = subdir_get(); + fuse_fs_init(d->next, conn); + return d; } static void subdir_destroy(void *data) { - struct subdir *d = data; - fuse_fs_destroy(d->next); - free(d->base); - free(d); + struct subdir *d = data; + fuse_fs_destroy(d->next); + free(d->base); + free(d); } static struct fuse_operations subdir_oper = { - .destroy = subdir_destroy, - .init = subdir_init, - .getattr = subdir_getattr, - .fgetattr = subdir_fgetattr, - .access = subdir_access, - .readlink = subdir_readlink, - .opendir = subdir_opendir, - .readdir = subdir_readdir, - .releasedir = subdir_releasedir, - .mknod = subdir_mknod, - .mkdir = subdir_mkdir, - .symlink = subdir_symlink, - .unlink = subdir_unlink, - .rmdir = subdir_rmdir, - .rename = subdir_rename, - .link = subdir_link, - .chmod = subdir_chmod, - .chown = subdir_chown, - .truncate = subdir_truncate, - .ftruncate = subdir_ftruncate, - .utimens = subdir_utimens, - .create = subdir_create, - .open = subdir_open, - .read = subdir_read, - .write = subdir_write, - .statfs = subdir_statfs, - .flush = subdir_flush, - .release = subdir_release, - .fsync = subdir_fsync, - .fsyncdir = subdir_fsyncdir, - .setxattr = subdir_setxattr, - .getxattr = subdir_getxattr, - .listxattr = subdir_listxattr, - .removexattr= subdir_removexattr, - .lock = subdir_lock, - .bmap = subdir_bmap, + .destroy = subdir_destroy, + .init = subdir_init, + .getattr = subdir_getattr, + .fgetattr = subdir_fgetattr, + .access = subdir_access, + .readlink = subdir_readlink, + .opendir = subdir_opendir, + .readdir = subdir_readdir, + .releasedir = subdir_releasedir, + .mknod = subdir_mknod, + .mkdir = subdir_mkdir, + .symlink = subdir_symlink, + .unlink = subdir_unlink, + .rmdir = subdir_rmdir, + .rename = subdir_rename, + .link = subdir_link, + .chmod = subdir_chmod, + .chown = subdir_chown, + .truncate = subdir_truncate, + .ftruncate = subdir_ftruncate, + .utimens = subdir_utimens, + .create = subdir_create, + .open = subdir_open, + .read = subdir_read, + .write = subdir_write, + .statfs = subdir_statfs, + .flush = subdir_flush, + .release = subdir_release, + .fsync = subdir_fsync, + .fsyncdir = subdir_fsyncdir, + .setxattr = subdir_setxattr, + .getxattr = subdir_getxattr, + .listxattr = subdir_listxattr, + .removexattr = subdir_removexattr, + .lock = subdir_lock, + .bmap = subdir_bmap, }; static struct fuse_opt subdir_opts[] = { - FUSE_OPT_KEY("-h", 0), - FUSE_OPT_KEY("--help", 0), - { "subdir=%s", offsetof(struct subdir, base), 0 }, - { "rellinks", offsetof(struct subdir, rellinks), 1 }, - { "norellinks", offsetof(struct subdir, rellinks), 0 }, - FUSE_OPT_END + FUSE_OPT_KEY("-h", 0), + FUSE_OPT_KEY("--help", 0), + { "subdir=%s", offsetof(struct subdir, base), 0 }, + { "rellinks", offsetof(struct subdir, rellinks), 1 }, + { "norellinks", offsetof(struct subdir, rellinks), 0 }, + FUSE_OPT_END }; static void subdir_help(void) { - fprintf(stderr, -" -o subdir=DIR prepend this directory to all paths (mandatory)\n" -" -o [no]rellinks transform absolute symlinks to relative\n"); + fprintf(stderr, +" -o subdir=DIR prepend this directory to all paths (mandatory)\n" +" -o [no]rellinks transform absolute symlinks to relative\n"); } static int subdir_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - (void) data; (void) arg; (void) outargs; + (void) data; (void) arg; (void) outargs; - if (!key) { - subdir_help(); - return -1; - } + if (!key) { + subdir_help(); + return -1; + } - return 1; + return 1; } static struct fuse_fs *subdir_new(struct fuse_args *args, - struct fuse_fs *next[]) -{ - struct fuse_fs *fs; - struct subdir *d; - - d = calloc(1, sizeof(struct subdir)); - if (d == NULL) { - fprintf(stderr, "fuse-subdir: memory allocation failed\n"); - return NULL; - } - - if (fuse_opt_parse(args, d, subdir_opts, subdir_opt_proc) == -1) - goto out_free; - - if (!next[0] || next[1]) { - fprintf(stderr, "fuse-subdir: exactly one next filesystem required\n"); - goto out_free; - } - - if (!d->base) { - fprintf(stderr, "fuse-subdir: missing 'subdir' option\n"); - goto out_free; - } - - if (d->base[0] && d->base[strlen(d->base)-1] != '/') { - char *tmp = realloc(d->base, strlen(d->base) + 2); - if (!tmp) { - fprintf(stderr, "fuse-subdir: memory allocation failed\n"); - goto out_free; - } - d->base = tmp; - strcat(d->base, "/"); - } - d->baselen = strlen(d->base); - d->next = next[0]; - fs = fuse_fs_new(&subdir_oper, sizeof(subdir_oper), d); - if (!fs) - goto out_free; - return fs; - - out_free: - free(d->base); - free(d); - return NULL; + struct fuse_fs *next[]) +{ + struct fuse_fs *fs; + struct subdir *d; + + d = calloc(1, sizeof(struct subdir)); + if (d == NULL) { + fprintf(stderr, "fuse-subdir: memory allocation failed\n"); + return NULL; + } + + if (fuse_opt_parse(args, d, subdir_opts, subdir_opt_proc) == -1) + goto out_free; + + if (!next[0] || next[1]) { + fprintf(stderr, "fuse-subdir: exactly one next filesystem required\n"); + goto out_free; + } + + if (!d->base) { + fprintf(stderr, "fuse-subdir: missing 'subdir' option\n"); + goto out_free; + } + + if (d->base[0] && d->base[strlen(d->base)-1] != '/') { + char *tmp = realloc(d->base, strlen(d->base) + 2); + if (!tmp) { + fprintf(stderr, "fuse-subdir: memory allocation failed\n"); + goto out_free; + } + d->base = tmp; + strcat(d->base, "/"); + } + d->baselen = strlen(d->base); + d->next = next[0]; + fs = fuse_fs_new(&subdir_oper, sizeof(subdir_oper), d); + if (!fs) + goto out_free; + return fs; + +out_free: + free(d->base); + free(d); + return NULL; } FUSE_REGISTER_MODULE(subdir, subdir_new); diff --git a/lib/mount.c b/lib/mount.c index 8a5c5ab..14fbfb5 100644 --- a/lib/mount.c +++ b/lib/mount.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "config.h" @@ -25,8 +25,8 @@ #include <sys/wait.h> #include <sys/mount.h> -#define FUSERMOUNT_PROG "fusermount" -#define FUSE_COMMFD_ENV "_FUSE_COMMFD" +#define FUSERMOUNT_PROG "fusermount" +#define FUSE_COMMFD_ENV "_FUSE_COMMFD" #ifndef HAVE_FORK #define fork() vfork() @@ -37,551 +37,555 @@ #endif enum { - KEY_KERN_FLAG, - KEY_KERN_OPT, - KEY_FUSERMOUNT_OPT, - KEY_SUBTYPE_OPT, - KEY_MTAB_OPT, - KEY_ALLOW_ROOT, - KEY_RO, - KEY_HELP, - KEY_VERSION, + KEY_KERN_FLAG, + KEY_KERN_OPT, + KEY_FUSERMOUNT_OPT, + KEY_SUBTYPE_OPT, + KEY_MTAB_OPT, + KEY_ALLOW_ROOT, + KEY_RO, + KEY_HELP, + KEY_VERSION, }; struct mount_opts { - int allow_other; - int allow_root; - int ishelp; - int flags; - int nonempty; - int blkdev; - char *fsname; - char *subtype; - char *subtype_opt; - char *mtab_opts; - char *fusermount_opts; - char *kernel_opts; + int allow_other; + int allow_root; + int ishelp; + int flags; + int nonempty; + int blkdev; + char *fsname; + char *subtype; + char *subtype_opt; + char *mtab_opts; + char *fusermount_opts; + char *kernel_opts; }; #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } static const struct fuse_opt fuse_mount_opts[] = { - FUSE_MOUNT_OPT("allow_other", allow_other), - FUSE_MOUNT_OPT("allow_root", allow_root), - FUSE_MOUNT_OPT("nonempty", nonempty), - FUSE_MOUNT_OPT("blkdev", blkdev), - FUSE_MOUNT_OPT("fsname=%s", fsname), - FUSE_MOUNT_OPT("subtype=%s", subtype), - FUSE_OPT_KEY("allow_other", KEY_KERN_OPT), - FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), - FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT), - FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT), - FUSE_OPT_KEY("large_read", KEY_KERN_OPT), - FUSE_OPT_KEY("blksize=", KEY_KERN_OPT), - FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT), - FUSE_OPT_KEY("max_read=", KEY_KERN_OPT), - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), - FUSE_OPT_KEY("user=", KEY_MTAB_OPT), - FUSE_OPT_KEY("-r", KEY_RO), - FUSE_OPT_KEY("ro", KEY_KERN_FLAG), - FUSE_OPT_KEY("rw", KEY_KERN_FLAG), - FUSE_OPT_KEY("suid", KEY_KERN_FLAG), - FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG), - FUSE_OPT_KEY("dev", KEY_KERN_FLAG), - FUSE_OPT_KEY("nodev", KEY_KERN_FLAG), - FUSE_OPT_KEY("exec", KEY_KERN_FLAG), - FUSE_OPT_KEY("noexec", KEY_KERN_FLAG), - FUSE_OPT_KEY("async", KEY_KERN_FLAG), - FUSE_OPT_KEY("sync", KEY_KERN_FLAG), - FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), - FUSE_OPT_KEY("atime", KEY_KERN_FLAG), - FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_END + FUSE_MOUNT_OPT("allow_other", allow_other), + FUSE_MOUNT_OPT("allow_root", allow_root), + FUSE_MOUNT_OPT("nonempty", nonempty), + FUSE_MOUNT_OPT("blkdev", blkdev), + FUSE_MOUNT_OPT("fsname=%s", fsname), + FUSE_MOUNT_OPT("subtype=%s", subtype), + FUSE_OPT_KEY("allow_other", KEY_KERN_OPT), + FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), + FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT), + FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT), + FUSE_OPT_KEY("large_read", KEY_KERN_OPT), + FUSE_OPT_KEY("blksize=", KEY_KERN_OPT), + FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT), + FUSE_OPT_KEY("max_read=", KEY_KERN_OPT), + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("user=", KEY_MTAB_OPT), + FUSE_OPT_KEY("-r", KEY_RO), + FUSE_OPT_KEY("ro", KEY_KERN_FLAG), + FUSE_OPT_KEY("rw", KEY_KERN_FLAG), + FUSE_OPT_KEY("suid", KEY_KERN_FLAG), + FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG), + FUSE_OPT_KEY("dev", KEY_KERN_FLAG), + FUSE_OPT_KEY("nodev", KEY_KERN_FLAG), + FUSE_OPT_KEY("exec", KEY_KERN_FLAG), + FUSE_OPT_KEY("noexec", KEY_KERN_FLAG), + FUSE_OPT_KEY("async", KEY_KERN_FLAG), + FUSE_OPT_KEY("sync", KEY_KERN_FLAG), + FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), + FUSE_OPT_KEY("atime", KEY_KERN_FLAG), + FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_END }; static void mount_help(void) { - fprintf(stderr, - " -o allow_other allow access to other users\n" - " -o allow_root allow access to root\n" - " -o nonempty allow mounts over non-empty file/dir\n" - " -o default_permissions enable permission checking by kernel\n" - " -o fsname=NAME set filesystem name\n" - " -o subtype=NAME set filesystem type\n" - " -o large_read issue large read requests (2.4 only)\n" - " -o max_read=N set maximum size of read requests\n" - "\n" - ); + fprintf(stderr, +" -o allow_other allow access to other users\n" +" -o allow_root allow access to root\n" +" -o nonempty allow mounts over non-empty file/dir\n" +" -o default_permissions enable permission checking by kernel\n" +" -o fsname=NAME set filesystem name\n" +" -o subtype=NAME set filesystem type\n" +" -o large_read issue large read requests (2.4 only)\n" +" -o max_read=N set maximum size of read requests\n" +"\n"); } static void exec_fusermount(const char *argv[]) { - execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv); - execvp(FUSERMOUNT_PROG, (char **) argv); + execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv); + execvp(FUSERMOUNT_PROG, (char **) argv); } static void mount_version(void) { - int pid = fork(); - if (!pid) { - const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL }; - exec_fusermount(argv); - _exit(1); - } else if (pid != -1) - waitpid(pid, NULL, 0); + int pid = fork(); + if (!pid) { + const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL }; + exec_fusermount(argv); + _exit(1); + } else if (pid != -1) + waitpid(pid, NULL, 0); } struct mount_flags { - const char *opt; - unsigned long flag; - int on; + const char *opt; + unsigned long flag; + int on; }; static struct mount_flags mount_flags[] = { - {"rw", MS_RDONLY, 0}, - {"ro", MS_RDONLY, 1}, - {"suid", MS_NOSUID, 0}, - {"nosuid", MS_NOSUID, 1}, - {"dev", MS_NODEV, 0}, - {"nodev", MS_NODEV, 1}, - {"exec", MS_NOEXEC, 0}, - {"noexec", MS_NOEXEC, 1}, - {"async", MS_SYNCHRONOUS, 0}, - {"sync", MS_SYNCHRONOUS, 1}, - {"atime", MS_NOATIME, 0}, - {"noatime", MS_NOATIME, 1}, - {"dirsync", MS_DIRSYNC, 1}, - {NULL, 0, 0} + {"rw", MS_RDONLY, 0}, + {"ro", MS_RDONLY, 1}, + {"suid", MS_NOSUID, 0}, + {"nosuid", MS_NOSUID, 1}, + {"dev", MS_NODEV, 0}, + {"nodev", MS_NODEV, 1}, + {"exec", MS_NOEXEC, 0}, + {"noexec", MS_NOEXEC, 1}, + {"async", MS_SYNCHRONOUS, 0}, + {"sync", MS_SYNCHRONOUS, 1}, + {"atime", MS_NOATIME, 0}, + {"noatime", MS_NOATIME, 1}, + {"dirsync", MS_DIRSYNC, 1}, + {NULL, 0, 0} }; static void set_mount_flag(const char *s, int *flags) { - int i; - - for (i = 0; mount_flags[i].opt != NULL; i++) { - const char *opt = mount_flags[i].opt; - if (strcmp(opt, s) == 0) { - if (mount_flags[i].on) - *flags |= mount_flags[i].flag; - else - *flags &= ~mount_flags[i].flag; - return; - } - } - fprintf(stderr, "fuse: internal error, can't find mount flag\n"); - abort(); + int i; + + for (i = 0; mount_flags[i].opt != NULL; i++) { + const char *opt = mount_flags[i].opt; + if (strcmp(opt, s) == 0) { + if (mount_flags[i].on) + *flags |= mount_flags[i].flag; + else + *flags &= ~mount_flags[i].flag; + return; + } + } + fprintf(stderr, "fuse: internal error, can't find mount flag\n"); + abort(); } static int fuse_mount_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - struct mount_opts *mo = data; - - switch (key) { - case KEY_ALLOW_ROOT: - if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || - fuse_opt_add_arg(outargs, "-oallow_root") == -1) - return -1; - return 0; - - case KEY_RO: - arg = "ro"; - /* fall through */ - case KEY_KERN_FLAG: - set_mount_flag(arg, &mo->flags); - return 0; - - case KEY_KERN_OPT: - return fuse_opt_add_opt(&mo->kernel_opts, arg); - - case KEY_FUSERMOUNT_OPT: - return fuse_opt_add_opt(&mo->fusermount_opts, arg); - - case KEY_SUBTYPE_OPT: - return fuse_opt_add_opt(&mo->subtype_opt, arg); - - case KEY_MTAB_OPT: - return fuse_opt_add_opt(&mo->mtab_opts, arg); - - case KEY_HELP: - mount_help(); - mo->ishelp = 1; - break; - - case KEY_VERSION: - mount_version(); - mo->ishelp = 1; - break; - } - return 1; + struct mount_opts *mo = data; + + switch (key) { + case KEY_ALLOW_ROOT: + if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || + fuse_opt_add_arg(outargs, "-oallow_root") == -1) + return -1; + return 0; + + case KEY_RO: + arg = "ro"; + /* fall through */ + case KEY_KERN_FLAG: + set_mount_flag(arg, &mo->flags); + return 0; + + case KEY_KERN_OPT: + return fuse_opt_add_opt(&mo->kernel_opts, arg); + + case KEY_FUSERMOUNT_OPT: + return fuse_opt_add_opt(&mo->fusermount_opts, arg); + + case KEY_SUBTYPE_OPT: + return fuse_opt_add_opt(&mo->subtype_opt, arg); + + case KEY_MTAB_OPT: + return fuse_opt_add_opt(&mo->mtab_opts, arg); + + case KEY_HELP: + mount_help(); + mo->ishelp = 1; + break; + + case KEY_VERSION: + mount_version(); + mo->ishelp = 1; + break; + } + return 1; } /* return value: - * >= 0 => fd - * -1 => error + * >= 0 => fd + * -1 => error */ static int receive_fd(int fd) { - struct msghdr msg; - struct iovec iov; - char buf[1]; - int rv; - size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; - struct cmsghdr *cmsg; - - iov.iov_base = buf; - iov.iov_len = 1; - - msg.msg_name = 0; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - /* old BSD implementations should use msg_accrights instead of - * msg_control; the interface is different. */ - msg.msg_control = ccmsg; - msg.msg_controllen = sizeof(ccmsg); - - while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); - if (rv == -1) { - perror("recvmsg"); - return -1; - } - if(!rv) { - /* EOF */ - return -1; - } - - cmsg = CMSG_FIRSTHDR(&msg); - if (!cmsg->cmsg_type == SCM_RIGHTS) { - fprintf(stderr, "got control message of unknown type %d\n", - cmsg->cmsg_type); - return -1; - } - return *(int*)CMSG_DATA(cmsg); + struct msghdr msg; + struct iovec iov; + char buf[1]; + int rv; + size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; + struct cmsghdr *cmsg; + + iov.iov_base = buf; + iov.iov_len = 1; + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + /* old BSD implementations should use msg_accrights instead of + * msg_control; the interface is different. */ + msg.msg_control = ccmsg; + msg.msg_controllen = sizeof(ccmsg); + + while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); + if (rv == -1) { + perror("recvmsg"); + return -1; + } + if(!rv) { + /* EOF */ + return -1; + } + + cmsg = CMSG_FIRSTHDR(&msg); + if (!cmsg->cmsg_type == SCM_RIGHTS) { + fprintf(stderr, "got control message of unknown type %d\n", + cmsg->cmsg_type); + return -1; + } + return *(int*)CMSG_DATA(cmsg); } void fuse_kern_unmount(const char *mountpoint, int fd) { - int res; - int pid; - - if (!mountpoint) - return; - - if (fd != -1) { - struct pollfd pfd; - - pfd.fd = fd; - pfd.events = 0; - res = poll(&pfd, 1, 0); - /* If file poll returns POLLERR on the device file descriptor, - then the filesystem is already unmounted */ - if (res == 1 && (pfd.revents & POLLERR)) - return; - - /* Need to close file descriptor, otherwise synchronous umount - would recurse into filesystem, and deadlock */ - close(fd); - } - - if (geteuid() == 0) { - fuse_mnt_umount("fuse", mountpoint, 1); - return; - } - - res = umount2(mountpoint, 2); - if (res == 0) - return; - - pid = fork(); - if(pid == -1) - return; - - if(pid == 0) { - const char *argv[] = - { FUSERMOUNT_PROG, "-u", "-q", "-z", "--", mountpoint, NULL }; - - exec_fusermount(argv); - _exit(1); - } - waitpid(pid, NULL, 0); + int res; + int pid; + + if (!mountpoint) + return; + + if (fd != -1) { + struct pollfd pfd; + + pfd.fd = fd; + pfd.events = 0; + res = poll(&pfd, 1, 0); + /* If file poll returns POLLERR on the device file descriptor, + then the filesystem is already unmounted */ + if (res == 1 && (pfd.revents & POLLERR)) + return; + + /* Need to close file descriptor, otherwise synchronous umount + would recurse into filesystem, and deadlock */ + close(fd); + } + + if (geteuid() == 0) { + fuse_mnt_umount("fuse", mountpoint, 1); + return; + } + + res = umount2(mountpoint, 2); + if (res == 0) + return; + + pid = fork(); + if(pid == -1) + return; + + if(pid == 0) { + const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z", + "--", mountpoint, NULL }; + + exec_fusermount(argv); + _exit(1); + } + waitpid(pid, NULL, 0); } void fuse_unmount_compat22(const char *mountpoint) { - fuse_kern_unmount(mountpoint, -1); + fuse_kern_unmount(mountpoint, -1); } static int fuse_mount_fusermount(const char *mountpoint, const char *opts, - int quiet) + int quiet) { - int fds[2], pid; - int res; - int rv; - - if (!mountpoint) { - fprintf(stderr, "fuse: missing mountpoint\n"); - return -1; - } - - res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); - if(res == -1) { - perror("fuse: socketpair() failed"); - return -1; - } - - pid = fork(); - if(pid == -1) { - perror("fuse: fork() failed"); - close(fds[0]); - close(fds[1]); - return -1; - } - - if(pid == 0) { - char env[10]; - const char *argv[32]; - int a = 0; - - if (quiet) { - int fd = open("/dev/null", O_RDONLY); - dup2(fd, 1); - dup2(fd, 2); - } - - argv[a++] = FUSERMOUNT_PROG; - if (opts) { - argv[a++] = "-o"; - argv[a++] = opts; - } - argv[a++] = "--"; - argv[a++] = mountpoint; - argv[a++] = NULL; - - close(fds[1]); - fcntl(fds[0], F_SETFD, 0); - snprintf(env, sizeof(env), "%i", fds[0]); - setenv(FUSE_COMMFD_ENV, env, 1); - exec_fusermount(argv); - perror("fuse: failed to exec fusermount"); - _exit(1); - } - - close(fds[0]); - rv = receive_fd(fds[1]); - close(fds[1]); - waitpid(pid, NULL, 0); /* bury zombie */ - - return rv; + int fds[2], pid; + int res; + int rv; + + if (!mountpoint) { + fprintf(stderr, "fuse: missing mountpoint\n"); + return -1; + } + + res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); + if(res == -1) { + perror("fuse: socketpair() failed"); + return -1; + } + + pid = fork(); + if(pid == -1) { + perror("fuse: fork() failed"); + close(fds[0]); + close(fds[1]); + return -1; + } + + if(pid == 0) { + char env[10]; + const char *argv[32]; + int a = 0; + + if (quiet) { + int fd = open("/dev/null", O_RDONLY); + dup2(fd, 1); + dup2(fd, 2); + } + + argv[a++] = FUSERMOUNT_PROG; + if (opts) { + argv[a++] = "-o"; + argv[a++] = opts; + } + argv[a++] = "--"; + argv[a++] = mountpoint; + argv[a++] = NULL; + + close(fds[1]); + fcntl(fds[0], F_SETFD, 0); + snprintf(env, sizeof(env), "%i", fds[0]); + setenv(FUSE_COMMFD_ENV, env, 1); + exec_fusermount(argv); + perror("fuse: failed to exec fusermount"); + _exit(1); + } + + close(fds[0]); + rv = receive_fd(fds[1]); + close(fds[1]); + waitpid(pid, NULL, 0); /* bury zombie */ + + return rv; } int fuse_mount_compat22(const char *mountpoint, const char *opts) { - return fuse_mount_fusermount(mountpoint, opts, 0); + return fuse_mount_fusermount(mountpoint, opts, 0); } static int fuse_mount_sys(const char *mnt, struct mount_opts *mo, - const char *mnt_opts) + const char *mnt_opts) { - char tmp[128]; - const char *devname = "/dev/fuse"; - char *source = NULL; - char *type = NULL; - struct stat stbuf; - int fd; - int res; - - if (!mnt) { - fprintf(stderr, "fuse: missing mountpoint\n"); - return -1; - } - - res = lstat(mnt, &stbuf); - if (res == -1) { - fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n", - mnt, strerror(errno)); - return -1; - } - - if (!mo->nonempty) { - res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, stbuf.st_size); - if (res == -1) - return -1; - } - - fd = open(devname, O_RDWR); - if (fd == -1) { - if (errno == ENODEV || errno == ENOENT) - fprintf(stderr, - "fuse: device not found, try 'modprobe fuse' first\n"); - else - fprintf(stderr, "fuse: failed to open %s: %s\n", devname, - strerror(errno)); - return -1; - } - - snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd, - stbuf.st_mode & S_IFMT, getuid(), getgid()); - - res = fuse_opt_add_opt(&mo->kernel_opts, tmp); - if (res == -1) - goto out_close; - - source = malloc((mo->fsname ? strlen(mo->fsname) : 0) + - (mo->subtype ? strlen(mo->subtype) : 0) + - strlen(devname) + 32); - - type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32); - if (!type || !source) { - fprintf(stderr, "fuse: failed to allocate memory\n"); - goto out_close; - } - - strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); - if (mo->subtype) { - strcat(type, "."); - strcat(type, mo->subtype); - } - strcpy(source, - mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname)); - - res = mount(source, mnt, type, mo->flags, mo->kernel_opts); - if (res == -1 && errno == ENODEV && mo->subtype) { - /* Probably missing subtype support */ - strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); - if (mo->fsname) { - if (!mo->blkdev) - sprintf(source, "%s#%s", mo->subtype, mo->fsname); - } else { - strcpy(source, type); - } - res = mount(source, mnt, type, mo->flags, mo->kernel_opts); - } - if (res == -1) { - /* - * Maybe kernel doesn't support unprivileged mounts, in this - * case try falling back to fusermount - */ - if (errno == EPERM) { - res = -2; - } else { - int errno_save = errno; - if (mo->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) - fprintf(stderr, "fuse: 'fuseblk' support missing\n"); - else - fprintf(stderr, "fuse: mount failed: %s\n", - strerror(errno_save)); - } - - goto out_close; - } - - if (geteuid() == 0) { - char *newmnt = fuse_mnt_resolve_path("fuse", mnt); - res = -1; - if (!newmnt) - goto out_umount; - - res = fuse_mnt_add_mount("fuse", source, newmnt, type, mnt_opts); - free(newmnt); - if (res == -1) - goto out_umount; - } - - return fd; - - out_umount: - umount2(mnt, 2); /* lazy umount */ - out_close: - free(type); - free(source); - close(fd); - return res; + char tmp[128]; + const char *devname = "/dev/fuse"; + char *source = NULL; + char *type = NULL; + struct stat stbuf; + int fd; + int res; + + if (!mnt) { + fprintf(stderr, "fuse: missing mountpoint\n"); + return -1; + } + + res = lstat(mnt, &stbuf); + if (res == -1) { + fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n", + mnt, strerror(errno)); + return -1; + } + + if (!mo->nonempty) { + res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, + stbuf.st_size); + if (res == -1) + return -1; + } + + fd = open(devname, O_RDWR); + if (fd == -1) { + if (errno == ENODEV || errno == ENOENT) + fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n"); + else + fprintf(stderr, "fuse: failed to open %s: %s\n", + devname, strerror(errno)); + return -1; + } + + snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", + fd, stbuf.st_mode & S_IFMT, getuid(), getgid()); + + res = fuse_opt_add_opt(&mo->kernel_opts, tmp); + if (res == -1) + goto out_close; + + source = malloc((mo->fsname ? strlen(mo->fsname) : 0) + + (mo->subtype ? strlen(mo->subtype) : 0) + + strlen(devname) + 32); + + type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32); + if (!type || !source) { + fprintf(stderr, "fuse: failed to allocate memory\n"); + goto out_close; + } + + strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); + if (mo->subtype) { + strcat(type, "."); + strcat(type, mo->subtype); + } + strcpy(source, + mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname)); + + res = mount(source, mnt, type, mo->flags, mo->kernel_opts); + if (res == -1 && errno == ENODEV && mo->subtype) { + /* Probably missing subtype support */ + strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); + if (mo->fsname) { + if (!mo->blkdev) + sprintf(source, "%s#%s", mo->subtype, + mo->fsname); + } else { + strcpy(source, type); + } + res = mount(source, mnt, type, mo->flags, mo->kernel_opts); + } + if (res == -1) { + /* + * Maybe kernel doesn't support unprivileged mounts, in this + * case try falling back to fusermount + */ + if (errno == EPERM) { + res = -2; + } else { + int errno_save = errno; + if (mo->blkdev && errno == ENODEV && + !fuse_mnt_check_fuseblk()) + fprintf(stderr, + "fuse: 'fuseblk' support missing\n"); + else + fprintf(stderr, "fuse: mount failed: %s\n", + strerror(errno_save)); + } + + goto out_close; + } + + if (geteuid() == 0) { + char *newmnt = fuse_mnt_resolve_path("fuse", mnt); + res = -1; + if (!newmnt) + goto out_umount; + + res = fuse_mnt_add_mount("fuse", source, newmnt, type, + mnt_opts); + free(newmnt); + if (res == -1) + goto out_umount; + } + + return fd; + +out_umount: + umount2(mnt, 2); /* lazy umount */ +out_close: + free(type); + free(source); + close(fd); + return res; } static int get_mnt_flag_opts(char **mnt_optsp, int flags) { - int i; + int i; - if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) - return -1; + if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) + return -1; - for (i = 0; mount_flags[i].opt != NULL; i++) { - if (mount_flags[i].on && (flags & mount_flags[i].flag) && - fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) - return -1; - } - return 0; + for (i = 0; mount_flags[i].opt != NULL; i++) { + if (mount_flags[i].on && (flags & mount_flags[i].flag) && + fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) + return -1; + } + return 0; } int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) { - struct mount_opts mo; - int res = -1; - char *mnt_opts = NULL; - - memset(&mo, 0, sizeof(mo)); - mo.flags = MS_NOSUID | MS_NODEV; - - if (args && - fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) - return -1; - - if (mo.allow_other && mo.allow_root) { - fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); - goto out; - } - res = 0; - if (mo.ishelp) - goto out; - - res = -1; - if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) - goto out; - if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) - goto out; - if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) - goto out; - - res = fuse_mount_sys(mountpoint, &mo, mnt_opts); - if (res == -2) { - if (mo.fusermount_opts && - fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1) - goto out; - - if (mo.subtype) { - char *tmp_opts = NULL; - - res = -1; - if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || - fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) { - free(tmp_opts); - goto out; - } - - res = fuse_mount_fusermount(mountpoint, tmp_opts, 1); - free(tmp_opts); - if (res == -1) - res = fuse_mount_fusermount(mountpoint, mnt_opts, 0); - } else { - res = fuse_mount_fusermount(mountpoint, mnt_opts, 0); - } - } - out: - free(mnt_opts); - free(mo.fsname); - free(mo.subtype); - free(mo.fusermount_opts); - free(mo.subtype_opt); - free(mo.kernel_opts); - free(mo.mtab_opts); - return res; + struct mount_opts mo; + int res = -1; + char *mnt_opts = NULL; + + memset(&mo, 0, sizeof(mo)); + mo.flags = MS_NOSUID | MS_NODEV; + + if (args && + fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) + return -1; + + if (mo.allow_other && mo.allow_root) { + fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); + goto out; + } + res = 0; + if (mo.ishelp) + goto out; + + res = -1; + if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) + goto out; + if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1) + goto out; + if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1) + goto out; + + res = fuse_mount_sys(mountpoint, &mo, mnt_opts); + if (res == -2) { + if (mo.fusermount_opts && + fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1) + goto out; + + if (mo.subtype) { + char *tmp_opts = NULL; + + res = -1; + if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || + fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) { + free(tmp_opts); + goto out; + } + + res = fuse_mount_fusermount(mountpoint, tmp_opts, 1); + free(tmp_opts); + if (res == -1) + res = fuse_mount_fusermount(mountpoint, + mnt_opts, 0); + } else { + res = fuse_mount_fusermount(mountpoint, mnt_opts, 0); + } + } +out: + free(mnt_opts); + free(mo.fsname); + free(mo.subtype); + free(mo.fusermount_opts); + free(mo.subtype_opt); + free(mo.kernel_opts); + free(mo.mtab_opts); + return res; } FUSE_SYMVER(".symver fuse_mount_compat22,fuse_mount@FUSE_2.2"); diff --git a/lib/mount_bsd.c b/lib/mount_bsd.c index 5197464..fb4f12a 100644 --- a/lib/mount_bsd.c +++ b/lib/mount_bsd.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2005-2006 Csaba Henk <csaba.henk@creo.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2005-2006 Csaba Henk <csaba.henk@creo.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "fuse_i.h" @@ -22,343 +22,349 @@ #include <string.h> #include <paths.h> -#define FUSERMOUNT_PROG "mount_fusefs" -#define FUSE_DEV_TRUNK "/dev/fuse" +#define FUSERMOUNT_PROG "mount_fusefs" +#define FUSE_DEV_TRUNK "/dev/fuse" enum { - KEY_ALLOW_ROOT, - KEY_RO, - KEY_HELP, - KEY_VERSION, - KEY_KERN + KEY_ALLOW_ROOT, + KEY_RO, + KEY_HELP, + KEY_VERSION, + KEY_KERN }; struct mount_opts { - int allow_other; - int allow_root; - int ishelp; - char *kernel_opts; + int allow_other; + int allow_root; + int ishelp; + char *kernel_opts; }; static const struct fuse_opt fuse_mount_opts[] = { - { "allow_other", offsetof(struct mount_opts, allow_other), 1 }, - { "allow_root", offsetof(struct mount_opts, allow_root), 1 }, - FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), - FUSE_OPT_KEY("-r", KEY_RO), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - /* standard FreeBSD mount options */ - FUSE_OPT_KEY("dev", KEY_KERN), - FUSE_OPT_KEY("async", KEY_KERN), - FUSE_OPT_KEY("atime", KEY_KERN), - FUSE_OPT_KEY("dev", KEY_KERN), - FUSE_OPT_KEY("exec", KEY_KERN), - FUSE_OPT_KEY("suid", KEY_KERN), - FUSE_OPT_KEY("symfollow", KEY_KERN), - FUSE_OPT_KEY("rdonly", KEY_KERN), - FUSE_OPT_KEY("sync", KEY_KERN), - FUSE_OPT_KEY("union", KEY_KERN), - FUSE_OPT_KEY("userquota", KEY_KERN), - FUSE_OPT_KEY("groupquota", KEY_KERN), - FUSE_OPT_KEY("clusterr", KEY_KERN), - FUSE_OPT_KEY("clusterw", KEY_KERN), - FUSE_OPT_KEY("suiddir", KEY_KERN), - FUSE_OPT_KEY("snapshot", KEY_KERN), - FUSE_OPT_KEY("multilabel", KEY_KERN), - FUSE_OPT_KEY("acls", KEY_KERN), - FUSE_OPT_KEY("force", KEY_KERN), - FUSE_OPT_KEY("update", KEY_KERN), - FUSE_OPT_KEY("ro", KEY_KERN), - FUSE_OPT_KEY("rw", KEY_KERN), - FUSE_OPT_KEY("auto", KEY_KERN), - /* options supported under both Linux and FBSD */ - FUSE_OPT_KEY("allow_other", KEY_KERN), - FUSE_OPT_KEY("default_permissions", KEY_KERN), - /* FBSD FUSE specific mount options */ - FUSE_OPT_KEY("private", KEY_KERN), - FUSE_OPT_KEY("neglect_shares", KEY_KERN), - FUSE_OPT_KEY("push_symlinks_in", KEY_KERN), - /* stock FBSD mountopt parsing routine lets anything be negated... */ - FUSE_OPT_KEY("nodev", KEY_KERN), - FUSE_OPT_KEY("noasync", KEY_KERN), - FUSE_OPT_KEY("noatime", KEY_KERN), - FUSE_OPT_KEY("nodev", KEY_KERN), - FUSE_OPT_KEY("noexec", KEY_KERN), - FUSE_OPT_KEY("nosuid", KEY_KERN), - FUSE_OPT_KEY("nosymfollow", KEY_KERN), - FUSE_OPT_KEY("nordonly", KEY_KERN), - FUSE_OPT_KEY("nosync", KEY_KERN), - FUSE_OPT_KEY("nounion", KEY_KERN), - FUSE_OPT_KEY("nouserquota", KEY_KERN), - FUSE_OPT_KEY("nogroupquota", KEY_KERN), - FUSE_OPT_KEY("noclusterr", KEY_KERN), - FUSE_OPT_KEY("noclusterw", KEY_KERN), - FUSE_OPT_KEY("nosuiddir", KEY_KERN), - FUSE_OPT_KEY("nosnapshot", KEY_KERN), - FUSE_OPT_KEY("nomultilabel", KEY_KERN), - FUSE_OPT_KEY("noacls", KEY_KERN), - FUSE_OPT_KEY("noforce", KEY_KERN), - FUSE_OPT_KEY("noupdate", KEY_KERN), - FUSE_OPT_KEY("noro", KEY_KERN), - FUSE_OPT_KEY("norw", KEY_KERN), - FUSE_OPT_KEY("noauto", KEY_KERN), - FUSE_OPT_KEY("noallow_other", KEY_KERN), - FUSE_OPT_KEY("nodefault_permissions", KEY_KERN), - FUSE_OPT_KEY("noprivate", KEY_KERN), - FUSE_OPT_KEY("noneglect_shares", KEY_KERN), - FUSE_OPT_KEY("nopush_symlinks_in", KEY_KERN), - /* Linux specific mount options, but let just the mount util handle them */ - FUSE_OPT_KEY("fsname=", KEY_KERN), - FUSE_OPT_KEY("nonempty", KEY_KERN), - FUSE_OPT_KEY("large_read", KEY_KERN), - FUSE_OPT_KEY("max_read=", KEY_KERN), - FUSE_OPT_END + { "allow_other", offsetof(struct mount_opts, allow_other), 1 }, + { "allow_root", offsetof(struct mount_opts, allow_root), 1 }, + FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT), + FUSE_OPT_KEY("-r", KEY_RO), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + /* standard FreeBSD mount options */ + FUSE_OPT_KEY("dev", KEY_KERN), + FUSE_OPT_KEY("async", KEY_KERN), + FUSE_OPT_KEY("atime", KEY_KERN), + FUSE_OPT_KEY("dev", KEY_KERN), + FUSE_OPT_KEY("exec", KEY_KERN), + FUSE_OPT_KEY("suid", KEY_KERN), + FUSE_OPT_KEY("symfollow", KEY_KERN), + FUSE_OPT_KEY("rdonly", KEY_KERN), + FUSE_OPT_KEY("sync", KEY_KERN), + FUSE_OPT_KEY("union", KEY_KERN), + FUSE_OPT_KEY("userquota", KEY_KERN), + FUSE_OPT_KEY("groupquota", KEY_KERN), + FUSE_OPT_KEY("clusterr", KEY_KERN), + FUSE_OPT_KEY("clusterw", KEY_KERN), + FUSE_OPT_KEY("suiddir", KEY_KERN), + FUSE_OPT_KEY("snapshot", KEY_KERN), + FUSE_OPT_KEY("multilabel", KEY_KERN), + FUSE_OPT_KEY("acls", KEY_KERN), + FUSE_OPT_KEY("force", KEY_KERN), + FUSE_OPT_KEY("update", KEY_KERN), + FUSE_OPT_KEY("ro", KEY_KERN), + FUSE_OPT_KEY("rw", KEY_KERN), + FUSE_OPT_KEY("auto", KEY_KERN), + /* options supported under both Linux and FBSD */ + FUSE_OPT_KEY("allow_other", KEY_KERN), + FUSE_OPT_KEY("default_permissions", KEY_KERN), + /* FBSD FUSE specific mount options */ + FUSE_OPT_KEY("private", KEY_KERN), + FUSE_OPT_KEY("neglect_shares", KEY_KERN), + FUSE_OPT_KEY("push_symlinks_in", KEY_KERN), + /* stock FBSD mountopt parsing routine lets anything be negated... */ + FUSE_OPT_KEY("nodev", KEY_KERN), + FUSE_OPT_KEY("noasync", KEY_KERN), + FUSE_OPT_KEY("noatime", KEY_KERN), + FUSE_OPT_KEY("nodev", KEY_KERN), + FUSE_OPT_KEY("noexec", KEY_KERN), + FUSE_OPT_KEY("nosuid", KEY_KERN), + FUSE_OPT_KEY("nosymfollow", KEY_KERN), + FUSE_OPT_KEY("nordonly", KEY_KERN), + FUSE_OPT_KEY("nosync", KEY_KERN), + FUSE_OPT_KEY("nounion", KEY_KERN), + FUSE_OPT_KEY("nouserquota", KEY_KERN), + FUSE_OPT_KEY("nogroupquota", KEY_KERN), + FUSE_OPT_KEY("noclusterr", KEY_KERN), + FUSE_OPT_KEY("noclusterw", KEY_KERN), + FUSE_OPT_KEY("nosuiddir", KEY_KERN), + FUSE_OPT_KEY("nosnapshot", KEY_KERN), + FUSE_OPT_KEY("nomultilabel", KEY_KERN), + FUSE_OPT_KEY("noacls", KEY_KERN), + FUSE_OPT_KEY("noforce", KEY_KERN), + FUSE_OPT_KEY("noupdate", KEY_KERN), + FUSE_OPT_KEY("noro", KEY_KERN), + FUSE_OPT_KEY("norw", KEY_KERN), + FUSE_OPT_KEY("noauto", KEY_KERN), + FUSE_OPT_KEY("noallow_other", KEY_KERN), + FUSE_OPT_KEY("nodefault_permissions", KEY_KERN), + FUSE_OPT_KEY("noprivate", KEY_KERN), + FUSE_OPT_KEY("noneglect_shares", KEY_KERN), + FUSE_OPT_KEY("nopush_symlinks_in", KEY_KERN), + /* + * Linux specific mount options, but let just the mount util + * handle them + */ + FUSE_OPT_KEY("fsname=", KEY_KERN), + FUSE_OPT_KEY("nonempty", KEY_KERN), + FUSE_OPT_KEY("large_read", KEY_KERN), + FUSE_OPT_KEY("max_read=", KEY_KERN), + FUSE_OPT_END }; static void mount_help(void) { - fprintf(stderr, - " -o allow_root allow access to root\n" - ); - system(FUSERMOUNT_PROG " --help"); - fputc('\n', stderr); + fprintf(stderr, + " -o allow_root allow access to root\n" + ); + system(FUSERMOUNT_PROG " --help"); + fputc('\n', stderr); } static void mount_version(void) { - system(FUSERMOUNT_PROG " --version"); + system(FUSERMOUNT_PROG " --version"); } static int fuse_mount_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - struct mount_opts *mo = data; - - switch (key) { - case KEY_ALLOW_ROOT: - if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || - fuse_opt_add_arg(outargs, "-oallow_root") == -1) - return -1; - return 0; - - case KEY_RO: - arg = "ro"; - /* fall through */ - - case KEY_KERN: - return fuse_opt_add_opt(&mo->kernel_opts, arg); - - case KEY_HELP: - mount_help(); - mo->ishelp = 1; - break; - - case KEY_VERSION: - mount_version(); - mo->ishelp = 1; - break; - } - return 1; + struct mount_opts *mo = data; + + switch (key) { + case KEY_ALLOW_ROOT: + if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 || + fuse_opt_add_arg(outargs, "-oallow_root") == -1) + return -1; + return 0; + + case KEY_RO: + arg = "ro"; + /* fall through */ + + case KEY_KERN: + return fuse_opt_add_opt(&mo->kernel_opts, arg); + + case KEY_HELP: + mount_help(); + mo->ishelp = 1; + break; + + case KEY_VERSION: + mount_version(); + mo->ishelp = 1; + break; + } + return 1; } void fuse_unmount_compat22(const char *mountpoint) { - char dev[128]; - char *ssc, *umount_cmd; - FILE *sf; - int rv; - char *seekscript = - "exec 2>/dev/null; " /* error message is annoying in help output */ - "/usr/bin/fstat " FUSE_DEV_TRUNK "* | " - "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; " - " { if ($3 == %d) print $10; }' | " - "/usr/bin/sort | " - "/usr/bin/uniq | " - "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'"; - - (void) mountpoint; - - /* - * If we don't know the fd, we have to resort to the scripted solution -- - * iterating over the fd-s is unpractical, as we don't know how many of - * open files we have. (This could be looked up in procfs -- however, - * that's optional on FBSD; or read out from the kmem -- however, that's - * bound to privileges (in fact, that's what happens when we call the - * setgid kmem fstat(1) utility). - */ - asprintf(&ssc, seekscript, getpid()); - - errno = 0; - sf = popen(ssc, "r"); - if (! sf) - return; - - fgets(dev, sizeof(dev), sf); - rv = pclose(sf); - if (rv) - return; - - asprintf(&umount_cmd, "/sbin/umount %s", dev); - system(umount_cmd); + char dev[128]; + char *ssc, *umount_cmd; + FILE *sf; + int rv; + char *seekscript = + /* error message is annoying in help output */ + "exec 2>/dev/null; " + "/usr/bin/fstat " FUSE_DEV_TRUNK "* | " + "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; " + " { if ($3 == %d) print $10; }' | " + "/usr/bin/sort | " + "/usr/bin/uniq | " + "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'"; + + (void) mountpoint; + + /* + * If we don't know the fd, we have to resort to the scripted + * solution -- iterating over the fd-s is unpractical, as we + * don't know how many of open files we have. (This could be + * looked up in procfs -- however, that's optional on FBSD; or + * read out from the kmem -- however, that's bound to + * privileges (in fact, that's what happens when we call the + * setgid kmem fstat(1) utility). + */ + asprintf(&ssc, seekscript, getpid()); + + errno = 0; + sf = popen(ssc, "r"); + if (! sf) + return; + + fgets(dev, sizeof(dev), sf); + rv = pclose(sf); + if (rv) + return; + + asprintf(&umount_cmd, "/sbin/umount %s", dev); + system(umount_cmd); } void fuse_kern_unmount(const char *mountpoint, int fd) { - char *ep, *umount_cmd, dev[128]; - struct stat sbuf; + char *ep, *umount_cmd, dev[128]; + struct stat sbuf; - (void)mountpoint; + (void)mountpoint; - if (fstat(fd, &sbuf) == -1) - return; + if (fstat(fd, &sbuf) == -1) + return; - devname_r(sbuf.st_rdev, S_IFCHR, dev, 128); + devname_r(sbuf.st_rdev, S_IFCHR, dev, 128); - if (strncmp(dev, "fuse", 4)) - return; + if (strncmp(dev, "fuse", 4)) + return; - strtol(dev + 4, &ep, 10); - if (*ep != '\0') - return; + strtol(dev + 4, &ep, 10); + if (*ep != '\0') + return; - asprintf(&umount_cmd, "/sbin/umount " _PATH_DEV "%s", dev); - system(umount_cmd); + asprintf(&umount_cmd, "/sbin/umount " _PATH_DEV "%s", dev); + system(umount_cmd); } /* Check if kernel is doing init in background */ static int init_backgrounded(void) { - int ibg, len; + int ibg, len; - len = sizeof(ibg); + len = sizeof(ibg); - if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0)) - return 0; + if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0)) + return 0; - return ibg; + return ibg; } static int fuse_mount_core(const char *mountpoint, const char *opts) { - const char *mountprog = FUSERMOUNT_PROG; - int fd; - char *fdnam, *dev; - int pid; + const char *mountprog = FUSERMOUNT_PROG; + int fd; + char *fdnam, *dev; + int pid; - fdnam = getenv("FUSE_DEV_FD"); + fdnam = getenv("FUSE_DEV_FD"); - if (fdnam) { - char *ep; + if (fdnam) { + char *ep; - fd = strtol(fdnam, &ep, 10); + fd = strtol(fdnam, &ep, 10); - if (*ep != '\0') { - fprintf(stderr, "invalid value given in FUSE_DEV_FD\n"); - return -1; - } + if (*ep != '\0') { + fprintf(stderr, "invalid value given in FUSE_DEV_FD\n"); + return -1; + } - if (fd < 0) - return -1; + if (fd < 0) + return -1; - goto mount; - } + goto mount; + } - dev = getenv("FUSE_DEV_NAME"); + dev = getenv("FUSE_DEV_NAME"); - if (! dev) - dev = FUSE_DEV_TRUNK; + if (! dev) + dev = FUSE_DEV_TRUNK; - if ((fd = open(dev, O_RDWR)) < 0) { - perror("fuse: failed to open fuse device"); - return -1; - } + if ((fd = open(dev, O_RDWR)) < 0) { + perror("fuse: failed to open fuse device"); + return -1; + } mount: - if (getenv("FUSE_NO_MOUNT") || ! mountpoint) - goto out; - - pid = fork(); - - if (pid == -1) { - perror("fuse: fork() failed"); - close(fd); - return -1; - } - - if (pid == 0) { - if (! init_backgrounded()) { - /* - * If init is not backgrounded, we have to call the mount util - * backgrounded, to avoid deadlock. - */ - - pid = fork(); - - if (pid == -1) { - perror("fuse: fork() failed"); - close(fd); - exit(1); - } - } - - if (pid == 0) { - const char *argv[32]; - int a = 0; - - if (! fdnam) - asprintf(&fdnam, "%d", fd); - - argv[a++] = mountprog; - if (opts) { - argv[a++] = "-o"; - argv[a++] = opts; - } - argv[a++] = fdnam; - argv[a++] = mountpoint; - argv[a++] = NULL; - execvp(mountprog, (char **) argv); - perror("fuse: failed to exec mount program"); - exit(1); - } - - exit(0); - } - - waitpid(pid, NULL, 0); + if (getenv("FUSE_NO_MOUNT") || ! mountpoint) + goto out; + + pid = fork(); + + if (pid == -1) { + perror("fuse: fork() failed"); + close(fd); + return -1; + } + + if (pid == 0) { + if (! init_backgrounded()) { + /* + * If init is not backgrounded, we have to + * call the mount util backgrounded, to avoid + * deadlock. + */ + + pid = fork(); + + if (pid == -1) { + perror("fuse: fork() failed"); + close(fd); + exit(1); + } + } + + if (pid == 0) { + const char *argv[32]; + int a = 0; + + if (! fdnam) + asprintf(&fdnam, "%d", fd); + + argv[a++] = mountprog; + if (opts) { + argv[a++] = "-o"; + argv[a++] = opts; + } + argv[a++] = fdnam; + argv[a++] = mountpoint; + argv[a++] = NULL; + execvp(mountprog, (char **) argv); + perror("fuse: failed to exec mount program"); + exit(1); + } + + exit(0); + } + + waitpid(pid, NULL, 0); out: - return fd; + return fd; } int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) { - struct mount_opts mo; - int res = -1; - - memset(&mo, 0, sizeof(mo)); - /* mount util should not try to spawn the daemon */ - setenv("MOUNT_FUSEFS_SAFE", "1", 1); - /* to notify the mount util it's called from lib */ - setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); - - if (args && - fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) - return -1; - - if (mo.allow_other && mo.allow_root) { - fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); - goto out; - } - if (mo.ishelp) - return 0; - - res = fuse_mount_core(mountpoint, mo.kernel_opts); - out: - free(mo.kernel_opts); - return res; + struct mount_opts mo; + int res = -1; + + memset(&mo, 0, sizeof(mo)); + /* mount util should not try to spawn the daemon */ + setenv("MOUNT_FUSEFS_SAFE", "1", 1); + /* to notify the mount util it's called from lib */ + setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); + + if (args && + fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) + return -1; + + if (mo.allow_other && mo.allow_root) { + fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); + goto out; + } + if (mo.ishelp) + return 0; + + res = fuse_mount_core(mountpoint, mo.kernel_opts); +out: + free(mo.kernel_opts); + return res; } FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2"); diff --git a/lib/mount_util.c b/lib/mount_util.c index 9ce431a..39a1e6f 100644 --- a/lib/mount_util.c +++ b/lib/mount_util.c @@ -1,9 +1,9 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include "mount_util.h" @@ -21,220 +21,223 @@ static int mtab_needs_update(const char *mnt) { - struct stat stbuf; + struct stat stbuf; - /* If mtab is within new mount, don't touch it */ - if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && - _PATH_MOUNTED[strlen(mnt)] == '/') - return 0; + /* If mtab is within new mount, don't touch it */ + if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 && + _PATH_MOUNTED[strlen(mnt)] == '/') + return 0; - if (lstat(_PATH_MOUNTED, &stbuf) != -1 && S_ISLNK(stbuf.st_mode)) - return 0; + if (lstat(_PATH_MOUNTED, &stbuf) != -1 && S_ISLNK(stbuf.st_mode)) + return 0; - return 1; + return 1; } int fuse_mnt_add_mount(const char *progname, const char *fsname, - const char *mnt, const char *type, const char *opts) + const char *mnt, const char *type, const char *opts) { - int res; - int status; - - if (!mtab_needs_update(mnt)) - return 0; - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - return -1; - } - if (res == 0) { - char templ[] = "/tmp/fusermountXXXXXX"; - char *tmp; - - setuid(geteuid()); - - /* - * hide in a directory, where mount isn't able to resolve - * fsname as a valid path - */ - tmp = mkdtemp(templ); - if (!tmp) { - fprintf(stderr, "%s: failed to create temporary directory\n", - progname); - exit(1); - } - if (chdir(tmp)) { - fprintf(stderr, "%s: failed to chdir to %s: %s\n", - progname, tmp, strerror(errno)); - exit(1); - } - rmdir(tmp); - execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts, - fsname, mnt, NULL); - fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", progname, - strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) { - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - return -1; - } - if (status != 0) - return -1; - - return 0; + int res; + int status; + + if (!mtab_needs_update(mnt)) + return 0; + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + return -1; + } + if (res == 0) { + char templ[] = "/tmp/fusermountXXXXXX"; + char *tmp; + + setuid(geteuid()); + + /* + * hide in a directory, where mount isn't able to resolve + * fsname as a valid path + */ + tmp = mkdtemp(templ); + if (!tmp) { + fprintf(stderr, + "%s: failed to create temporary directory\n", + progname); + exit(1); + } + if (chdir(tmp)) { + fprintf(stderr, "%s: failed to chdir to %s: %s\n", + progname, tmp, strerror(errno)); + exit(1); + } + rmdir(tmp); + execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, + "-o", opts, fsname, mnt, NULL); + fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) { + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + return -1; + } + if (status != 0) + return -1; + + return 0; } int fuse_mnt_umount(const char *progname, const char *mnt, int lazy) { - int res; - int status; - - if (!mtab_needs_update(mnt)) { - res = umount2(mnt, lazy ? 2 : 0); - if (res == -1) - fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, - mnt, strerror(errno)); - return res; - } - - res = fork(); - if (res == -1) { - fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); - return -1; - } - if (res == 0) { - setuid(geteuid()); - execl("/bin/umount", "/bin/umount", "-i", mnt, lazy ? "-l" : NULL, - NULL); - fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", progname, - strerror(errno)); - exit(1); - } - res = waitpid(res, &status, 0); - if (res == -1) { - fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); - return -1; - } - if (status != 0) - return -1; - - return 0; + int res; + int status; + + if (!mtab_needs_update(mnt)) { + res = umount2(mnt, lazy ? 2 : 0); + if (res == -1) + fprintf(stderr, "%s: failed to unmount %s: %s\n", + progname, mnt, strerror(errno)); + return res; + } + + res = fork(); + if (res == -1) { + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + return -1; + } + if (res == 0) { + setuid(geteuid()); + execl("/bin/umount", "/bin/umount", "-i", mnt, + lazy ? "-l" : NULL, NULL); + fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", + progname, strerror(errno)); + exit(1); + } + res = waitpid(res, &status, 0); + if (res == -1) { + fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno)); + return -1; + } + if (status != 0) + return -1; + + return 0; } char *fuse_mnt_resolve_path(const char *progname, const char *orig) { - char buf[PATH_MAX]; - char *copy; - char *dst; - char *end; - char *lastcomp; - const char *toresolv; - - if (!orig[0]) { - fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig); - return NULL; - } - - copy = strdup(orig); - if (copy == NULL) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return NULL; - } - - toresolv = copy; - lastcomp = NULL; - for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); - if (end[0] != '/') { - char *tmp; - end[1] = '\0'; - tmp = strrchr(copy, '/'); - if (tmp == NULL) { - lastcomp = copy; - toresolv = "."; - } else { - lastcomp = tmp + 1; - if (tmp == copy) - toresolv = "/"; - } - if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { - lastcomp = NULL; - toresolv = copy; - } - else if (tmp) - tmp[0] = '\0'; - } - if (realpath(toresolv, buf) == NULL) { - fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, - strerror(errno)); - free(copy); - return NULL; - } - if (lastcomp == NULL) - dst = strdup(buf); - else { - dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); - if (dst) { - unsigned buflen = strlen(buf); - if (buflen && buf[buflen-1] == '/') - sprintf(dst, "%s%s", buf, lastcomp); - else - sprintf(dst, "%s/%s", buf, lastcomp); - } - } - free(copy); - if (dst == NULL) - fprintf(stderr, "%s: failed to allocate memory\n", progname); - return dst; + char buf[PATH_MAX]; + char *copy; + char *dst; + char *end; + char *lastcomp; + const char *toresolv; + + if (!orig[0]) { + fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, + orig); + return NULL; + } + + copy = strdup(orig); + if (copy == NULL) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return NULL; + } + + toresolv = copy; + lastcomp = NULL; + for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --); + if (end[0] != '/') { + char *tmp; + end[1] = '\0'; + tmp = strrchr(copy, '/'); + if (tmp == NULL) { + lastcomp = copy; + toresolv = "."; + } else { + lastcomp = tmp + 1; + if (tmp == copy) + toresolv = "/"; + } + if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) { + lastcomp = NULL; + toresolv = copy; + } + else if (tmp) + tmp[0] = '\0'; + } + if (realpath(toresolv, buf) == NULL) { + fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig, + strerror(errno)); + free(copy); + return NULL; + } + if (lastcomp == NULL) + dst = strdup(buf); + else { + dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1); + if (dst) { + unsigned buflen = strlen(buf); + if (buflen && buf[buflen-1] == '/') + sprintf(dst, "%s%s", buf, lastcomp); + else + sprintf(dst, "%s/%s", buf, lastcomp); + } + } + free(copy); + if (dst == NULL) + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return dst; } int fuse_mnt_check_empty(const char *progname, const char *mnt, - mode_t rootmode, off_t rootsize) + mode_t rootmode, off_t rootsize) { - int isempty = 1; - - if (S_ISDIR(rootmode)) { - struct dirent *ent; - DIR *dp = opendir(mnt); - if (dp == NULL) { - fprintf(stderr, "%s: failed to open mountpoint for reading: %s\n", - progname, strerror(errno)); - return -1; - } - while ((ent = readdir(dp)) != NULL) { - if (strcmp(ent->d_name, ".") != 0 && - strcmp(ent->d_name, "..") != 0) { - isempty = 0; - break; - } - } - closedir(dp); - } else if (rootsize) - isempty = 0; - - if (!isempty) { - fprintf(stderr, "%s: mountpoint is not empty\n", progname); - fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname); - return -1; - } - return 0; + int isempty = 1; + + if (S_ISDIR(rootmode)) { + struct dirent *ent; + DIR *dp = opendir(mnt); + if (dp == NULL) { + fprintf(stderr, + "%s: failed to open mountpoint for reading: %s\n", + progname, strerror(errno)); + return -1; + } + while ((ent = readdir(dp)) != NULL) { + if (strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0) { + isempty = 0; + break; + } + } + closedir(dp); + } else if (rootsize) + isempty = 0; + + if (!isempty) { + fprintf(stderr, "%s: mountpoint is not empty\n", progname); + fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname); + return -1; + } + return 0; } int fuse_mnt_check_fuseblk(void) { - char buf[256]; - FILE *f = fopen("/proc/filesystems", "r"); - if (!f) - return 1; - - while (fgets(buf, sizeof(buf), f)) - if (strstr(buf, "fuseblk\n")) { - fclose(f); - return 1; - } - - fclose(f); - return 0; + char buf[256]; + FILE *f = fopen("/proc/filesystems", "r"); + if (!f) + return 1; + + while (fgets(buf, sizeof(buf), f)) + if (strstr(buf, "fuseblk\n")) { + fclose(f); + return 1; + } + + fclose(f); + return 0; } diff --git a/lib/mount_util.h b/lib/mount_util.h index 29de2be..cf54d9d 100644 --- a/lib/mount_util.h +++ b/lib/mount_util.h @@ -1,17 +1,17 @@ /* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + FUSE: Filesystem in Userspace + Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB. + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB. */ #include <sys/types.h> int fuse_mnt_add_mount(const char *progname, const char *fsname, - const char *mnt, const char *type, const char *opts); + const char *mnt, const char *type, const char *opts); int fuse_mnt_umount(const char *progname, const char *mnt, int lazy); char *fuse_mnt_resolve_path(const char *progname, const char *orig); int fuse_mnt_check_empty(const char *progname, const char *mnt, - mode_t rootmode, off_t rootsize); + mode_t rootmode, off_t rootsize); int fuse_mnt_check_fuseblk(void); diff --git a/lib/ulockmgr.c b/lib/ulockmgr.c index e38fdc5..6703cd0 100644 --- a/lib/ulockmgr.c +++ b/lib/ulockmgr.c @@ -1,9 +1,9 @@ /* - libulockmgr: Userspace Lock Manager Library - Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu> + libulockmgr: Userspace Lock Manager Library + Copyright (C) 2006 Miklos Szeredi <miklos@szeredi.hu> - This program can be distributed under the terms of the GNU LGPLv2. - See the file COPYING.LIB + This program can be distributed under the terms of the GNU LGPLv2. + See the file COPYING.LIB */ /* #define DEBUG 1 */ @@ -22,28 +22,28 @@ #include <sys/wait.h> struct message { - unsigned intr : 1; - unsigned nofd : 1; - pthread_t thr; - int cmd; - int fd; - struct flock lock; - int error; + unsigned intr : 1; + unsigned nofd : 1; + pthread_t thr; + int cmd; + int fd; + struct flock lock; + int error; }; struct fd_store { - struct fd_store *next; - int fd; - int inuse; + struct fd_store *next; + int fd; + int inuse; }; struct owner { - struct owner *next; - struct owner *prev; - struct fd_store *fds; - void *id; - size_t id_len; - int cfd; + struct owner *next; + struct owner *prev; + struct fd_store *fds; + void *id; + size_t id_len; + int cfd; }; static pthread_mutex_t ulockmgr_lock; @@ -54,19 +54,19 @@ static struct owner owner_list = { .next = &owner_list, .prev = &owner_list }; static void list_del_owner(struct owner *owner) { - struct owner *prev = owner->prev; - struct owner *next = owner->next; - prev->next = next; - next->prev = prev; + struct owner *prev = owner->prev; + struct owner *next = owner->next; + prev->next = next; + next->prev = prev; } static void list_add_owner(struct owner *owner, struct owner *next) { - struct owner *prev = next->prev; - owner->next = next; - owner->prev = prev; - prev->next = owner; - next->prev = owner; + struct owner *prev = next->prev; + owner->next = next; + owner->prev = prev; + prev->next = owner; + next->prev = owner; } /* @@ -74,365 +74,367 @@ static void list_add_owner(struct owner *owner, struct owner *next) * on AF_UNIX, SOCK_STREAM sockets, that could cause it to return * zero, even if data was available. Retrying the recv will return * the data in this case. -*/ + */ static int do_recv(int sock, void *buf, size_t len, int flags) { - int res = recv(sock, buf, len, flags); - if (res == 0) - res = recv(sock, buf, len, flags); + int res = recv(sock, buf, len, flags); + if (res == 0) + res = recv(sock, buf, len, flags); - return res; + return res; } static int ulockmgr_send_message(int sock, void *buf, size_t buflen, - int *fdp, int numfds) + int *fdp, int numfds) { - struct msghdr msg; - struct cmsghdr *p_cmsg; - struct iovec vec; - size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; - int res; - - assert(numfds <= MAX_SEND_FDS); - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - p_cmsg = CMSG_FIRSTHDR(&msg); - p_cmsg->cmsg_level = SOL_SOCKET; - p_cmsg->cmsg_type = SCM_RIGHTS; - p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds); - memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds); - msg.msg_controllen = p_cmsg->cmsg_len; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - vec.iov_base = buf; - vec.iov_len = buflen; - res = sendmsg(sock, &msg, MSG_NOSIGNAL); - if (res == -1) { - perror("libulockmgr: sendmsg"); - return -1; - } - if ((size_t) res != buflen) { - fprintf(stderr, "libulockmgr: sendmsg short\n"); - return -1; - } - return 0; + struct msghdr msg; + struct cmsghdr *p_cmsg; + struct iovec vec; + size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)]; + int res; + + assert(numfds <= MAX_SEND_FDS); + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + p_cmsg = CMSG_FIRSTHDR(&msg); + p_cmsg->cmsg_level = SOL_SOCKET; + p_cmsg->cmsg_type = SCM_RIGHTS; + p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds); + memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds); + msg.msg_controllen = p_cmsg->cmsg_len; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + vec.iov_base = buf; + vec.iov_len = buflen; + res = sendmsg(sock, &msg, MSG_NOSIGNAL); + if (res == -1) { + perror("libulockmgr: sendmsg"); + return -1; + } + if ((size_t) res != buflen) { + fprintf(stderr, "libulockmgr: sendmsg short\n"); + return -1; + } + return 0; } static int ulockmgr_start_daemon(void) { - int sv[2]; - int res; - char tmp[64]; - - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - return -1; - } - snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]); - res = system(tmp); - close(sv[0]); - if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) { - close(sv[1]); - return -1; - } - ulockmgr_cfd = sv[1]; - return 0; + int sv[2]; + int res; + char tmp[64]; + + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + return -1; + } + snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]); + res = system(tmp); + close(sv[0]); + if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) { + close(sv[1]); + return -1; + } + ulockmgr_cfd = sv[1]; + return 0; } static struct owner *ulockmgr_new_owner(const void *id, size_t id_len) { - int sv[2]; - int res; - char c = 'm'; - struct owner *o; - - if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1) - return NULL; - - o = calloc(1, sizeof(struct owner) + id_len); - if (!o) { - fprintf(stderr, "libulockmgr: failed to allocate memory\n"); - return NULL; - } - o->id = o + 1; - o->id_len = id_len; - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - goto out_free; - } - res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1); - close(sv[0]); - if (res == -1) { - close(ulockmgr_cfd); - ulockmgr_cfd = -1; - goto out_close; - } - - o->cfd = sv[1]; - memcpy(o->id, id, id_len); - list_add_owner(o, &owner_list); - - return o; - - out_close: - close(sv[1]); - out_free: - free(o); - return NULL; + int sv[2]; + int res; + char c = 'm'; + struct owner *o; + + if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1) + return NULL; + + o = calloc(1, sizeof(struct owner) + id_len); + if (!o) { + fprintf(stderr, "libulockmgr: failed to allocate memory\n"); + return NULL; + } + o->id = o + 1; + o->id_len = id_len; + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + goto out_free; + } + res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1); + close(sv[0]); + if (res == -1) { + close(ulockmgr_cfd); + ulockmgr_cfd = -1; + goto out_close; + } + + o->cfd = sv[1]; + memcpy(o->id, id, id_len); + list_add_owner(o, &owner_list); + + return o; + +out_close: + close(sv[1]); +out_free: + free(o); + return NULL; } static int ulockmgr_send_request(struct message *msg, const void *id, - size_t id_len) + size_t id_len) { - int sv[2]; - int cfd; - struct owner *o; - struct fd_store *f = NULL; - struct fd_store *newf = NULL; - struct fd_store **fp; - int fd = msg->fd; - int cmd = msg->cmd; - int res; - int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK && - msg->lock.l_start == 0 && msg->lock.l_len == 0); - - for (o = owner_list.next; o != &owner_list; o = o->next) - if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0) - break; - - if (o == &owner_list) - o = NULL; - - if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK) - o = ulockmgr_new_owner(id, id_len); - - if (!o) { - if (cmd == F_GETLK) { - res = fcntl(msg->fd, F_GETLK, &msg->lock); - return (res == -1) ? -errno : 0; - } else if (msg->lock.l_type == F_UNLCK) - return 0; - else - return -ENOLCK; - } - - if (unlockall) - msg->nofd = 1; - else { - for (fp = &o->fds; *fp; fp = &(*fp)->next) { - f = *fp; - if (f->fd == fd) { - msg->nofd = 1; - break; - } - } - } - - if (!msg->nofd) { - newf = f = calloc(1, sizeof(struct fd_store)); - if (!f) { - fprintf(stderr, "libulockmgr: failed to allocate memory\n"); - return -ENOLCK; - } - } - - res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); - if (res == -1) { - perror("libulockmgr: socketpair"); - free(newf); - return -ENOLCK; - } - - cfd = sv[1]; - sv[1] = msg->fd; - res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv, - msg->nofd ? 1 : 2); - close(sv[0]); - if (res == -1) { - free(newf); - close(cfd); - return -EIO; - } - - if (newf) { - newf->fd = msg->fd; - newf->next = o->fds; - o->fds = newf; - } - if (f) - f->inuse++; - - res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL); - if (res == -1) { - perror("libulockmgr: recv"); - msg->error = EIO; - } else if (res != sizeof(struct message)) { - fprintf(stderr, "libulockmgr: recv short\n"); - msg->error = EIO; - } else if (cmd == F_SETLKW && msg->error == EAGAIN) { - pthread_mutex_unlock(&ulockmgr_lock); - while (1) { - sigset_t old; - sigset_t unblock; - int errno_save; - - sigemptyset(&unblock); - sigaddset(&unblock, SIGUSR1); - pthread_sigmask(SIG_UNBLOCK, &unblock, &old); - res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL); - errno_save = errno; - pthread_sigmask(SIG_SETMASK, &old, NULL); - if (res == sizeof(struct message)) - break; - else if (res >= 0) { - fprintf(stderr, "libulockmgr: recv short\n"); - msg->error = EIO; - break; - } else if (errno_save != EINTR) { - errno = errno_save; - perror("libulockmgr: recv"); - msg->error = EIO; - break; - } - msg->intr = 1; - res = send(o->cfd, msg, sizeof(struct message), MSG_NOSIGNAL); - if (res == -1) { - perror("libulockmgr: send"); - msg->error = EIO; - break; - } - if (res != sizeof(struct message)) { - fprintf(stderr, "libulockmgr: send short\n"); - msg->error = EIO; - break; - } - } - pthread_mutex_lock(&ulockmgr_lock); - - } - if (f) - f->inuse--; - close(cfd); - if (unlockall) { - for (fp = &o->fds; *fp;) { - f = *fp; - if (f->fd == fd && !f->inuse) { - *fp = f->next; - free(f); - } else - fp = &f->next; - } - if (!o->fds) { - list_del_owner(o); - close(o->cfd); - free(o); - } - /* Force OK on unlock-all, since it _will_ succeed once the - owner is deleted */ - msg->error = 0; - } - - return -msg->error; + int sv[2]; + int cfd; + struct owner *o; + struct fd_store *f = NULL; + struct fd_store *newf = NULL; + struct fd_store **fp; + int fd = msg->fd; + int cmd = msg->cmd; + int res; + int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK && + msg->lock.l_start == 0 && msg->lock.l_len == 0); + + for (o = owner_list.next; o != &owner_list; o = o->next) + if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0) + break; + + if (o == &owner_list) + o = NULL; + + if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK) + o = ulockmgr_new_owner(id, id_len); + + if (!o) { + if (cmd == F_GETLK) { + res = fcntl(msg->fd, F_GETLK, &msg->lock); + return (res == -1) ? -errno : 0; + } else if (msg->lock.l_type == F_UNLCK) + return 0; + else + return -ENOLCK; + } + + if (unlockall) + msg->nofd = 1; + else { + for (fp = &o->fds; *fp; fp = &(*fp)->next) { + f = *fp; + if (f->fd == fd) { + msg->nofd = 1; + break; + } + } + } + + if (!msg->nofd) { + newf = f = calloc(1, sizeof(struct fd_store)); + if (!f) { + fprintf(stderr, "libulockmgr: failed to allocate memory\n"); + return -ENOLCK; + } + } + + res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + if (res == -1) { + perror("libulockmgr: socketpair"); + free(newf); + return -ENOLCK; + } + + cfd = sv[1]; + sv[1] = msg->fd; + res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv, + msg->nofd ? 1 : 2); + close(sv[0]); + if (res == -1) { + free(newf); + close(cfd); + return -EIO; + } + + if (newf) { + newf->fd = msg->fd; + newf->next = o->fds; + o->fds = newf; + } + if (f) + f->inuse++; + + res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL); + if (res == -1) { + perror("libulockmgr: recv"); + msg->error = EIO; + } else if (res != sizeof(struct message)) { + fprintf(stderr, "libulockmgr: recv short\n"); + msg->error = EIO; + } else if (cmd == F_SETLKW && msg->error == EAGAIN) { + pthread_mutex_unlock(&ulockmgr_lock); + while (1) { + sigset_t old; + sigset_t unblock; + int errno_save; + + sigemptyset(&unblock); + sigaddset(&unblock, SIGUSR1); + pthread_sigmask(SIG_UNBLOCK, &unblock, &old); + res = do_recv(cfd, msg, sizeof(struct message), + MSG_WAITALL); + errno_save = errno; + pthread_sigmask(SIG_SETMASK, &old, NULL); + if (res == sizeof(struct message)) + break; + else if (res >= 0) { + fprintf(stderr, "libulockmgr: recv short\n"); + msg->error = EIO; + break; + } else if (errno_save != EINTR) { + errno = errno_save; + perror("libulockmgr: recv"); + msg->error = EIO; + break; + } + msg->intr = 1; + res = send(o->cfd, msg, sizeof(struct message), + MSG_NOSIGNAL); + if (res == -1) { + perror("libulockmgr: send"); + msg->error = EIO; + break; + } + if (res != sizeof(struct message)) { + fprintf(stderr, "libulockmgr: send short\n"); + msg->error = EIO; + break; + } + } + pthread_mutex_lock(&ulockmgr_lock); + + } + if (f) + f->inuse--; + close(cfd); + if (unlockall) { + for (fp = &o->fds; *fp;) { + f = *fp; + if (f->fd == fd && !f->inuse) { + *fp = f->next; + free(f); + } else + fp = &f->next; + } + if (!o->fds) { + list_del_owner(o); + close(o->cfd); + free(o); + } + /* Force OK on unlock-all, since it _will_ succeed once the + owner is deleted */ + msg->error = 0; + } + + return -msg->error; } #ifdef DEBUG static uint32_t owner_hash(const unsigned char *id, size_t id_len) { - uint32_t h = 0; - size_t i; - for (i = 0; i < id_len; i++) - h = ((h << 8) | (h >> 24)) ^ id[i]; + uint32_t h = 0; + size_t i; + for (i = 0; i < id_len; i++) + h = ((h << 8) | (h >> 24)) ^ id[i]; - return h; + return h; } #endif static int ulockmgr_canonicalize(int fd, struct flock *lock) { - off_t offset; - if (lock->l_whence == SEEK_CUR) { - offset = lseek(fd, 0, SEEK_CUR); - if (offset == (off_t) -1) - return -errno; - } else if (lock->l_whence == SEEK_END) { - struct stat stbuf; - int res = fstat(fd, &stbuf); - if (res == -1) - return -errno; - - offset = stbuf.st_size; - } else - offset = 0; - - lock->l_whence = SEEK_SET; - lock->l_start += offset; - - if (lock->l_start < 0) - return -EINVAL; - - if (lock->l_len < 0) { - lock->l_start += lock->l_len; - if (lock->l_start < 0) - return -EINVAL; - lock->l_len = -lock->l_len; - } - if (lock->l_len && lock->l_start + lock->l_len - 1 < 0) - return -EINVAL; - - return 0; + off_t offset; + if (lock->l_whence == SEEK_CUR) { + offset = lseek(fd, 0, SEEK_CUR); + if (offset == (off_t) -1) + return -errno; + } else if (lock->l_whence == SEEK_END) { + struct stat stbuf; + int res = fstat(fd, &stbuf); + if (res == -1) + return -errno; + + offset = stbuf.st_size; + } else + offset = 0; + + lock->l_whence = SEEK_SET; + lock->l_start += offset; + + if (lock->l_start < 0) + return -EINVAL; + + if (lock->l_len < 0) { + lock->l_start += lock->l_len; + if (lock->l_start < 0) + return -EINVAL; + lock->l_len = -lock->l_len; + } + if (lock->l_len && lock->l_start + lock->l_len - 1 < 0) + return -EINVAL; + + return 0; } int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner, - size_t owner_len) + size_t owner_len) { - int err; - struct message msg; - sigset_t old; - sigset_t block; + int err; + struct message msg; + sigset_t old; + sigset_t block; - if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW) - return -EINVAL; + if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW) + return -EINVAL; - if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR && - lock->l_whence != SEEK_END) - return -EINVAL; + if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR && + lock->l_whence != SEEK_END) + return -EINVAL; #ifdef DEBUG - fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n", - cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len, - owner_hash(owner, owner_len)); + fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n", + cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len, + owner_hash(owner, owner_len)); #endif - /* Unlock should never block anyway */ - if (cmd == F_SETLKW && lock->l_type == F_UNLCK) - cmd = F_SETLK; - - memset(&msg, 0, sizeof(struct message)); - msg.cmd = cmd; - msg.fd = fd; - msg.lock = *lock; - err = ulockmgr_canonicalize(fd, &msg.lock); - if (err) - return err; - - sigemptyset(&block); - sigaddset(&block, SIGUSR1); - pthread_sigmask(SIG_BLOCK, &block, &old); - pthread_mutex_lock(&ulockmgr_lock); - err = ulockmgr_send_request(&msg, owner, owner_len); - pthread_mutex_unlock(&ulockmgr_lock); - pthread_sigmask(SIG_SETMASK, &old, NULL); - if (!err && cmd == F_GETLK) { - if (msg.lock.l_type == F_UNLCK) - lock->l_type = F_UNLCK; - else - *lock = msg.lock; - } - - return err; + /* Unlock should never block anyway */ + if (cmd == F_SETLKW && lock->l_type == F_UNLCK) + cmd = F_SETLK; + + memset(&msg, 0, sizeof(struct message)); + msg.cmd = cmd; + msg.fd = fd; + msg.lock = *lock; + err = ulockmgr_canonicalize(fd, &msg.lock); + if (err) + return err; + + sigemptyset(&block); + sigaddset(&block, SIGUSR1); + pthread_sigmask(SIG_BLOCK, &block, &old); + pthread_mutex_lock(&ulockmgr_lock); + err = ulockmgr_send_request(&msg, owner, owner_len); + pthread_mutex_unlock(&ulockmgr_lock); + pthread_sigmask(SIG_SETMASK, &old, NULL); + if (!err && cmd == F_GETLK) { + if (msg.lock.l_type == F_UNLCK) + lock->l_type = F_UNLCK; + else + *lock = msg.lock; + } + + return err; } |