📄 fuse.c
字号:
static void fuse_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, ino, list, size); if (res > 0) fuse_reply_buf(req, list, res); else reply_err(req, res); free(list); } else { res = common_listxattr(f, ino, NULL, 0); if (res >= 0) fuse_reply_xattr(req, res); else reply_err(req, res); }}static void fuse_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) { err = -ENOSYS; if (f->op.removexattr) err = f->op.removexattr(path, name); free(path); } pthread_rwlock_unlock(&f->tree_lock); reply_err(req, err);}static struct fuse_lowlevel_ops fuse_path_ops = { .init = fuse_data_init, .destroy = fuse_data_destroy, .lookup = fuse_lookup, .forget = fuse_forget, .getattr = fuse_getattr, .setattr = fuse_setattr, .access = fuse_access, .readlink = fuse_readlink, .mknod = fuse_mknod, .mkdir = fuse_mkdir, .unlink = fuse_unlink, .rmdir = fuse_rmdir, .symlink = fuse_symlink, .rename = fuse_rename, .link = fuse_link, .create = fuse_create, .open = fuse_open, .read = fuse_read, .write = fuse_write, .flush = fuse_flush, .release = fuse_release, .fsync = fuse_fsync, .opendir = fuse_opendir, .readdir = fuse_readdir, .releasedir = fuse_releasedir, .fsyncdir = fuse_fsyncdir, .statfs = fuse_statfs, .setxattr = fuse_setxattr, .getxattr = fuse_getxattr, .listxattr = fuse_listxattr, .removexattr = fuse_removexattr,};static void free_cmd(struct fuse_cmd *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);}int fuse_exited(struct fuse *f){ return fuse_session_exited(f->se);}struct fuse_session *fuse_get_session(struct fuse *f){ 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 *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_receive(ch, cmd->buf, bufsize); if (res <= 0) { free_cmd(cmd); if (res == -1) 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;}int fuse_invalidate(struct fuse *f, const char *path){ (void) f; (void) path; return -EINVAL;}void fuse_exit(struct fuse *f){ fuse_session_exit(f->se);}struct fuse_context *fuse_get_context(){ static struct fuse_context context; if (fuse_getcontext) return fuse_getcontext(); else return &context;}void fuse_set_getcontext_func(struct fuse_context *(*func)(void)){ fuse_getcontext = func;}enum { KEY_HELP, KEY_KEEP};#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", KEY_KEEP), FUSE_OPT_KEY("-d", 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("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("negative_timeout=%lf", negative_timeout, 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 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" "\n");}static int fuse_lib_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs){ (void) data; (void) arg; (void) outargs; if (key == KEY_HELP) fuse_lib_help(); return 1;}int fuse_is_lib_option(const char *opt){ return fuse_lowlevel_is_lib_option(opt) || fuse_opt_match(fuse_lib_opts, opt);}struct fuse *fuse_new_common(int fd, struct fuse_args *args, const struct fuse_operations *op, size_t op_size, int compat){ struct fuse_chan *ch; struct fuse *f; struct node *root; 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); } f = (struct fuse *) calloc(1, sizeof(struct fuse)); if (f == NULL) { fprintf(stderr, "fuse: failed to allocate fuse object\n"); goto out; } f->conf.entry_timeout = 1.0; f->conf.attr_timeout = 1.0; f->conf.negative_timeout = 0.0; if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1) goto out_free;#ifdef __FreeBSD__ /* * In FreeBSD, we always use these settings as inode numbers are needed to * make getcwd(3) work. */ f->conf.readdir_ino = 1;#endif f->se = fuse_lowlevel_new(args, &fuse_path_ops, sizeof(fuse_path_ops), f); if (f->se == NULL) goto out_free; ch = fuse_kern_chan_new(fd); if (ch == NULL) goto out_free_session; 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; } mutex_init(&f->lock); memcpy(&f->op, op, op_size); f->compat = compat; 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; } root->parent = 0; root->nodeid = FUSE_ROOT_ID; root->generation = 0; root->refctr = 1; root->nlookup = 1; hash_id(f, root); return f; 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: free(f); out: return NULL;}struct fuse *fuse_new(int fd, struct fuse_args *args, const struct fuse_operations *op, size_t op_size){ return fuse_new_common(fd, args, op, op_size, 0);}void fuse_destroy(struct fuse *f){ size_t i; 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) { f->op.unlink(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); fuse_session_destroy(f->se); free(f);}#ifndef __FreeBSD__#include "fuse_compat.h"static int fuse_do_open(struct fuse *f, char *path, struct fuse_file_info *fi){ if (!f->compat) return f->op.open(path, fi); else if (f->compat == 22) { int err; struct fuse_file_info_compat22 tmp; memcpy(&tmp, fi, sizeof(tmp)); err = ((struct fuse_operations_compat22 *) &f->op)->open(path, &tmp); memcpy(fi, &tmp, sizeof(tmp)); fi->fh = tmp.fh; return err; } else return ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);}static void fuse_do_release(struct fuse *f, char *path, struct fuse_file_info *fi){ if (!f->compat || f->compat >= 22) f->op.release(path ? path : "-", fi); else if (path) ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);}static int fuse_do_opendir(struct fuse *f, char *path, struct fuse_file_info *fi){ if (!f->compat) { return f->op.opendir(path, fi); } else { int err; struct fuse_file_info_compat22 tmp; memcpy(&tmp, fi, sizeof(tmp)); err = ((struct fuse_operations_compat22 *) &f->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){ 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;}static int fuse_do_statfs(struct fuse *f, char *path, struct statvfs *buf){ int err; if (!f->compat) { err = f->op.statfs(path, buf); } else if (f->compat > 11) { struct statfs oldbuf; err = ((struct fuse_operations_compat22 *) &f->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 *) &f->op)->statfs(&compatbuf); if (!err) convert_statfs_compat(&compatbuf, buf); } return err;}static struct fuse *fuse_new_common_compat(int fd, const char *opts, const struct fuse_operations *op, size_t op_size, int compat){ struct fuse *f; 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; } f = fuse_new_common(fd, &args, op, op_size, compat); fuse_opt_free_args(&args); return f;}struct fuse *fuse_new_compat22(int fd, const char *opts, const struct fuse_operations_compat22 *op, size_t op_size){ 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){ 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 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);}__asm__(".symver fuse_exited,__fuse_exited@");__asm__(".symver fuse_process_cmd,__fuse_process_cmd@");__asm__(".symver fuse_read_cmd,__fuse_read_cmd@");__asm__(".symver fuse_set_getcontext_func,__fuse_set_getcontext_func@");__asm__(".symver fuse_new_compat2,fuse_new@");__asm__(".symver fuse_new_compat22,fuse_new@FUSE_2.2");#else /* __FreeBSD__ */static int fuse_do_open(struct fuse *f, char *path, struct fuse_file_info *fi){ return f->op.open(path, fi);}static void fuse_do_release(struct fuse *f, char *path, struct fuse_file_info *fi){ f->op.release(path ? path : "-", fi);}static int fuse_do_opendir(struct fuse *f, char *path, struct fuse_file_info *fi){ return f->op.opendir(path, fi);}static int fuse_do_statfs(struct fuse *f, char *path, struct statvfs *buf){ return f->op.statfs(path, buf);}#endif /* __FreeBSD__ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -