inode based API first working version
diff --git a/example/.cvsignore b/example/.cvsignore
index 80eb82b..56dabc1 100644
--- a/example/.cvsignore
+++ b/example/.cvsignore
@@ -5,4 +5,5 @@
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 <miklos@szeredi.hu>
+
+ This program can be distributed under the terms of the GNU GPL.
+ See the file COPYING.
+*/
+
+#include <fuse_lowlevel.h>
+#include <fuse.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+
+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 <sys/types.h>
#include <sys/stat.h>
#include <sys/statfs.h>
@@ -63,20 +65,6 @@
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 @@
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 <fuse_common.h> directly; use <fuse.h> or <fuse_lowlevel.h instead."
#endif
+#ifndef _FUSE_COMMON_H_
+#define _FUSE_COMMON_H_
+
/** Information about open files */
struct fuse_file_info {
/** Open flags. Available in open() and release() */
@@ -22,28 +25,9 @@
/** In case of a write operation indicates if this was caused by a
writepage */
int writepage;
+
+ /** Can be filled in by open, to use direct I/O on this file */
+ unsigned int direct_io : 1;
};
-/** Extra context that may be needed by some filesystems
- *
- * The uid, gid and pid fields are not filled in case of a writepage
- * operation.
- */
-struct fuse_context {
- /** Pointer to the fuse object */
- struct fuse *fuse;
-
- /** User ID of the calling process */
- uid_t uid;
-
- /** Group ID of the calling process */
- gid_t gid;
-
- /** Thread ID of the calling process */
- pid_t pid;
-
- /** Private filesystem data */
- void *private_data;
-};
-
-
+#endif /* _FUSE_COMMON_H_ */
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index 673493e..0881ac8 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -13,7 +13,12 @@
* Low level API *
* ----------------------------------------------------------- */
-#include <fuse_common.h>
+#include "fuse_common.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <utime.h>
#ifdef __cplusplus
extern "C" {
@@ -25,10 +30,9 @@
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 @@
#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 @@
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 @@
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 @@
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 <stdio.h>
#include <string.h>
@@ -28,7 +26,7 @@
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 @@
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 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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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 struct fuse *fuse_setup_common(int argc, char *argv[],
+
const struct fuse_operations *op,
size_t op_size,
char **mountpoint,