📄 fuse.c
字号:
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);}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;}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; 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);}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);}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(); 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); free(fs);}static void fuse_lib_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; 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);}static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino, 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);}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);}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;}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);}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);}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);}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);}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);}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);}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);}static void fuse_lib_symlink(fuse_req_t req, const char *linkname, fuse_ino_t parent, const char *name){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -