From 76c1752f14177a5c56f9cfa5aaac5b346823d47b Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 13 Jul 2005 14:08:19 +0000 Subject: [PATCH] inode based API first working version --- example/.cvsignore | 1 + example/Makefile.am | 2 +- example/hello_ll.c | 170 +++++++++++++++ include/fuse.h | 25 +-- include/fuse_common.h | 28 +-- include/fuse_lowlevel.h | 93 ++++++--- lib/Makefile.am | 1 + lib/fuse_lowlevel.c | 450 ++++++++++++++++++++++++---------------- lib/fuse_versionscript | 19 ++ lib/helper.c | 1 + 10 files changed, 537 insertions(+), 253 deletions(-) create mode 100644 example/hello_ll.c diff --git a/example/.cvsignore b/example/.cvsignore index 80eb82b..56dabc1 100644 --- a/example/.cvsignore +++ b/example/.cvsignore @@ -5,4 +5,5 @@ fusexmp fusexmp_fh null hello +hello_ll .libs diff --git a/example/Makefile.am b/example/Makefile.am index be7a674..8d62e9d 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -noinst_PROGRAMS = fusexmp fusexmp_fh null hello +noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll fusexmp_SOURCES = fusexmp.c fusexmp_fh_SOURCES = fusexmp_fh.c diff --git a/example/hello_ll.c b/example/hello_ll.c new file mode 100644 index 0000000..2739e3a --- /dev/null +++ b/example/hello_ll.c @@ -0,0 +1,170 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2005 Miklos Szeredi + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *hello_str = "Hello World!\n"; +static const char *hello_name = "hello"; + +static int hello_stat(fuse_ino_t ino, struct stat *stbuf) +{ + stbuf->st_ino = ino; + switch (ino) { + case 1: + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + break; + + case 2: + stbuf->st_mode = S_IFREG | 0444; + stbuf->st_nlink = 1; + stbuf->st_size = strlen(hello_str); + break; + + default: + return -1; + } + return 0; +} + +static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino) +{ + struct stat stbuf; + + memset(&stbuf, 0, sizeof(stbuf)); + if (hello_stat(ino, &stbuf) == -1) + fuse_reply_err(req, ENOENT); + else + fuse_reply_attr(req, &stbuf, 1.0); +} + +static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) +{ + struct fuse_entry_param e; + + if (parent != 1 || strcmp(name, hello_name) != 0) + fuse_reply_err(req, ENOENT); + else { + memset(&e, 0, sizeof(e)); + e.ino = 2; + e.attr_timeout = 1.0; + e.entry_timeout = 1.0; + hello_stat(e.ino, &e.attr); + + fuse_reply_entry(req, &e); + } +} + +struct dirbuf { + char *p; + size_t size; +}; + +static void dirbuf_add(struct dirbuf *b, const char *name, fuse_ino_t ino) +{ + struct stat stbuf; + size_t oldsize = b->size; + b->size += fuse_dirent_size(strlen(name)); + b->p = realloc(b->p, b->size); + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_ino = ino; + fuse_add_dirent(b->p + oldsize, name, &stbuf, b->size); +} + +#define min(x, y) ((x) < (y) ? (x) : (y)) + +static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize, + off_t off, size_t maxsize) +{ + + if (off < bufsize) + return fuse_reply_buf(req, buf + off, min(bufsize - off, maxsize)); + else + return fuse_reply_buf(req, NULL, 0); +} + +static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi) +{ + (void) fi; + + if (ino != 1) + fuse_reply_err(req, ENOTDIR); + else { + struct dirbuf b; + + memset(&b, 0, sizeof(b)); + dirbuf_add(&b, ".", 1); + dirbuf_add(&b, "..", 1); + dirbuf_add(&b, hello_name, 2); + reply_buf_limited(req, b.p, b.size, off, size); + free(b.p); + } +} + +static void hello_ll_open(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + if (ino != 2) + fuse_reply_err(req, EISDIR); + else if ((fi->flags & 3) != O_RDONLY) + fuse_reply_err(req, EACCES); + else + fuse_reply_open(req, fi); +} + +static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi) +{ + (void) fi; + + assert(ino == 2); + reply_buf_limited(req, hello_str, strlen(hello_str), off, size); +} + +static struct fuse_ll_operations hello_ll_oper = { + .lookup = hello_ll_lookup, + .getattr = hello_ll_getattr, + .readdir = hello_ll_readdir, + .open = hello_ll_open, + .read = hello_ll_read, +}; + +int main(int argc, char *argv[]) +{ + const char *mountpoint; + struct fuse_ll *f; + int err = -1; + int fd; + + if (argc != 2) { + fprintf(stderr, "usage: %s mountpoint\n", argv[0]); + return 1; + } + mountpoint = argv[1]; + fd = fuse_mount(mountpoint, NULL); + if (fd != -1) { + f = fuse_ll_new(fd, "debug", &hello_ll_oper, sizeof(hello_ll_oper)); + if (f != NULL) { + err = fuse_ll_loop(f); + fuse_ll_destroy(f); + } + close(fd); + } + fuse_unmount(mountpoint); + + return err ? 1 : 0; +} diff --git a/include/fuse.h b/include/fuse.h index 40c9b72..24e8871 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -31,6 +31,8 @@ #error Please add -D_FILE_OFFSET_BITS=64 to your compile flags! #endif +#include "fuse_common.h" + #include #include #include @@ -63,20 +65,6 @@ typedef struct fuse_dirhandle *fuse_dirh_t; typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type, ino_t ino); -/** Information about open files */ -struct fuse_file_info { - /** Open flags. Available in open() and release() */ - int flags; - - /** File handle. May be filled in by filesystem in open(). - Available in all other file operations */ - unsigned long fh; - - /** In case of a write operation indicates if this was caused by a - writepage */ - int writepage; -}; - /** * The file system operations: * @@ -459,12 +447,9 @@ int fuse_loop_mt(struct fuse *f); struct fuse_context *fuse_get_context(void); /** - * Invalidate cached data of a file. - * - * Useful if the 'kernel_cache' mount option is given, since in that - * case the cache is not invalidated on file open. - * - * @return 0 on success or -errno on failure + * Obsolete, doesn't do anything + * + * @return 0 */ int fuse_invalidate(struct fuse *f, const char *path); diff --git a/include/fuse_common.h b/include/fuse_common.h index cd19435..96359ef 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -10,6 +10,9 @@ #error "Never include directly; use or +#include "fuse_common.h" + +#include +#include +#include +#include #ifdef __cplusplus extern "C" { @@ -25,10 +30,9 @@ typedef struct fuse_req *fuse_req_t; struct fuse_entry_param { fuse_ino_t ino; unsigned long generation; - const struct stat *attr; + struct stat attr; double attr_timeout; double entry_timeout; - unsigned int direct_io : 1; }; /* 'to_set' flags in setattr */ @@ -40,9 +44,14 @@ struct fuse_entry_param { #define FUSE_SET_ATTR_MTIME (1 << 5) #define FUSE_SET_ATTR_CTIME (1 << 6) -struct fuse_lowlevel_operations { +/* ------------------------------------------ */ + +struct fuse_ll_operations { + void* (*init) (void); + void (*destroy) (void *); + void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); - void (*forget) (fuse_req_t req, fuse_ino_t ino); + void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); void (*getattr) (fuse_req_t req, fuse_ino_t ino); void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set); @@ -59,22 +68,22 @@ struct fuse_lowlevel_operations { fuse_ino_t newparent, const char *newname); void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname); - void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f); + void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *f); + struct fuse_file_info *fi); void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, - size_t size, off_t off, struct fuse_file_info *f); - void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f); - void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f); + size_t size, off_t off, struct fuse_file_info *fi); + void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); + void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *f); - void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f); + struct fuse_file_info *fi); + void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, - struct fuse_file_info *f); + struct fuse_file_info *fi); void (*releasedir) (fuse_req_t req, fuse_ino_t ino, - struct fuse_file_info *f); + struct fuse_file_info *fi); void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, - struct fuse_file_info *f); + struct fuse_file_info *fi); void (*statfs) (fuse_req_t req, fuse_ino_t ino); void (*setxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags); @@ -84,43 +93,67 @@ struct fuse_lowlevel_operations { void (*removexattr)(fuse_req_t req, fuse_ino_t ino, const char *name); }; -/* all except release and forget */ +/* ------------------------------------------ */ + +/* all except forget */ int fuse_reply_err(fuse_req_t req, int err); -/* forget, unlink, rmdir, rename, setxattr, removexattr, release, releasedir */ -int fuse_reply_ok(fuse_req_t req); +/* forget */ +int fuse_reply_none(fuse_req_t req); /* lookup, mknod, mkdir, symlink, link */ -int fuse_reply_entry(fuse_req_t req, struct fuse_entry_param *e); +int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e); /* getattr, setattr */ -int fuse_reply_attr(fuse_req_t req, int struct stat *attr, double attr_timeout); +int fuse_reply_attr(fuse_req_t req, const struct stat *attr, + double attr_timeout); + /* readlink */ int fuse_reply_readlink(fuse_req_t req, const char *link); -/* open, flush, fsync, opendir, fsyncdir */ -int fuse_reply_file_info(fuse_req_t req, const struct fuse_file_info *f); +/* open, opendir */ +int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi); /* write */ -int fuse_reply_write(fuse_req_t req, size_t count, - const struct fuse_file_info *f); +int fuse_reply_write(fuse_req_t req, size_t count); -/* read, readdir */ -int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size, - const struct fuse_file_info *f); +/* read, readdir, getxattr, listxattr */ +int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size); /* statfs */ int fuse_reply_statfs(fuse_req_t req, const struct statfs *statfs); /* getxattr, listxattr */ -int fuse_reply_xattr(fuse_req_t req, const char *buf, size_t size); +int fuse_reply_xattr(fuse_req_t req, size_t count); + +/* ------------------------------------------ */ /* return the size of a directory entry */ size_t fuse_dirent_size(size_t namelen); /* add a directory entry to the buffer */ -void fuse_add_dirent(char *buf, const char *name, const struct stat *stat, - off_t off); +char *fuse_add_dirent(char *buf, const char *name, const struct stat *stat, + off_t off); + +/* ------------------------------------------ */ + +struct fuse_ll *fuse_ll_new(int fd, const char *opts, + const struct fuse_ll_operations *op, + size_t op_size); + +void fuse_ll_destroy(struct fuse_ll *f); + +int fuse_ll_is_lib_option(const char *opt); + +int fuse_ll_loop(struct fuse_ll *f); + +int fuse_ll_exited(struct fuse_ll* f); + +struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f); + +void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd); + +/* ------------------------------------------ */ #ifdef __cplusplus } diff --git a/lib/Makefile.am b/lib/Makefile.am index 4c68739..e5c356a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -5,6 +5,7 @@ lib_LTLIBRARIES = libfuse.la libfuse_la_SOURCES = \ fuse.c \ fuse_mt.c \ + fuse_lowlevel.c \ helper.c \ mount.c \ fuse_i.h \ diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index f14aeeb..495eb1d 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -6,10 +6,8 @@ See the file COPYING.LIB */ -#include "fuse_i.h" -#include "fuse_compat.h" +#include "fuse_lowlevel.h" #include "fuse_kernel.h" -#include "fuse_kernel_compat5.h" #include #include @@ -28,7 +26,7 @@ struct fuse_ll { unsigned int debug : 1; unsigned int allow_root : 1; int fd; - struct fuse_lowlevel_operations op; + struct fuse_ll_operations op; volatile int exited; int got_init; void *user_data; @@ -42,6 +40,14 @@ struct fuse_cmd { size_t buflen; }; +struct fuse_req { + struct fuse_ll *f; + uint64_t unique; + uid_t uid; + gid_t gid; + pid_t pid; +}; + static const char *opname(enum fuse_opcode opcode) { switch (opcode) { @@ -77,7 +83,7 @@ static const char *opname(enum fuse_opcode opcode) } } -static void convert_stat(struct stat *stbuf, struct fuse_attr *attr) +static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr) { attr->ino = stbuf->st_ino; attr->mode = stbuf->st_mode; @@ -97,6 +103,22 @@ static void convert_stat(struct stat *stbuf, struct fuse_attr *attr) #endif } +static void convert_attr(const struct fuse_attr *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; + stbuf->st_ctime = attr->ctime; +#ifdef HAVE_STRUCT_STAT_ST_ATIM + stbuf->st_atim.tv_nsec = attr->atimensec; + stbuf->st_mtim.tv_nsec = attr->mtimensec; + stbuf->st_ctim.tv_nsec = attr->ctimensec; +#endif +} + static size_t iov_length(const struct iovec *iov, size_t count) { size_t seg; @@ -115,17 +137,12 @@ static int send_reply_raw(struct fuse_ll *f, const struct iovec iov[], struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base; out->len = outsize; - if ((f->flags & FUSE_DEBUG)) { + if (f->debug) { printf(" unique: %llu, error: %i (%s), outsize: %i\n", out->unique, out->error, strerror(-out->error), outsize); fflush(stdout); } - /* This needs to be done before the reply, otherwise the scheduler - could play tricks with us, and only let the counter be - increased long after the operation is done */ - fuse_inc_avail(f); - res = writev(f->fd, iov, count); if (res == -1) { /* ENOENT means the operation was interrupted */ @@ -136,8 +153,8 @@ static int send_reply_raw(struct fuse_ll *f, const struct iovec iov[], return 0; } -static int send_reply(struct fuse_ll *f, struct fuse_in_header *in, int error, - void *arg, size_t argsize) +static int send_reply(struct fuse_ll *f, uint64_t unique, int error, + const void *arg, size_t argsize) { struct fuse_out_header out; struct iovec iov[2]; @@ -148,14 +165,14 @@ static int send_reply(struct fuse_ll *f, struct fuse_in_header *in, int error, error = -ERANGE; } - out.unique = in->unique; + out.unique = unique; out.error = error; count = 1; iov[0].iov_base = &out; iov[0].iov_len = sizeof(struct fuse_out_header); if (argsize && !error) { count++; - iov[1].iov_base = arg; + iov[1].iov_base = (void *) arg; iov[1].iov_len = argsize; } return send_reply_raw(f, iov, count); @@ -166,8 +183,8 @@ size_t fuse_dirent_size(size_t namelen) return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); } -void fuse_add_dirent(char *buf, const char *name, const struct stat *stat, - off_t off) +char *fuse_add_dirent(char *buf, const char *name, const struct stat *stat, + off_t off) { unsigned namelen = strlen(name); unsigned entlen = FUSE_NAME_OFFSET + namelen; @@ -183,10 +200,11 @@ void fuse_add_dirent(char *buf, const char *name, const struct stat *stat, if (padlen) memset(buf + entlen, 0, padlen); - return 0; + return buf + entsize; } -static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs) +static void convert_statfs(const struct statfs *statfs, + struct fuse_kstatfs *kstatfs) { kstatfs->bsize = statfs->f_bsize; kstatfs->blocks = statfs->f_blocks; @@ -197,6 +215,131 @@ static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs) kstatfs->namelen = statfs->f_namelen; } +static void free_req(fuse_req_t req) +{ + free(req); +} + +static int send_reply_req(fuse_req_t req, const void *arg, size_t argsize) +{ + int res = send_reply(req->f, req->unique, 0, arg, argsize); + free_req(req); + return res; +} + +int fuse_reply_err(fuse_req_t req, int err) +{ + int res = send_reply(req->f, req->unique, -err, NULL, 0); + free_req(req); + return res; +} + +int fuse_reply_none(fuse_req_t req) +{ + free_req(req); + return 0; +} + +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; +} + +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); +} + +int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e) +{ + struct fuse_entry_out arg; + + memset(&arg, 0, sizeof(arg)); + 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); + + return send_reply_req(req, &arg, sizeof(arg)); +} + +int fuse_reply_attr(fuse_req_t req, const struct stat *attr, + double attr_timeout) +{ + 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); + + return send_reply_req(req, &arg, sizeof(arg)); +} + +int fuse_reply_readlink(fuse_req_t req, const char *link) +{ + return send_reply_req(req, link, strlen(link)); +} + +int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f) +{ + struct fuse_open_out arg; + + memset(&arg, 0, sizeof(arg)); + arg.fh = f->fh; + + return send_reply_req(req, &arg, sizeof(arg)); +} + +int fuse_reply_write(fuse_req_t req, size_t count) +{ + struct fuse_write_out arg; + + memset(&arg, 0, sizeof(arg)); + arg.size = count; + + return send_reply_req(req, &arg, sizeof(arg)); +} + +int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size) +{ + return send_reply_req(req, buf, size); +} + +int fuse_reply_statfs(fuse_req_t req, const struct statfs *statfs) +{ + struct fuse_statfs_out arg; + + memset(&arg, 0, sizeof(arg)); + convert_statfs(statfs, &arg.st); + + return send_reply_req(req, &arg, sizeof(arg)); +} + +int fuse_reply_xattr(fuse_req_t req, size_t count) +{ + struct fuse_getxattr_out arg; + + memset(&arg, 0, sizeof(arg)); + arg.size = count; + + return send_reply_req(req, &arg, sizeof(arg)); +} + static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name) { if (req->f->op.lookup) @@ -205,10 +348,11 @@ static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name) fuse_reply_err(req, ENOSYS); } -static void do_forget(fuse_req_t req, fuse_ino_t nodeid) +static void do_forget(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_forget_in *arg) { if (req->f->op.forget) - req->f->op.forget(req, nodeid); + req->f->op.forget(req, nodeid, arg->nlookup); } static void do_getattr(fuse_req_t req, fuse_ino_t nodeid) @@ -222,9 +366,11 @@ static void do_getattr(fuse_req_t req, fuse_ino_t nodeid) static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, struct fuse_setattr_in *arg) { - if (req->f->op.setattr) - req->f->op.setattr(req, nodeid, &arg->attr, arg->valid); - else + if (req->f->op.setattr) { + struct stat stbuf; + convert_attr(&arg->attr, &stbuf); + req->f->op.setattr(req, nodeid, &stbuf, arg->valid); + } else fuse_reply_err(req, ENOSYS); } @@ -304,27 +450,26 @@ static void do_open(fuse_req_t req, fuse_ino_t nodeid, struct fuse_open_in *arg) { struct fuse_file_info fi; - + memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; if (req->f->op.open) req->f->op.open(req, nodeid, &fi); else - fuse_reply_err(req, ENOSYS); + fuse_reply_open(req, &fi); } static void do_read(fuse_req_t req, fuse_ino_t nodeid, struct fuse_read_in *arg) { - struct fuse_file_info fi; + if (req->f->op.read) { + struct fuse_file_info fi; - memset(&fi, 0, sizeof(fi)); - fi.fh = arg->fh; - - if (req->f->op.read) + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; req->f->op.read(req, nodeid, arg->size, arg->offset, &fi); - else + } else fuse_reply_err(req, ENOSYS); } @@ -338,7 +483,8 @@ static void do_write(fuse_req_t req, fuse_ino_t nodeid, fi.writepage = arg->write_flags & 1; if (req->f->op.write) - req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi); + req->f->op.write(req, nodeid, PARAM(arg), arg->size, + arg->offset, &fi); else fuse_reply_err(req, ENOSYS); } @@ -369,7 +515,7 @@ static void do_release(fuse_req_t req, fuse_ino_t nodeid, if (req->f->op.release) req->f->op.release(req, nodeid, &fi); else - fuse_reply_err(req, ENOSYS); + fuse_reply_err(req, 0); } static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, @@ -397,7 +543,7 @@ static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, if (req->f->op.opendir) req->f->op.opendir(req, nodeid, &fi); else - fuse_reply_err(req, ENOSYS); + fuse_reply_open(req, &fi); } static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, @@ -426,7 +572,7 @@ static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, if (req->f->op.releasedir) req->f->op.releasedir(req, nodeid, &fi); else - fuse_reply_err(req, ENOSYS); + fuse_reply_err(req, 0); } static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, @@ -446,7 +592,7 @@ static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, static void do_statfs(fuse_req_t req, fuse_ino_t nodeid) { if (req->f->op.statfs) - res = req->f->op.statfs(req, nodeid); + req->f->op.statfs(req, nodeid); else fuse_reply_err(req, ENOSYS); } @@ -458,7 +604,8 @@ static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, unsigned char *value = name + strlen(name) + 1; if (req->f->op.setxattr) - req->f->op.setxattr(req, nodeid, name, value, arg->size, arg->flags); + req->f->op.setxattr(req, nodeid, name, value, arg->size, + arg->flags); else fuse_reply_err(req, ENOSYS); } @@ -489,17 +636,12 @@ static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name) fuse_reply_err(req, ENOSYS); } -static void do_init(struct fuse_ll *f, struct fuse_in_header *in, +static void do_init(struct fuse_ll *f, uint64_t unique, struct fuse_init_in_out *arg) { struct fuse_init_in_out outarg; - if (in->padding == 5) { - arg->minor = arg->major; - arg->major = in->padding; - } - - if (f->flags & FUSE_DEBUG) { + if (f->debug) { printf("INIT: %u.%u\n", arg->major, arg->minor); fflush(stdout); } @@ -507,26 +649,19 @@ static void do_init(struct fuse_ll *f, struct fuse_in_header *in, if (f->op.init) f->user_data = f->op.init(); - if (arg->major == 5) { - f->major = 5; - f->minor = 1; - } else if (arg->major == 6) { - f->major = 6; - f->minor = 1; - } else { - f->major = FUSE_KERNEL_VERSION; - f->minor = FUSE_KERNEL_MINOR_VERSION; - } + f->major = FUSE_KERNEL_VERSION; + f->minor = FUSE_KERNEL_MINOR_VERSION; + memset(&outarg, 0, sizeof(outarg)); outarg.major = f->major; outarg.minor = f->minor; - if (f->flags & FUSE_DEBUG) { + if (f->debug) { printf(" INIT: %u.%u\n", outarg.major, outarg.minor); fflush(stdout); } - send_reply(f, in, 0, &outarg, sizeof(outarg)); + send_reply(f, unique, 0, &outarg, sizeof(outarg)); } static void free_cmd(struct fuse_cmd *cmd) @@ -535,169 +670,172 @@ static void free_cmd(struct fuse_cmd *cmd) free(cmd); } -void fuse_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd) +void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd) { struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf; - void *inarg = cmd->buf + SIZEOF_COMPAT(f, fuse_in_header); - struct fuse_context *ctx = fuse_get_context(); + void *inarg = cmd->buf + sizeof(struct fuse_in_header); + struct fuse_req *req; - fuse_dec_avail(f); - - if ((f->flags & FUSE_DEBUG)) { + if (f->debug) { printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n", in->unique, opname(in->opcode), in->opcode, (unsigned long) in->nodeid, cmd->buflen); fflush(stdout); } - if (!f->got_init && in->opcode != FUSE_INIT) { - /* Old kernel version probably */ - send_reply(f, in, -EPROTO, NULL, 0); + if (!f->got_init) { + if (in->opcode != FUSE_INIT) + send_reply(f, in->unique, -EPROTO, NULL, 0); + else + do_init(f, in->unique, (struct fuse_init_in_out *) inarg); goto out; } - if ((f->flags & FUSE_ALLOW_ROOT) && in->uid != f->owner && in->uid != 0 && + 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) { - send_reply(f, in, -EACCES, NULL, 0); + send_reply(f, in->unique, -EACCES, NULL, 0); goto out; } - ctx->fuse = f; - ctx->uid = in->uid; - ctx->gid = in->gid; - ctx->pid = in->pid; - ctx->private_data = f->user_data; + req = (struct fuse_req *) malloc(sizeof(struct fuse_req)); + if (req == NULL) { + fprintf(stderr, "fuse: failed to allocate request\n"); + goto out; + } + + req->f = f; + req->unique = in->unique; + req->uid = in->uid; + req->gid = in->gid; + req->pid = in->pid; switch (in->opcode) { case FUSE_LOOKUP: - do_lookup(f, req, nodeid, (char *) inarg); + do_lookup(req, in->nodeid, (char *) inarg); break; - do_forget(f, in, (struct fuse_forget_in *) inarg); + case FUSE_FORGET: + do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg); break; - } + case FUSE_GETATTR: - do_getattr(f, in); + do_getattr(req, in->nodeid); break; case FUSE_SETATTR: - do_setattr(f, in, (struct fuse_setattr_in *) inarg); + do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg); break; case FUSE_READLINK: - do_readlink(f, in); + do_readlink(req, in->nodeid); break; case FUSE_MKNOD: - do_mknod(f, in, (struct fuse_mknod_in *) inarg); + do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg); break; case FUSE_MKDIR: - do_mkdir(f, in, (struct fuse_mkdir_in *) inarg); + do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg); break; case FUSE_UNLINK: - do_unlink(f, in, (char *) inarg); + do_unlink(req, in->nodeid, (char *) inarg); break; case FUSE_RMDIR: - do_rmdir(f, in, (char *) inarg); + do_rmdir(req, in->nodeid, (char *) inarg); break; case FUSE_SYMLINK: - do_symlink(f, in, (char *) inarg, + do_symlink(req, in->nodeid, (char *) inarg, ((char *) inarg) + strlen((char *) inarg) + 1); break; case FUSE_RENAME: - do_rename(f, in, (struct fuse_rename_in *) inarg); + do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg); break; case FUSE_LINK: - do_link(f, in, (struct fuse_link_in *) inarg); + do_link(req, in->nodeid, (struct fuse_link_in *) inarg); break; case FUSE_OPEN: - do_open(f, in, (struct fuse_open_in *) inarg); + do_open(req, in->nodeid, (struct fuse_open_in *) inarg); break; case FUSE_FLUSH: - do_flush(f, in, (struct fuse_flush_in *) inarg); + do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg); break; case FUSE_RELEASE: - do_release(f, in, (struct fuse_release_in *) inarg); + do_release(req, in->nodeid, (struct fuse_release_in *) inarg); break; case FUSE_READ: - do_read(f, in, (struct fuse_read_in *) inarg); + do_read(req, in->nodeid, (struct fuse_read_in *) inarg); break; case FUSE_WRITE: - do_write(f, in, (struct fuse_write_in *) inarg); + do_write(req, in->nodeid, (struct fuse_write_in *) inarg); break; case FUSE_STATFS: - do_statfs(f, in); + do_statfs(req, in->nodeid); break; case FUSE_FSYNC: - do_fsync(f, in, (struct fuse_fsync_in *) inarg); + do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg); break; case FUSE_SETXATTR: - do_setxattr(f, in, (struct fuse_setxattr_in *) inarg); + do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg); break; case FUSE_GETXATTR: - do_getxattr(f, in, (struct fuse_getxattr_in *) inarg); + do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg); break; case FUSE_LISTXATTR: - do_listxattr(f, in, (struct fuse_getxattr_in *) inarg); + do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg); break; case FUSE_REMOVEXATTR: - do_removexattr(f, in, (char *) inarg); - break; - - case FUSE_INIT: - do_init(f, in, (struct fuse_init_in_out *) inarg); + do_removexattr(req, in->nodeid, (char *) inarg); break; case FUSE_OPENDIR: - do_opendir(f, in, (struct fuse_open_in *) inarg); + do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg); break; case FUSE_READDIR: - do_readdir(f, in, (struct fuse_read_in *) inarg); + do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg); break; case FUSE_RELEASEDIR: - do_releasedir(f, in, (struct fuse_release_in *) inarg); + do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg); break; case FUSE_FSYNCDIR: - do_fsyncdir(f, in, (struct fuse_fsync_in *) inarg); + do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg); break; default: - send_reply(f, in, -ENOSYS, NULL, 0); + fuse_reply_err(req, ENOSYS); } out: free_cmd(cmd); } -int fuse_exited(struct fuse_ll* f) +int fuse_ll_exited(struct fuse_ll* f) { return f->exited; } -struct fuse_cmd *fuse_read_cmd(struct fuse_ll *f) +struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f) { ssize_t res; struct fuse_cmd *cmd; @@ -716,12 +854,12 @@ struct fuse_cmd *fuse_read_cmd(struct fuse_ll *f) return NULL; } in = (struct fuse_in_header *) cmd->buf; - inarg = cmd->buf + SIZEOF_COMPAT(f, fuse_in_header); + inarg = cmd->buf + sizeof(struct fuse_in_header); res = read(f->fd, cmd->buf, FUSE_MAX_IN); if (res == -1) { free_cmd(cmd); - if (fuse_exited(f) || errno == EINTR || errno == ENOENT) + if (fuse_ll_exited(f) || errno == EINTR || errno == ENOENT) return NULL; /* ENODEV means we got unmounted, so we silenty return failure */ @@ -730,14 +868,14 @@ struct fuse_cmd *fuse_read_cmd(struct fuse_ll *f) perror("fuse: reading device"); } - fuse_exit(f); + f->exited = 1; return NULL; } - if ((size_t) res < SIZEOF_COMPAT(f, fuse_in_header)) { + if ((size_t) res < sizeof(struct fuse_in_header)) { free_cmd(cmd); /* Cannot happen */ fprintf(stderr, "short read on fuse device\n"); - fuse_exit(f); + f->exited = 1; return NULL; } cmd->buflen = res; @@ -746,7 +884,7 @@ struct fuse_cmd *fuse_read_cmd(struct fuse_ll *f) return cmd; } -int fuse_loop(struct fuse_ll *f) +int fuse_ll_loop(struct fuse_ll *f) { if (f == NULL) return -1; @@ -754,69 +892,29 @@ int fuse_loop(struct fuse_ll *f) while (1) { struct fuse_cmd *cmd; - if (fuse_exited(f)) + if (fuse_ll_exited(f)) break; - cmd = fuse_read_cmd(f); + cmd = fuse_ll_read_cmd(f); if (cmd == NULL) continue; - fuse_process_cmd(f, cmd); + fuse_ll_process_cmd(f, cmd); } f->exited = 0; return 0; } -int fuse_invalidate(struct fuse_ll *f, const char *path) -{ - (void) f; - (void) path; - return -EINVAL; -} - -void fuse_exit(struct fuse_ll *f) -{ - f->exited = 1; -} - -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; -} - -static int begins_with(const char *s, const char *beg) -{ - if (strncmp(s, beg, strlen(beg)) == 0) - return 1; - else - return 0; -} - -int fuse_is_lib_option(const char *opt) +int fuse_ll_is_lib_option(const char *opt) { if (strcmp(opt, "debug") == 0 || - strcmp(opt, "hard_remove") == 0 || - strcmp(opt, "use_ino") == 0 || - strcmp(opt, "allow_root") == 0 || - strcmp(opt, "readdir_ino") == 0 || - begins_with(opt, "umask=") || - begins_with(opt, "uid=") || - begins_with(opt, "gid=")) + strcmp(opt, "allow_root") == 0) return 1; else return 0; } -static int parse_lib_opts(struct fuse_ll *f, const char *opts) +static int parse_ll_opts(struct fuse_ll *f, const char *opts) { if (opts) { char *xopts = strdup(opts); @@ -830,21 +928,9 @@ static int parse_lib_opts(struct fuse_ll *f, const char *opts) while((opt = strsep(&s, ","))) { if (strcmp(opt, "debug") == 0) - f->flags |= FUSE_DEBUG; - else if (strcmp(opt, "hard_remove") == 0) - f->flags |= FUSE_HARD_REMOVE; - else if (strcmp(opt, "use_ino") == 0) - f->flags |= FUSE_USE_INO; + f->debug = 1; else if (strcmp(opt, "allow_root") == 0) - f->flags |= FUSE_ALLOW_ROOT; - else if (strcmp(opt, "readdir_ino") == 0) - f->flags |= FUSE_READDIR_INO; - else if (sscanf(opt, "umask=%o", &f->umask) == 1) - f->flags |= FUSE_SET_MODE; - else if (sscanf(opt, "uid=%u", &f->uid) == 1) - f->flags |= FUSE_SET_UID; - else if(sscanf(opt, "gid=%u", &f->gid) == 1) - f->flags |= FUSE_SET_GID; + f->allow_root = 1; else fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt); } @@ -853,15 +939,15 @@ static int parse_lib_opts(struct fuse_ll *f, const char *opts) return 0; } -struct fuse_ll *fuse_lowlevel_new(int fd, const char *opts, - const struct fuse_lowlevel_operations *op, - size_t op_size) +struct fuse_ll *fuse_ll_new(int fd, const char *opts, + const struct fuse_ll_operations *op, + size_t op_size) { struct fuse_ll *f; - if (sizeof(struct fuse_lowlevel_operations) < op_size) { + if (sizeof(struct fuse_ll_operations) < op_size) { fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); - op_size = sizeof(struct fuse_lowlevel_operations); + op_size = sizeof(struct fuse_ll_operations); } f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); @@ -870,7 +956,7 @@ struct fuse_ll *fuse_lowlevel_new(int fd, const char *opts, goto out; } - if (parse_lib_opts(f, opts) == -1) + if (parse_ll_opts(f, opts) == -1) goto out_free; f->fd = fd; @@ -886,4 +972,8 @@ struct fuse_ll *fuse_lowlevel_new(int fd, const char *opts, return NULL; } +void fuse_ll_destroy(struct fuse_ll *f) +{ + free(f); +} diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index edbed43..1068265 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -1,11 +1,20 @@ FUSE_2.2 { global: + fuse_add_dirent; fuse_destroy; + fuse_dirent_size; fuse_exit; fuse_exited; fuse_get_context; fuse_invalidate; fuse_is_lib_option; + fuse_ll_new; + fuse_ll_destroy; + fuse_ll_is_lib_option; + fuse_ll_loop; + fuse_ll_exited; + fuse_ll_read_cmd; + fuse_ll_process_cmd; fuse_loop; fuse_loop_mt; fuse_loop_mt_proc; @@ -20,6 +29,16 @@ FUSE_2.2 { fuse_new_compat2; fuse_process_cmd; fuse_read_cmd; + fuse_reply_err; + fuse_reply_none; + fuse_reply_entry; + fuse_reply_attr; + fuse_reply_readlink; + fuse_reply_open; + fuse_reply_write; + fuse_reply_buf; + fuse_reply_statfs; + fuse_reply_xattr; fuse_set_getcontext_func; fuse_setup; fuse_setup_compat2; diff --git a/lib/helper.c b/lib/helper.c index 13f3ca2..d5c63f2 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -289,6 +289,7 @@ static int fuse_parse_cmdline(int argc, const char *argv[], char **kernel_opts, } static struct fuse *fuse_setup_common(int argc, char *argv[], + const struct fuse_operations *op, size_t op_size, char **mountpoint, -- 2.30.2