📄 fuse_lowlevel.c
字号:
} fflush(stdout); } 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) { printf(" INIT: %u.%u\n", outarg.major, outarg.minor); printf(" flags=0x%08x\n", outarg.flags); printf(" max_readahead=0x%08x\n", outarg.max_readahead); printf(" max_write=0x%08x\n", outarg.max_write); fflush(stdout); } 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; (void) nodeid; (void) inarg; f->got_destroy = 1; if (f->op.destroy) f->op.destroy(f->userdata); send_reply_ok(req, NULL, 0);}void *fuse_req_userdata(fuse_req_t req){ return req->f->userdata;}const struct fuse_ctx *fuse_req_ctx(fuse_req_t req){ return &req->ctx;}void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, 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);}int fuse_req_interrupted(fuse_req_t req){ int interrupted; pthread_mutex_lock(&req->f->lock); interrupted = req->interrupted; pthread_mutex_unlock(&req->f->lock); return interrupted;}static struct { 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" },};#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;}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) { printf("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); fflush(stdout); } 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,};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};static void fuse_ll_version(void){ 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");}static int fuse_ll_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs){ (void) data; (void) outargs; switch (key) { case KEY_HELP: fuse_ll_help(); break; case KEY_VERSION: fuse_ll_version(); break; default: fprintf(stderr, "fuse: unknown option `%s'\n", arg); } return -1;}int fuse_lowlevel_is_lib_option(const char *opt){ return fuse_opt_match(fuse_ll_opts, opt);}static void fuse_ll_destroy(void *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); } pthread_mutex_destroy(&f->lock); free(f);}/* * always call fuse_lowlevel_new_common() internally, to work around a * misfeature in the FreeBSD runtime linker, which links the old * 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){ 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); } 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); 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; se = fuse_session_new(&sop, f); if (!se) goto out_free; return se; 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){ 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){ 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){ 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){ struct fuse_open_out 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; memset(&newbuf, 0, sizeof(newbuf)); convert_statfs_compat(stbuf, &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){ 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); return se;}struct fuse_ll_compat_conf { 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};int fuse_sync_compat_args(struct fuse_args *args){ 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; if (fuse_opt_insert_arg(args, 1, "-osync_read")) return -1; 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;}__asm__(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");__asm__(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");__asm__(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4");#else /* __FreeBSD__ */int fuse_sync_compat_args(struct fuse_args *args){ (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){ if (fuse_sync_compat_args(args) == -1) return NULL; return fuse_lowlevel_new_common(args, (const struct fuse_lowlevel_ops *) op, op_size, userdata);}__asm__(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -