📄 fuse.c
字号:
}static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req, 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);}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);}static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req, struct fuse_intr_data *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){ if (f->conf.intr) fuse_do_prepare_interrupt(req, d);}static int fuse_do_getattr(struct fuse *f, fuse_req_t req, const char *path, struct stat *buf){ int res; struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = f->op.getattr(path, buf); fuse_finish_interrupt(f, req, &d); return res;}static int fuse_do_fgetattr(struct fuse *f, fuse_req_t req, const char *path, struct stat *buf, struct fuse_file_info *fi){ int res; struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = f->op.fgetattr(path, buf, fi); fuse_finish_interrupt(f, req, &d); return res;}static int fuse_do_rename(struct fuse *f, fuse_req_t req, const char *oldpath, const char *newpath){ int res; struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = f->op.rename(oldpath, newpath); fuse_finish_interrupt(f, req, &d); return res;}static int fuse_do_unlink(struct fuse *f, fuse_req_t req, const char *path){ int res; struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = f->op.unlink(path); fuse_finish_interrupt(f, req, &d); return res;}static void fuse_do_release(struct fuse *f, fuse_req_t req, const char *path, struct fuse_file_info *fi){ struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); f->op.release(path, fi); fuse_finish_interrupt(f, req, &d);}static int fuse_do_opendir(struct fuse *f, fuse_req_t req, char *path, struct fuse_file_info *fi){ int res; struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = f->op.opendir(path, fi); fuse_finish_interrupt(f, req, &d); return res;}static int fuse_do_open(struct fuse *f, fuse_req_t req, char *path, struct fuse_file_info *fi){ int res; struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = f->op.open(path, fi); fuse_finish_interrupt(f, req, &d); return res;}static int fuse_do_flush(struct fuse *f, fuse_req_t req, const char *path, struct fuse_file_info *fi){ int res; struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = f->op.flush(path, fi); fuse_finish_interrupt(f, req, &d); return res;}static int fuse_do_statfs(struct fuse *f, fuse_req_t req, const char *path, struct statvfs *buf){ int res; struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = f->op.statfs(path, buf); fuse_finish_interrupt(f, req, &d); return res;}static void fuse_do_releasedir(struct fuse *f, fuse_req_t req, const char *path, struct fuse_file_info *fi){ struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); f->op.releasedir(path, fi); fuse_finish_interrupt(f, req, &d);}static int fuse_do_create(struct fuse *f, fuse_req_t req, const char *path, mode_t mode, struct fuse_file_info *fi){ int res; struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = f->op.create(path, mode, fi); fuse_finish_interrupt(f, req, &d); return res;}static int fuse_do_lock(struct fuse *f, fuse_req_t req, const char *path, struct fuse_file_info *fi, int cmd, struct flock *lock){ int res; struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = f->op.lock(path, fi, cmd, lock); fuse_finish_interrupt(f, req, &d); return res;}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;}static char *hidden_name(struct fuse *f, fuse_req_t req, 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; if (!f->op.getattr) return NULL; 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_do_getattr(f, req, newpath, &buf); if (res != 0) break; free(newpath); newpath = NULL; } while(--failctr); return newpath;}static int hide_node(struct fuse *f, fuse_req_t req, const char *oldpath, fuse_ino_t dir, const char *oldname){ char newname[64]; char *newpath; int err = -EBUSY; if (f->op.rename && f->op.unlink) { newpath = hidden_name(f, req, dir, oldname, newname, sizeof(newname)); if (newpath) { err = fuse_do_rename(f, req, 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#ifdef FUSE_STAT_HAS_NANOSEC && ST_MTIM(stbuf).tv_nsec == ts->tv_nsec#endif ;}static void mtime_set(const struct stat *stbuf, struct timespec *ts){#ifdef FUSE_STAT_HAS_NANOSEC *ts = ST_MTIM(stbuf);#else ts->tv_sec = stbuf->st_mtime;#endif}#ifndef CLOCK_MONOTONIC#define CLOCK_MONOTONIC CLOCK_REALTIME#endifstatic 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 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; mtime_set(stbuf, &node->mtime); node->size = stbuf->st_size; curr_time(&node->stat_updated);}static int lookup_path(struct fuse *f, fuse_req_t req, 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 && f->op.fgetattr) res = fuse_do_fgetattr(f, req, path, &e->attr, fi); else res = fuse_do_getattr(f, req, 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) { printf(" NODEID: %lu\n", (unsigned long) e->ino); fflush(stdout); } } } 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;}static void fuse_freecontext(void *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;}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);}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; c->ctx.private_data = c->ctx.fuse->user_data; 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);}static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e, 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);}static void fuse_data_init(void *data, struct fuse_conn_info *conn){ struct fuse *f = (struct fuse *) data; struct fuse_context_i *c = fuse_get_context_internal(); memset(c, 0, sizeof(*c)); c->ctx.fuse = f; c->ctx.private_data = f->user_data; if (f->op.init) f->user_data = f->op.init(conn);}static void fuse_data_destroy(void *data){ struct fuse *f = (struct fuse *) data; struct fuse_context_i *c = fuse_get_context_internal(); memset(c, 0, sizeof(*c)); c->ctx.fuse = f; c->ctx.private_data = f->user_data; if (f->op.destroy) f->op.destroy(f->user_data);}static void fuse_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) { if (f->conf.debug) { printf("LOOKUP %s\n", path); fflush(stdout); } err = -ENOSYS; if (f->op.getattr) { err = lookup_path(f, req, 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; } } free(path); } pthread_rwlock_unlock(&f->tree_lock); reply_entry(req, &e, err);}static void fuse_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup){ struct fuse *f = req_fuse(req); if (f->conf.debug) { printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup); fflush(stdout); } forget_node(f, ino, nlookup); fuse_reply_none(req);}static void fuse_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -