aboutsummaryrefslogtreecommitdiff
path: root/lib/fuse.c
diff options
context:
space:
mode:
authorGravatar Miklos Szeredi <miklos@szeredi.hu>2005-07-15 09:59:59 +0000
committerGravatar Miklos Szeredi <miklos@szeredi.hu>2005-07-15 09:59:59 +0000
commitbd10a7b16f10c1a5f61a4531c8631048e00fa230 (patch)
tree3662bd63e8b6b4946a757f73ac65c47a32b63beb /lib/fuse.c
parent163581a2d291cf8b7d93e9e58756a43c8209af1c (diff)
added lowlevel API
Diffstat (limited to 'lib/fuse.c')
-rw-r--r--lib/fuse.c1791
1 files changed, 660 insertions, 1131 deletions
diff --git a/lib/fuse.c b/lib/fuse.c
index 45ea1b3..b93ded3 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -8,8 +8,6 @@
#include "fuse_i.h"
#include "fuse_compat.h"
-#include "fuse_kernel.h"
-#include "fuse_kernel_compat5.h"
#include <stdio.h>
#include <string.h>
@@ -34,9 +32,6 @@
/** Use st_ino field in getattr instead of generating inode numbers */
#define FUSE_USE_INO (1 << 3)
-/** Only allow root or the owner to access the filesystem */
-#define FUSE_ALLOW_ROOT (1 << 4)
-
/** Make a best effort to fill in inode number in a readdir **/
#define FUSE_READDIR_INO (1 << 5)
@@ -54,30 +49,18 @@
#define FUSE_MAX_PATH 4096
-#define PARAM_T(inarg, type) (((char *)(inarg)) + sizeof(type))
-#define PARAM(inarg) PARAM_T(inarg, *(inarg))
-#define PARAM_COMPAT(f, inarg, type) \
- ((f)->major == 5 ? PARAM_T(inarg, struct type ## _compat5) : PARAM(inarg))
-
-#define MEMBER_COMPAT(f, ptr, memb, type) \
- ((f)->major == 5 ? &((struct type ## _compat5 *) (ptr))->memb : &ptr->memb)
-
-#define SIZEOF_COMPAT(f, type) \
- ((f)->major == 5 ? sizeof(struct type ## _compat5) : sizeof(struct type))
-
-#define ENTRY_REVALIDATE_TIME 1 /* sec */
-#define ATTR_REVALIDATE_TIME 1 /* sec */
+#define ENTRY_REVALIDATE_TIME 1.0 /* sec */
+#define ATTR_REVALIDATE_TIME 1.0 /* sec */
struct node {
struct node *name_next;
struct node *id_next;
- nodeid_t nodeid;
+ fuse_ino_t nodeid;
unsigned int generation;
int refctr;
- nodeid_t parent;
+ fuse_ino_t parent;
char *name;
- uint64_t version;
uint64_t nlookup;
int open_count;
int is_hidden;
@@ -93,15 +76,9 @@ struct fuse_dirhandle {
int filled;
unsigned long fh;
int error;
- nodeid_t nodeid;
+ fuse_ino_t nodeid;
};
-struct fuse_cmd {
- char *buf;
- size_t buflen;
-};
-
-
static struct fuse_context *(*fuse_getcontext)(void) = NULL;
#ifndef USE_UCLIBC
@@ -117,56 +94,7 @@ static void mutex_init(pthread_mutex_t *mut)
}
#endif
-static const char *opname(enum fuse_opcode opcode)
-{
- switch (opcode) {
- case FUSE_LOOKUP: return "LOOKUP";
- case FUSE_FORGET: return "FORGET";
- case FUSE_GETATTR: return "GETATTR";
- case FUSE_SETATTR: return "SETATTR";
- case FUSE_READLINK: return "READLINK";
- case FUSE_SYMLINK: return "SYMLINK";
- case FUSE_MKNOD: return "MKNOD";
- case FUSE_MKDIR: return "MKDIR";
- case FUSE_UNLINK: return "UNLINK";
- case FUSE_RMDIR: return "RMDIR";
- case FUSE_RENAME: return "RENAME";
- case FUSE_LINK: return "LINK";
- case FUSE_OPEN: return "OPEN";
- case FUSE_READ: return "READ";
- case FUSE_WRITE: return "WRITE";
- case FUSE_STATFS: return "STATFS";
- case FUSE_FLUSH: return "FLUSH";
- case FUSE_RELEASE: return "RELEASE";
- case FUSE_FSYNC: return "FSYNC";
- case FUSE_SETXATTR: return "SETXATTR";
- case FUSE_GETXATTR: return "GETXATTR";
- case FUSE_LISTXATTR: return "LISTXATTR";
- case FUSE_REMOVEXATTR: return "REMOVEXATTR";
- case FUSE_INIT: return "INIT";
- case FUSE_OPENDIR: return "OPENDIR";
- case FUSE_READDIR: return "READDIR";
- case FUSE_RELEASEDIR: return "RELEASEDIR";
- case FUSE_FSYNCDIR: return "FSYNCDIR";
- default: return "???";
- }
-}
-
-static inline void fuse_dec_avail(struct fuse *f)
-{
- pthread_mutex_lock(&f->worker_lock);
- f->numavail --;
- pthread_mutex_unlock(&f->worker_lock);
-}
-
-static inline void fuse_inc_avail(struct fuse *f)
-{
- pthread_mutex_lock(&f->worker_lock);
- f->numavail ++;
- pthread_mutex_unlock(&f->worker_lock);
-}
-
-static struct node *get_node_nocheck(struct fuse *f, nodeid_t nodeid)
+static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
{
size_t hash = nodeid % f->id_table_size;
struct node *node;
@@ -178,7 +106,7 @@ static struct node *get_node_nocheck(struct fuse *f, nodeid_t nodeid)
return NULL;
}
-static struct node *get_node(struct fuse *f, nodeid_t nodeid)
+static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
{
struct node *node = get_node_nocheck(f, nodeid);
if (!node) {
@@ -214,7 +142,7 @@ static void hash_id(struct fuse *f, struct node *node)
f->id_table[hash] = node;
}
-static unsigned int name_hash(struct fuse *f, nodeid_t parent, const char *name)
+static unsigned int name_hash(struct fuse *f, fuse_ino_t parent, const char *name)
{
unsigned int hash = *name;
@@ -249,7 +177,7 @@ static void unhash_name(struct fuse *f, struct node *node)
}
}
-static int hash_name(struct fuse *f, struct node *node, nodeid_t parent,
+static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parent,
const char *name)
{
size_t hash = name_hash(f, parent, name);
@@ -283,7 +211,7 @@ static void unref_node(struct fuse *f, struct node *node)
delete_node(f, node);
}
-static nodeid_t next_id(struct fuse *f)
+static fuse_ino_t next_id(struct fuse *f)
{
do {
f->ctr++;
@@ -293,7 +221,7 @@ static nodeid_t next_id(struct fuse *f)
return f->ctr;
}
-static struct node *lookup_node(struct fuse *f, nodeid_t parent,
+static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
const char *name)
{
size_t hash = name_hash(f, parent, name);
@@ -306,8 +234,8 @@ static struct node *lookup_node(struct fuse *f, nodeid_t parent,
return NULL;
}
-static struct node *find_node(struct fuse *f, nodeid_t parent, char *name,
- uint64_t version)
+static struct node *find_node(struct fuse *f, fuse_ino_t parent,
+ const char *name)
{
struct node *node;
@@ -330,7 +258,6 @@ static struct node *find_node(struct fuse *f, nodeid_t parent, char *name,
}
hash_id(f, node);
}
- node->version = version;
node->nlookup ++;
out_err:
pthread_mutex_unlock(&f->lock);
@@ -352,7 +279,7 @@ static char *add_name(char *buf, char *s, const char *name)
return s;
}
-static char *get_path_name(struct fuse *f, nodeid_t nodeid, const char *name)
+static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
{
char buf[FUSE_MAX_PATH];
char *s = buf + FUSE_MAX_PATH - 1;
@@ -388,12 +315,12 @@ static char *get_path_name(struct fuse *f, nodeid_t nodeid, const char *name)
return strdup(s);
}
-static char *get_path(struct fuse *f, nodeid_t nodeid)
+static char *get_path(struct fuse *f, fuse_ino_t nodeid)
{
return get_path_name(f, nodeid, NULL);
}
-static void forget_node(struct fuse *f, nodeid_t nodeid, uint64_t nlookup)
+static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
{
struct node *node;
if (nodeid == FUSE_ROOT_ID)
@@ -409,29 +336,7 @@ static void forget_node(struct fuse *f, nodeid_t nodeid, uint64_t nlookup)
pthread_mutex_unlock(&f->lock);
}
-static void forget_node_old(struct fuse *f, nodeid_t nodeid, uint64_t version)
-{
- struct node *node;
-
- pthread_mutex_lock(&f->lock);
- node = get_node_nocheck(f, nodeid);
- if (node && node->version == version && nodeid != FUSE_ROOT_ID) {
- node->version = 0;
- unhash_name(f, node);
- unref_node(f, node);
- }
- pthread_mutex_unlock(&f->lock);
-}
-
-static void cancel_lookup(struct fuse *f, nodeid_t nodeid, uint64_t version)
-{
- if (f->major <= 6)
- forget_node_old(f, nodeid, version);
- else
- forget_node(f, nodeid, 1);
-}
-
-static void remove_node(struct fuse *f, nodeid_t dir, const char *name)
+static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
{
struct node *node;
@@ -442,8 +347,8 @@ static void remove_node(struct fuse *f, nodeid_t dir, const char *name)
pthread_mutex_unlock(&f->lock);
}
-static int rename_node(struct fuse *f, nodeid_t olddir, const char *oldname,
- nodeid_t newdir, const char *newname, int hide)
+static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
+ fuse_ino_t newdir, const char *newname, int hide)
{
struct node *node;
struct node *newnode;
@@ -478,94 +383,19 @@ static int rename_node(struct fuse *f, nodeid_t olddir, const char *oldname,
return err;
}
-static void convert_stat(struct fuse *f, nodeid_t nodeid, struct stat *stbuf,
- struct fuse_attr *attr)
+static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
{
- attr->ino = (f->flags & FUSE_USE_INO) ? stbuf->st_ino : nodeid;
- attr->mode = stbuf->st_mode;
+ if (!(f->flags & FUSE_USE_INO))
+ stbuf->st_ino = nodeid;
if (f->flags & FUSE_SET_MODE)
- attr->mode = (attr->mode & S_IFMT) | (0777 & ~f->umask);
- attr->nlink = stbuf->st_nlink;
- attr->uid = (f->flags & FUSE_SET_UID) ? f->uid : stbuf->st_uid;
- attr->gid = (f->flags & FUSE_SET_GID) ? f->gid : stbuf->st_gid;
- attr->rdev = stbuf->st_rdev;
- attr->size = stbuf->st_size;
- attr->blocks = stbuf->st_blocks;
- attr->atime = stbuf->st_atime;
- attr->mtime = stbuf->st_mtime;
- attr->ctime = stbuf->st_ctime;
-#ifdef HAVE_STRUCT_STAT_ST_ATIM
- attr->atimensec = stbuf->st_atim.tv_nsec;
- attr->mtimensec = stbuf->st_mtim.tv_nsec;
- attr->ctimensec = stbuf->st_ctim.tv_nsec;
-#endif
+ stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->umask);
+ if (f->flags & FUSE_SET_UID)
+ stbuf->st_uid = f->uid;
+ if (f->flags & FUSE_SET_GID)
+ stbuf->st_gid = f->gid;
}
-static size_t iov_length(const struct iovec *iov, size_t count)
-{
- size_t seg;
- size_t ret = 0;
-
- for (seg = 0; seg < count; seg++)
- ret += iov[seg].iov_len;
- return ret;
-}
-
-static int send_reply_raw(struct fuse *f, const struct iovec iov[],
- size_t count)
-{
- int res;
- unsigned outsize = iov_length(iov, count);
- struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base;
- out->len = outsize;
-
- if ((f->flags & FUSE_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 */
- if (!f->exited && errno != ENOENT)
- perror("fuse: writing device");
- return -errno;
- }
- return 0;
-}
-
-static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
- void *arg, size_t argsize)
-{
- struct fuse_out_header out;
- struct iovec iov[2];
- size_t count;
-
- if (error <= -1000 || error > 0) {
- fprintf(stderr, "fuse: bad error value: %i\n", error);
- error = -ERANGE;
- }
-
- out.unique = in->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_len = argsize;
- }
- return send_reply_raw(f, iov, count);
-}
-
-static int is_open(struct fuse *f, nodeid_t dir, const char *name)
+static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
{
struct node *node;
int isopen = 0;
@@ -577,7 +407,7 @@ static int is_open(struct fuse *f, nodeid_t dir, const char *name)
return isopen;
}
-static char *hidden_name(struct fuse *f, nodeid_t dir, const char *oldname,
+static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname,
char *newname, size_t bufsize)
{
struct stat buf;
@@ -619,7 +449,7 @@ static char *hidden_name(struct fuse *f, nodeid_t dir, const char *oldname,
return newpath;
}
-static int hide_node(struct fuse *f, const char *oldpath, nodeid_t dir,
+static int hide_node(struct fuse *f, const char *oldpath, fuse_ino_t dir,
const char *oldname)
{
char newname[64];
@@ -638,31 +468,27 @@ static int hide_node(struct fuse *f, const char *oldpath, nodeid_t dir,
return err;
}
-static int lookup_path(struct fuse *f, nodeid_t nodeid, uint64_t version,
- char *name, const char *path,
- struct fuse_entry_out *arg)
+static int lookup_path(struct fuse *f, fuse_ino_t nodeid, const char *name,
+ const char *path, struct fuse_entry_param *e)
{
int res;
- struct stat buf;
- res = f->op.getattr(path, &buf);
+ memset(e, 0, sizeof(struct fuse_entry_param));
+ res = f->op.getattr(path, &e->attr);
if (res == 0) {
struct node *node;
- node = find_node(f, nodeid, name, version);
+ node = find_node(f, nodeid, name);
if (node == NULL)
res = -ENOMEM;
else {
- memset(arg, 0, sizeof(struct fuse_entry_out));
- convert_stat(f, node->nodeid, &buf, &arg->attr);
- arg->nodeid = node->nodeid;
- arg->generation = node->generation;
- arg->entry_valid = ENTRY_REVALIDATE_TIME;
- arg->entry_valid_nsec = 0;
- arg->attr_valid = ATTR_REVALIDATE_TIME;
- arg->attr_valid_nsec = 0;
+ e->ino = node->nodeid;
+ e->generation = node->generation;
+ e->entry_timeout = ENTRY_REVALIDATE_TIME;
+ e->attr_timeout = ATTR_REVALIDATE_TIME;
+ set_stat(f, e->ino, &e->attr);
if (f->flags & FUSE_DEBUG) {
- printf(" NODEID: %lu\n", (unsigned long) arg->nodeid);
+ printf(" NODEID: %lu\n", (unsigned long) e->ino);
fflush(stdout);
}
}
@@ -670,346 +496,375 @@ static int lookup_path(struct fuse *f, nodeid_t nodeid, uint64_t version,
return res;
}
-static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
+static struct fuse *req_fuse(fuse_req_t req)
{
- int res;
- int res2;
+ return (struct fuse *) fuse_req_userdata(req);
+}
+
+static struct fuse *req_fuse_prepare(fuse_req_t req)
+{
+ struct fuse_context *c = fuse_get_context();
+ const struct fuse_ctx *ctx = fuse_req_ctx(req);
+ c->fuse = req_fuse(req);
+ c->uid = ctx->uid;
+ c->gid = ctx->gid;
+ c->pid = ctx->pid;
+ c->private_data = c->fuse->user_data;
+
+ return c->fuse;
+}
+
+static inline void reply_err(fuse_req_t req, int err)
+{
+ /* fuse_reply_err() uses non-negated errno values */
+ fuse_reply_err(req, -err);
+}
+
+static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
+ int err)
+{
+ if (!err) {
+ if (fuse_reply_entry(req, e) == -ENOENT)
+ forget_node(req_fuse(req), e->ino, 1);
+ } else
+ reply_err(req, err);
+}
+
+static void *fuse_data_init(void *data)
+{
+ struct fuse *f = (struct fuse *) data;
+
+ if (f->op.init)
+ f->user_data = f->op.init();
+
+ return f;
+}
+
+static void fuse_data_destroy(void *data)
+{
+ struct fuse *f = (struct fuse *) data;
+
+ if (f->op.destroy)
+ f->op.destroy(f->user_data);
+}
+
+static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
+{
+ struct fuse *f = req_fuse_prepare(req);
+ struct fuse_entry_param e;
char *path;
- struct fuse_entry_out arg;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path_name(f, in->nodeid, name);
+ path = get_path_name(f, parent, name);
if (path != NULL) {
if (f->flags & FUSE_DEBUG) {
printf("LOOKUP %s\n", path);
fflush(stdout);
}
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.getattr)
- res = lookup_path(f, in->nodeid, in->unique, name, path, &arg);
+ err = lookup_path(f, parent, name, path, &e);
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- res2 = send_reply(f, in, res, &arg, sizeof(arg));
- if (res == 0 && res2 == -ENOENT)
- cancel_lookup(f, arg.nodeid, in->unique);
+ reply_entry(req, &e, err);
}
-static void do_forget(struct fuse *f, struct fuse_in_header *in,
- struct fuse_forget_in *arg)
+static void fuse_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
{
+ struct fuse *f = req_fuse(req);
if (f->flags & FUSE_DEBUG) {
- printf("FORGET %lu/%llu\n", (unsigned long) in->nodeid,
- arg->nlookup);
+ printf("FORGET %lu/%lu\n", ino, nlookup);
fflush(stdout);
}
- if (f->major <= 6)
- forget_node_old(f, in->nodeid, arg->nlookup);
- else
- forget_node(f, in->nodeid, arg->nlookup);
+ forget_node(f, ino, nlookup);
+ fuse_reply_none(req);
}
-static void do_getattr(struct fuse *f, struct fuse_in_header *in)
+static void fuse_getattr(fuse_req_t req, fuse_ino_t ino)
{
- int res;
- char *path;
+ struct fuse *f = req_fuse_prepare(req);
struct stat buf;
- struct fuse_attr_out arg;
+ char *path;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
if (path != NULL) {
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.getattr)
- res = f->op.getattr(path, &buf);
+ err = f->op.getattr(path, &buf);
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
-
- if (res == 0) {
- memset(&arg, 0, sizeof(struct fuse_attr_out));
- arg.attr_valid = ATTR_REVALIDATE_TIME;
- arg.attr_valid_nsec = 0;
- convert_stat(f, in->nodeid, &buf, &arg.attr);
- }
-
- send_reply(f, in, res, &arg, sizeof(arg));
+ if (!err) {
+ set_stat(f, ino, &buf);
+ fuse_reply_attr(req, &buf, ATTR_REVALIDATE_TIME);
+ } else
+ reply_err(req, err);
}
-static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr)
+static int do_chmod(struct fuse *f, const char *path, struct stat *attr)
{
- int res;
+ int err;
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.chmod)
- res = f->op.chmod(path, attr->mode);
+ err = f->op.chmod(path, attr->st_mode);
- return res;
+ return err;
}
-static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr,
+static int do_chown(struct fuse *f, const char *path, struct stat *attr,
int valid)
{
- int res;
- uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
- gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
+ int err;
+ uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
+ gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.chown)
- res = f->op.chown(path, uid, gid);
+ err = f->op.chown(path, uid, gid);
- return res;
+ return err;
}
-static int do_truncate(struct fuse *f, const char *path,
- struct fuse_attr *attr)
+static int do_truncate(struct fuse *f, const char *path, struct stat *attr)
{
- int res;
+ int err;
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.truncate)
- res = f->op.truncate(path, attr->size);
+ err = f->op.truncate(path, attr->st_size);
- return res;
+ return err;
}
-static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr)
+static int do_utime(struct fuse *f, const char *path, struct stat *attr)
{
- int res;
+ int err;
struct utimbuf buf;
- buf.actime = attr->atime;
- buf.modtime = attr->mtime;
- res = -ENOSYS;
+ buf.actime = attr->st_atime;
+ buf.modtime = attr->st_mtime;
+ err = -ENOSYS;
if (f->op.utime)
- res = f->op.utime(path, &buf);
+ err = f->op.utime(path, &buf);
- return res;
+ return err;
}
-static void do_setattr(struct fuse *f, struct fuse_in_header *in,
- struct fuse_setattr_in *arg)
+static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+ int valid)
{
- int res;
+ struct fuse *f = req_fuse_prepare(req);
+ struct stat buf;
char *path;
- int valid = arg->valid;
- struct fuse_attr *attr = MEMBER_COMPAT(f, arg, attr, fuse_setattr_in);
- struct fuse_attr_out outarg;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
if (path != NULL) {
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.getattr) {
- res = 0;
- if (!res && (valid & FATTR_MODE))
- res = do_chmod(f, path, attr);
- if (!res && (valid & (FATTR_UID | FATTR_GID)))
- res = do_chown(f, path, attr, valid);
- if (!res && (valid & FATTR_SIZE))
- res = do_truncate(f, path, attr);
- if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
- (FATTR_ATIME | FATTR_MTIME))
- res = do_utime(f, path, attr);
- if (!res) {
- struct stat buf;
- res = f->op.getattr(path, &buf);
- if (!res) {
- memset(&outarg, 0, sizeof(struct fuse_attr_out));
- outarg.attr_valid = ATTR_REVALIDATE_TIME;
- outarg.attr_valid_nsec = 0;
- convert_stat(f, in->nodeid, &buf, &outarg.attr);
- }
- }
+ err = 0;
+ if (!err && (valid & FUSE_SET_ATTR_MODE))
+ err = do_chmod(f, path, attr);
+ if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)))
+ err = do_chown(f, path, attr, valid);
+ if (!err && (valid & FUSE_SET_ATTR_SIZE))
+ err = do_truncate(f, path, attr);
+ if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))
+ err = do_utime(f, path, attr);
+ if (!err)
+ err = f->op.getattr(path, &buf);
}
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- send_reply(f, in, res, &outarg, sizeof(outarg));
+ if (!err) {
+ set_stat(f, ino, &buf);
+ fuse_reply_attr(req, &buf, ATTR_REVALIDATE_TIME);
+ } else
+ reply_err(req, err);
}
-static void do_readlink(struct fuse *f, struct fuse_in_header *in)
+static void fuse_readlink(fuse_req_t req, fuse_ino_t ino)
{
- int res;
+ struct fuse *f = req_fuse_prepare(req);
char link[PATH_MAX + 1];
char *path;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
if (path != NULL) {
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.readlink)
- res = f->op.readlink(path, link, sizeof(link));
+ err = f->op.readlink(path, link, sizeof(link));
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- link[PATH_MAX] = '\0';
- send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
+ if (!err) {
+ link[PATH_MAX] = '\0';
+ fuse_reply_readlink(req, link);
+ } else
+ reply_err(req, err);
}
-static void do_mknod(struct fuse *f, struct fuse_in_header *in,
- struct fuse_mknod_in *inarg)
+static void fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
+ mode_t mode, dev_t rdev)
{
- int res;
- int res2;
+ struct fuse *f = req_fuse_prepare(req);
+ struct fuse_entry_param e;
char *path;
- char *name = PARAM(inarg);
- struct fuse_entry_out outarg;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path_name(f, in->nodeid, name);
+ path = get_path_name(f, parent, name);
if (path != NULL) {
if (f->flags & FUSE_DEBUG) {
printf("MKNOD %s\n", path);
fflush(stdout);
}
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.mknod && f->op.getattr) {
- res = f->op.mknod(path, inarg->mode, inarg->rdev);
- if (res == 0)
- res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
+ err = f->op.mknod(path, mode, rdev);
+ if (!err)
+ err = lookup_path(f, parent, name, path, &e);
}
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
- if (res == 0 && res2 == -ENOENT)
- cancel_lookup(f, outarg.nodeid, in->unique);
+ reply_entry(req, &e, err);
}
-static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
- struct fuse_mkdir_in *inarg)
+static void fuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
+ mode_t mode)
{
- int res;
- int res2;
+ struct fuse *f = req_fuse_prepare(req);
+ struct fuse_entry_param e;
char *path;
- char *name = PARAM_COMPAT(f, inarg, fuse_mkdir_in);
- struct fuse_entry_out outarg;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path_name(f, in->nodeid, name);
+ path = get_path_name(f, parent, name);
if (path != NULL) {
if (f->flags & FUSE_DEBUG) {
printf("MKDIR %s\n", path);
fflush(stdout);
}
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.mkdir && f->op.getattr) {
- res = f->op.mkdir(path, inarg->mode);
- if (res == 0)
- res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
+ err = f->op.mkdir(path, mode);
+ if (!err)
+ err = lookup_path(f, parent, name, path, &e);
}
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
- if (res == 0 && res2 == -ENOENT)
- cancel_lookup(f, outarg.nodeid, in->unique);
+ reply_entry(req, &e, err);
}
-static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
+static void fuse_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
{
- int res;
+ struct fuse *f = req_fuse_prepare(req);
char *path;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_wrlock(&f->tree_lock);
- path = get_path_name(f, in->nodeid, name);
+ path = get_path_name(f, parent, name);
if (path != NULL) {
if (f->flags & FUSE_DEBUG) {
printf("UNLINK %s\n", path);
fflush(stdout);
}
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.unlink) {
- if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->nodeid, name))
- res = hide_node(f, path, in->nodeid, name);
+ if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, parent, name))
+ err = hide_node(f, path, parent, name);
else {
- res = f->op.unlink(path);
- if (res == 0)
- remove_node(f, in->nodeid, name);
-
+ err = f->op.unlink(path);
+ if (!err)
+ remove_node(f, parent, name);
}
}
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- send_reply(f, in, res, NULL, 0);
+ reply_err(req, err);
}
-static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
+static void fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
{
- int res;
+ struct fuse *f = req_fuse_prepare(req);
char *path;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_wrlock(&f->tree_lock);
- path = get_path_name(f, in->nodeid, name);
+ path = get_path_name(f, parent, name);
if (path != NULL) {
if (f->flags & FUSE_DEBUG) {
printf("RMDIR %s\n", path);
fflush(stdout);
}
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.rmdir) {
- res = f->op.rmdir(path);
- if (res == 0)
- remove_node(f, in->nodeid, name);
+ err = f->op.rmdir(path);
+ if (!err)
+ remove_node(f, parent, name);
}
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- send_reply(f, in, res, NULL, 0);
+ reply_err(req, err);
}
-static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
- char *link)
+static void fuse_symlink(fuse_req_t req, const char *link, fuse_ino_t parent,
+ const char *name)
{
- int res;
- int res2;
+ struct fuse *f = req_fuse_prepare(req);
+ struct fuse_entry_param e;
char *path;
- struct fuse_entry_out outarg;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path_name(f, in->nodeid, name);
+ path = get_path_name(f, parent, name);
if (path != NULL) {
if (f->flags & FUSE_DEBUG) {
printf("SYMLINK %s\n", path);
fflush(stdout);
}
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.symlink && f->op.getattr) {
- res = f->op.symlink(link, path);
- if (res == 0)
- res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
+ err = f->op.symlink(link, path);
+ if (!err)
+ err = lookup_path(f, parent, name, path, &e);
}
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
- if (res == 0 && res2 == -ENOENT)
- cancel_lookup(f, outarg.nodeid, in->unique);
-
+ reply_entry(req, &e, err);
}
-static void do_rename(struct fuse *f, struct fuse_in_header *in,
- struct fuse_rename_in *inarg)
+static void fuse_rename(fuse_req_t req, fuse_ino_t olddir, const char *oldname,
+ fuse_ino_t newdir, const char *newname)
{
- int res;
- nodeid_t olddir = in->nodeid;
- nodeid_t newdir = inarg->newdir;
- char *oldname = PARAM(inarg);
- char *newname = oldname + strlen(oldname) + 1;
+ struct fuse *f = req_fuse_prepare(req);
char *oldpath;
char *newpath;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_wrlock(&f->tree_lock);
oldpath = get_path_name(f, olddir, oldname);
if (oldpath != NULL) {
@@ -1019,16 +874,16 @@ static void do_rename(struct fuse *f, struct fuse_in_header *in,
printf("RENAME %s -> %s\n", oldpath, newpath);
fflush(stdout);
}
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.rename) {
- res = 0;
+ err = 0;
if (!(f->flags & FUSE_HARD_REMOVE) &&
is_open(f, newdir, newname))
- res = hide_node(f, newpath, newdir, newname);
- if (res == 0) {
- res = f->op.rename(oldpath, newpath);
- if (res == 0)
- res = rename_node(f, olddir, oldname, newdir, newname, 0);
+ err = hide_node(f, newpath, newdir, newname);
+ if (!err) {
+ err = f->op.rename(oldpath, newpath);
+ if (!err)
+ err = rename_node(f, olddir, oldname, newdir, newname, 0);
}
}
free(newpath);
@@ -1036,561 +891,265 @@ static void do_rename(struct fuse *f, struct fuse_in_header *in,
free(oldpath);
}
pthread_rwlock_unlock(&f->tree_lock);
- send_reply(f, in, res, NULL, 0);
+ reply_err(req, err);
}
-static void do_link(struct fuse *f, struct fuse_in_header *in,
- struct fuse_link_in *arg)
+static void fuse_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
+ const char *newname)
{
- int res;
- int res2;
+ struct fuse *f = req_fuse_prepare(req);
+ struct fuse_entry_param e;
char *oldpath;
char *newpath;
- char *name = PARAM(arg);
- struct fuse_entry_out outarg;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- oldpath = get_path(f, arg->oldnodeid);
+ oldpath = get_path(f, ino);
if (oldpath != NULL) {
- newpath = get_path_name(f, in->nodeid, name);
+ newpath = get_path_name(f, newparent, newname);
if (newpath != NULL) {
if (f->flags & FUSE_DEBUG) {
printf("LINK %s\n", newpath);
fflush(stdout);
}
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.link && f->op.getattr) {
- res = f->op.link(oldpath, newpath);
- if (res == 0)
- res = lookup_path(f, in->nodeid, in->unique, name,
- newpath, &outarg);
+ err = f->op.link(oldpath, newpath);
+ if (!err)
+ err = lookup_path(f, newparent, newname, newpath, &e);
}
free(newpath);
}
free(oldpath);
}
pthread_rwlock_unlock(&f->tree_lock);
- res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
- if (res == 0 && res2 == -ENOENT)
- cancel_lookup(f, outarg.nodeid, in->unique);
+ reply_entry(req, &e, err);
}
-static void do_open(struct fuse *f, struct fuse_in_header *in,
- struct fuse_open_in *arg)
+static void fuse_open(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi)
{
- int res;
+ struct fuse *f = req_fuse_prepare(req);
char *path;
- struct fuse_open_out outarg;
- struct fuse_file_info fi;
+ int err;
- memset(&outarg, 0, sizeof(outarg));
- memset(&fi, 0, sizeof(fi));
- fi.flags = arg->flags;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
if (path != NULL) {
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.open) {
if (!f->compat)
- res = f->op.open(path, &fi);
+ err = f->op.open(path, fi);
else
- res = ((struct fuse_operations_compat2 *) &f->op)->open(path, fi.flags);
+ err = ((struct fuse_operations_compat2 *) &f->op)->open(path, fi->flags);
}
}
- if (res == 0) {
- int res2;
- outarg.fh = fi.fh;
+ if (!err) {
if (f->flags & FUSE_DEBUG) {
- printf("OPEN[%lu] flags: 0x%x\n", fi.fh, arg->flags);
+ printf("OPEN[%lu] flags: 0x%x\n", fi->fh, fi->flags);
fflush(stdout);
}
pthread_mutex_lock(&f->lock);
- res2 = send_reply(f, in, res, &outarg, SIZEOF_COMPAT(f, fuse_open_out));
- if(res2 == -ENOENT) {
+ if (fuse_reply_open(req, fi) == -ENOENT) {
/* The open syscall was interrupted, so it must be cancelled */
if(f->op.release) {
if (!f->compat)
- f->op.release(path, &fi);
+ f->op.release(path, fi);
else
- ((struct fuse_operations_compat2 *) &f->op)->release(path, fi.flags);
+ ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
}
} else {
- struct node *node = get_node(f, in->nodeid);
+ struct node *node = get_node(f, ino);
node->open_count ++;
}
pthread_mutex_unlock(&f->lock);
} else
- send_reply(f, in, res, NULL, 0);
+ reply_err(req, err);
if (path)
free(path);
pthread_rwlock_unlock(&f->tree_lock);
}
-static void do_flush(struct fuse *f, struct fuse_in_header *in,
- struct fuse_flush_in *arg)
+static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
+ struct fuse_file_info *fi)
{
+ struct fuse *f = req_fuse_prepare(req);
char *path;
- int res;
- struct fuse_file_info fi;
-
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
- res = -ENOENT;
- pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
- if (path != NULL) {
- if (f->flags & FUSE_DEBUG) {
- printf("FLUSH[%lu]\n", (unsigned long) arg->fh);
- fflush(stdout);
- }
- res = -ENOSYS;
- if (f->op.flush)
- res = f->op.flush(path, &fi);
- free(path);
- }
- pthread_rwlock_unlock(&f->tree_lock);
- send_reply(f, in, res, NULL, 0);
-}
-
-static void do_release(struct fuse *f, struct fuse_in_header *in,
- struct fuse_release_in *arg)
-{
- struct node *node;
- char *path;
- struct fuse_file_info fi;
- int unlink_hidden;
-
- memset(&fi, 0, sizeof(fi));
- fi.flags = arg->flags;
- fi.fh = arg->fh;
-
- pthread_mutex_lock(&f->lock);
- node = get_node(f, in->nodeid);
- assert(node->open_count > 0);
- --node->open_count;
- unlink_hidden = (node->is_hidden && !node->open_count);
- pthread_mutex_unlock(&f->lock);
-
- pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
- if (f->flags & FUSE_DEBUG) {
- printf("RELEASE[%lu] flags: 0x%x\n", fi.fh, fi.flags);
- fflush(stdout);
- }
- if (f->op.release) {
- if (!f->compat)
- f->op.release(path ? path : "-", &fi);
- else if (path)
- ((struct fuse_operations_compat2 *) &f->op)->release(path, fi.flags);
- }
-
- if(unlink_hidden && path)
- f->op.unlink(path);
-
- if (path)
- free(path);
- pthread_rwlock_unlock(&f->tree_lock);
-
- send_reply(f, in, 0, NULL, 0);
-}
-
-static void do_read(struct fuse *f, struct fuse_in_header *in,
- struct fuse_read_in *arg)
-{
- int res;
- char *path;
- size_t size;
char *buf;
- struct fuse_file_info fi;
+ int res;
- buf = (char *) malloc(arg->size);
+ buf = (char *) malloc(size);
if (buf == NULL) {
- send_reply(f, in, -ENOMEM, NULL, 0);
+ reply_err(req, -ENOMEM);
return;
}
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
-
res = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
if (path != NULL) {
if (f->flags & FUSE_DEBUG) {
- printf("READ[%lu] %u bytes from %llu\n",
- (unsigned long) arg->fh, arg->size, arg->offset);
+ printf("READ[%lu] %u bytes from %llu\n", fi->fh, size, off);
fflush(stdout);
}
res = -ENOSYS;
if (f->op.read)
- res = f->op.read(path, buf, arg->size, arg->offset, &fi);
+ res = f->op.read(path, buf, size, off, fi);
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- size = 0;
if (res >= 0) {
- size = res;
- res = 0;
if (f->flags & FUSE_DEBUG) {
- printf(" READ[%lu] %u bytes\n", (unsigned long) arg->fh,
- size);
+ printf(" READ[%lu] %u bytes\n", fi->fh, res);
fflush(stdout);
}
- }
+ fuse_reply_buf(req, buf, res);
+ } else
+ reply_err(req, res);
- send_reply(f, in, res, buf, size);
free(buf);
}
-static void do_write(struct fuse *f, struct fuse_in_header *in,
- struct fuse_write_in *arg)
+static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
+ size_t size, off_t off, struct fuse_file_info *fi)
{
- int res;
+ struct fuse *f = req_fuse_prepare(req);
char *path;
- struct fuse_write_out outarg;
- struct fuse_file_info fi;
-
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
- fi.writepage = arg->write_flags & 1;
+ int res;
res = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
if (path != NULL) {
if (f->flags & FUSE_DEBUG) {
printf("WRITE%s[%lu] %u bytes to %llu\n",
- (arg->write_flags & 1) ? "PAGE" : "",
- (unsigned long) arg->fh, arg->size, arg->offset);
+ fi->writepage ? "PAGE" : "", fi->fh, size, off);
fflush(stdout);
}
res = -ENOSYS;
if (f->op.write)
- res = f->op.write(path, PARAM(arg), arg->size, arg->offset, &fi);
+ res = f->op.write(path, buf, size, off, fi);
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- memset(&outarg, 0, sizeof(outarg));
- if (res >= 0) {
- outarg.size = res;
- res = 0;
- }
-
- send_reply(f, in, res, &outarg, SIZEOF_COMPAT(f, fuse_write_out));
-}
-
-static int default_statfs(struct statfs *buf)
-{
- buf->f_namelen = 255;
- buf->f_bsize = 512;
- return 0;
-}
-
-static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
- struct statfs *statfs)
-{
- statfs->f_bsize = compatbuf->block_size;
- statfs->f_blocks = compatbuf->blocks;
- statfs->f_bfree = compatbuf->blocks_free;
- statfs->f_bavail = compatbuf->blocks_free;
- statfs->f_files = compatbuf->files;
- statfs->f_ffree = compatbuf->files_free;
- statfs->f_namelen = compatbuf->namelen;
-}
-
-static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
-{
- kstatfs->bsize = statfs->f_bsize;
- kstatfs->blocks = statfs->f_blocks;
- kstatfs->bfree = statfs->f_bfree;
- kstatfs->bavail = statfs->f_bavail;
- kstatfs->files = statfs->f_files;
- kstatfs->ffree = statfs->f_ffree;
- kstatfs->namelen = statfs->f_namelen;
-}
-
-static void do_statfs(struct fuse *f, struct fuse_in_header *in)
-{
- int res;
- struct fuse_statfs_out arg;
- struct statfs buf;
-
- memset(&buf, 0, sizeof(struct statfs));
- if (f->op.statfs) {
- if (!f->compat || f->compat > 11)
- res = f->op.statfs("/", &buf);
- else {
- struct fuse_statfs_compat1 compatbuf;
- memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
- res = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
- if (res == 0)
- convert_statfs_compat(&compatbuf, &buf);
- }
- }
+ if (res >= 0)
+ fuse_reply_write(req, res);
else
- res = default_statfs(&buf);
-
- if (res == 0)
- convert_statfs(&buf, &arg.st);
-
- send_reply(f, in, res, &arg, sizeof(arg));
+ reply_err(req, res);
}
-static void do_fsync(struct fuse *f, struct fuse_in_header *in,
- struct fuse_fsync_in *inarg)
+static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi)
{
- int res;
+ struct fuse *f = req_fuse_prepare(req);
char *path;
- struct fuse_file_info fi;
-
- memset(&fi, 0, sizeof(fi));
- fi.fh = inarg->fh;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
if (path != NULL) {
if (f->flags & FUSE_DEBUG) {
- printf("FSYNC[%lu]\n", (unsigned long) inarg->fh);
+ printf("FLUSH[%lu]\n", fi->fh);
fflush(stdout);
}
- res = -ENOSYS;
- if (f->op.fsync)
- res = f->op.fsync(path, inarg->fsync_flags & 1, &fi);
+ err = -ENOSYS;
+ if (f->op.flush)
+ err = f->op.flush(path, fi);
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- send_reply(f, in, res, NULL, 0);
+ reply_err(req, err);
}
-static void do_setxattr(struct fuse *f, struct fuse_in_header *in,
- struct fuse_setxattr_in *arg)
+static void fuse_release(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi)
{
- int res;
+ struct fuse *f = req_fuse_prepare(req);
char *path;
- char *name = PARAM(arg);
- unsigned char *value = name + strlen(name) + 1;
-
- res = -ENOENT;
- pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
- if (path != NULL) {
- res = -ENOSYS;
- if (f->op.setxattr)
- res = f->op.setxattr(path, name, value, arg->size, arg->flags);
- free(path);
- }
- pthread_rwlock_unlock(&f->tree_lock);
- send_reply(f, in, res, NULL, 0);
-}
+ struct node *node;
+ int unlink_hidden;
-static int common_getxattr(struct fuse *f, struct fuse_in_header *in,
- const char *name, char *value, size_t size)
-{
- int res;
- char *path;
+ pthread_mutex_lock(&f->lock);
+ node = get_node(f, ino);
+ assert(node->open_count > 0);
+ --node->open_count;
+ unlink_hidden = (node->is_hidden && !node->open_count);
+ pthread_mutex_unlock(&f->lock);
- res = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
- if (path != NULL) {
- res = -ENOSYS;
- if (f->op.getxattr)
- res = f->op.getxattr(path, name, value, size);
- free(path);
- }
- pthread_rwlock_unlock(&f->tree_lock);
- return res;
-}
-
-static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
- const char *name, size_t size)
-{
- int res;
- char *value = (char *) malloc(size);
- if (value == NULL) {
- send_reply(f, in, -ENOMEM, NULL, 0);
- return;
- }
- res = common_getxattr(f, in, name, value, size);
- size = 0;
- if (res > 0) {
- size = res;
- res = 0;
+ path = get_path(f, ino);
+ if (f->flags & FUSE_DEBUG) {
+ printf("RELEASE[%lu] flags: 0x%x\n", fi->fh, fi->flags);
+ fflush(stdout);
}
- send_reply(f, in, res, value, size);
- free(value);
-}
-
-static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
- const char *name)
-{
- int res;
- struct fuse_getxattr_out arg;
-
- memset(&arg, 0, sizeof(arg));
- res = common_getxattr(f, in, name, NULL, 0);
- if (res >= 0) {
- arg.size = res;
- res = 0;
+ if (f->op.release) {
+ if (!f->compat)
+ f->op.release(path ? path : "-", fi);
+ else if (path)
+ ((struct fuse_operations_compat2 *) &f->op)->release(path, fi->flags);
}
- send_reply(f, in, res, &arg, SIZEOF_COMPAT(f, fuse_getxattr_out));
-}
-
-static void do_getxattr(struct fuse *f, struct fuse_in_header *in,
- struct fuse_getxattr_in *arg)
-{
- char *name = PARAM(arg);
- if (arg->size)
- do_getxattr_read(f, in, name, arg->size);
- else
- do_getxattr_size(f, in, name);
-}
-
-static int common_listxattr(struct fuse *f, struct fuse_in_header *in,
- char *list, size_t size)
-{
- int res;
- char *path;
+ if(unlink_hidden && path)
+ f->op.unlink(path);
- res = -ENOENT;
- pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
- if (path != NULL) {
- res = -ENOSYS;
- if (f->op.listxattr)
- res = f->op.listxattr(path, list, size);
+ if (path)
free(path);
- }
pthread_rwlock_unlock(&f->tree_lock);
- return res;
-}
-static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
- size_t size)
-{
- int res;
- char *list = (char *) malloc(size);
- if (list == NULL) {
- send_reply(f, in, -ENOMEM, NULL, 0);
- return;
- }
- res = common_listxattr(f, in, list, size);
- size = 0;
- if (res > 0) {
- size = res;
- res = 0;
- }
- send_reply(f, in, res, list, size);
- free(list);
+ reply_err(req, 0);
}
-static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
+static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
+ struct fuse_file_info *fi)
{
- int res;
- struct fuse_getxattr_out arg;
-
- memset(&arg, 0, sizeof(arg));
- res = common_listxattr(f, in, NULL, 0);
- if (res >= 0) {
- arg.size = res;
- res = 0;
- }
- send_reply(f, in, res, &arg, SIZEOF_COMPAT(f, fuse_getxattr_out));
-}
-
-static void do_listxattr(struct fuse *f, struct fuse_in_header *in,
- struct fuse_getxattr_in *arg)
-{
- if (arg->size)
- do_listxattr_read(f, in, arg->size);
- else
- do_listxattr_size(f, in);
-}
-
-static void do_removexattr(struct fuse *f, struct fuse_in_header *in,
- char *name)
-{
- int res;
+ struct fuse *f = req_fuse_prepare(req);
char *path;
+ int err;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
if (path != NULL) {
- res = -ENOSYS;
- if (f->op.removexattr)
- res = f->op.removexattr(path, name);
+ if (f->flags & FUSE_DEBUG) {
+ printf("FSYNC[%lu]\n", fi->fh);
+ fflush(stdout);
+ }
+ err = -ENOSYS;
+ if (f->op.fsync)
+ err = f->op.fsync(path, datasync, fi);
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- send_reply(f, in, res, NULL, 0);
-}
-
-static void do_init(struct fuse *f, struct fuse_in_header *in,
- 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) {
- printf("INIT: %u.%u\n", arg->major, arg->minor);
- fflush(stdout);
- }
- f->got_init = 1;
- 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;
- }
- memset(&outarg, 0, sizeof(outarg));
- outarg.major = f->major;
- outarg.minor = f->minor;
-
- if (f->flags & FUSE_DEBUG) {
- printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
- fflush(stdout);
- }
-
- send_reply(f, in, 0, &outarg, sizeof(outarg));
+ reply_err(req, err);
}
-static struct fuse_dirhandle *get_dirhandle(unsigned long fh)
+static struct fuse_dirhandle *get_dirhandle(const struct fuse_file_info *llfi,
+ struct fuse_file_info *fi)
{
- return (struct fuse_dirhandle *) fh;
+ struct fuse_dirhandle *dh = (struct fuse_dirhandle *) llfi->fh;
+ memset(fi, 0, sizeof(struct fuse_file_info));
+ fi->fh = dh->fh;
+ return dh;
}
-static void do_opendir(struct fuse *f, struct fuse_in_header *in,
- struct fuse_open_in *arg)
+static void fuse_opendir(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *llfi)
{
- int res;
- struct fuse_open_out outarg;
+ struct fuse *f = req_fuse_prepare(req);
struct fuse_dirhandle *dh;
dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
if (dh == NULL) {
- send_reply(f, in, -ENOMEM, NULL, 0);
+ reply_err(req, -ENOMEM);
return;
}
memset(dh, 0, sizeof(struct fuse_dirhandle));
@@ -1598,31 +1157,29 @@ static void do_opendir(struct fuse *f, struct fuse_in_header *in,
dh->contents = NULL;
dh->len = 0;
dh->filled = 0;
- dh->nodeid = in->nodeid;
+ dh->nodeid = ino;
mutex_init(&dh->lock);
- memset(&outarg, 0, sizeof(outarg));
- outarg.fh = (unsigned long) dh;
+ llfi->fh = (unsigned long) dh;
if (f->op.opendir) {
struct fuse_file_info fi;
char *path;
+ int err;
memset(&fi, 0, sizeof(fi));
- fi.flags = arg->flags;
+ fi.flags = llfi->flags;
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
if (path != NULL) {
- res = f->op.opendir(path, &fi);
+ err = f->op.opendir(path, &fi);
dh->fh = fi.fh;
}
- if (res == 0) {
- int res2;
+ if (!err) {
pthread_mutex_lock(&f->lock);
- res2 = send_reply(f, in, res, &outarg, SIZEOF_COMPAT(f, fuse_open_out));
- if(res2 == -ENOENT) {
+ if (fuse_reply_open(req, llfi) == -ENOENT) {
/* The opendir syscall was interrupted, so it must be
cancelled */
if(f->op.releasedir)
@@ -1632,50 +1189,47 @@ static void do_opendir(struct fuse *f, struct fuse_in_header *in,
}
pthread_mutex_unlock(&f->lock);
} else {
- send_reply(f, in, res, NULL, 0);
+ reply_err(req, err);
free(dh);
}
free(path);
pthread_rwlock_unlock(&f->tree_lock);
} else
- send_reply(f, in, 0, &outarg, SIZEOF_COMPAT(f, fuse_open_out));
+ fuse_reply_open(req, llfi);
}
static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
- int type, ino_t ino, off_t off)
+ const struct stat *stat, off_t off)
{
+ struct stat stbuf;
unsigned namelen = strlen(name);
- unsigned entlen;
unsigned entsize;
- unsigned padlen;
unsigned newlen;
unsigned char *newptr;
+ if (stat)
+ stbuf = *stat;
+ else {
+ memset(&stbuf, 0, sizeof(stbuf));
+ stbuf.st_ino = -1;
+ }
+
if (!(dh->fuse->flags & FUSE_USE_INO)) {
- ino = (ino_t) -1;
+ stbuf.st_ino = (ino_t) -1;
if (dh->fuse->flags & FUSE_READDIR_INO) {
struct node *node;
pthread_mutex_lock(&dh->fuse->lock);
node = lookup_node(dh->fuse, dh->nodeid, name);
if (node)
- ino = (ino_t) node->nodeid;
+ stbuf.st_ino = (ino_t) node->nodeid;
pthread_mutex_unlock(&dh->fuse->lock);
}
}
- if (namelen > FUSE_NAME_MAX)
- namelen = FUSE_NAME_MAX;
- else if (!namelen) {
- dh->error = -EIO;
- return 1;
- }
-
- entlen = (dh->fuse->major == 5 ?
- FUSE_NAME_OFFSET_COMPAT5 : FUSE_NAME_OFFSET) + namelen;
- entsize = FUSE_DIRENT_ALIGN(entlen);
- padlen = entsize - entlen;
+ entsize = fuse_dirent_size(namelen);
newlen = dh->len + entsize;
- if (off && dh->fuse->major != 5) {
+
+ if (off) {
dh->filled = 0;
if (newlen > dh->needlen)
return 1;
@@ -1687,24 +1241,7 @@ static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
return 1;
}
dh->contents = newptr;
- if (dh->fuse->major == 5) {
- struct fuse_dirent_compat5 *dirent;
- dirent = (struct fuse_dirent_compat5 *) (dh->contents + dh->len);
- dirent->ino = ino;
- dirent->namelen = namelen;
- dirent->type = type;
- strncpy(dirent->name, name, namelen);
- } else {
- struct fuse_dirent *dirent;
- dirent = (struct fuse_dirent *) (dh->contents + dh->len);
- dirent->ino = ino;
- dirent->off = off ? off : newlen;
- dirent->namelen = namelen;
- dirent->type = type;
- strncpy(dirent->name, name, namelen);
- }
- if (padlen)
- memset(dh->contents + dh->len + entlen, 0, padlen);
+ fuse_add_dirent(dh->contents + dh->len, name, &stbuf, off ? off : newlen);
dh->len = newlen;
return 0;
}
@@ -1712,40 +1249,39 @@ static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
static int fill_dir(void *buf, const char *name, const struct stat *stat,
off_t off)
{
- int type = stat ? (stat->st_mode & 0170000) >> 12 : 0;
- ino_t ino = stat ? stat->st_ino : (ino_t) -1;
- return fill_dir_common(buf, name, type, ino, off);
+ return fill_dir_common((struct fuse_dirhandle *) buf, name, stat, off);
}
static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
ino_t ino)
{
- fill_dir_common(dh, name, type, ino, 0);
+ struct stat stbuf;
+
+ memset(&stbuf, 0, sizeof(stbuf));
+ stbuf.st_mode = type << 12;
+ stbuf.st_ino = ino;
+
+ fill_dir_common(dh, name, &stbuf, 0);
return dh->error;
}
-static int readdir_fill(struct fuse *f, struct fuse_in_header *in,
- struct fuse_read_in *arg, struct fuse_dirhandle *dh)
+static int readdir_fill(struct fuse *f, fuse_ino_t ino, size_t size,
+ off_t off, struct fuse_dirhandle *dh,
+ struct fuse_file_info *fi)
{
int err = -ENOENT;
char *path;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
if (path != NULL) {
- struct fuse_file_info fi;
-
- memset(&fi, 0, sizeof(fi));
- fi.fh = dh->fh;
-
dh->len = 0;
dh->error = 0;
- dh->needlen = arg->size;
+ dh->needlen = size;
dh->filled = 1;
err = -ENOSYS;
- if (f->op.readdir) {
- off_t offset = f->major == 5 ? 0 : arg->offset;
- err = f->op.readdir(path, dh, fill_dir, offset, &fi);
- } else if (f->op.getdir)
+ if (f->op.readdir)
+ err = f->op.readdir(path, dh, fill_dir, off, fi);
+ else if (f->op.getdir)
err = f->op.getdir(path, dh, fill_dir_old);
if (!err)
err = dh->error;
@@ -1757,50 +1293,47 @@ static int readdir_fill(struct fuse *f, struct fuse_in_header *in,
return err;
}
-static void do_readdir(struct fuse *f, struct fuse_in_header *in,
- struct fuse_read_in *arg)
+static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+ off_t off, struct fuse_file_info *llfi)
{
- int err = 0;
- struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
- size_t size = 0;
- unsigned char *buf = NULL;
+ struct fuse *f = req_fuse_prepare(req);
+ struct fuse_file_info fi;
+ struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
pthread_mutex_lock(&dh->lock);
if (!dh->filled) {
- err = readdir_fill(f, in, arg, dh);
- if (err)
+ int err = readdir_fill(f, ino, size, off, dh, &fi);
+ if (err) {
+ reply_err(req, err);
goto out;
+ }
}
if (dh->filled) {
- if (arg->offset < dh->len) {
- size = arg->size;
- if (arg->offset + size > dh->len)
- size = dh->len - arg->offset;
- buf = dh->contents + arg->offset;
- }
+ if (off < dh->len) {
+ if (off + size > dh->len)
+ size = dh->len - off;
+ } else
+ size = 0;
} else {
size = dh->len;
- buf = dh->contents;
+ off = 0;
}
-
+ fuse_reply_buf(req, dh->contents + off, size);
out:
- send_reply(f, in, err, buf, size);
pthread_mutex_unlock(&dh->lock);
}
-static void do_releasedir(struct fuse *f, struct fuse_in_header *in,
- struct fuse_release_in *arg)
+static void fuse_releasedir(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *llfi)
{
- struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
+ struct fuse *f = req_fuse_prepare(req);
+ struct fuse_file_info fi;
+ struct fuse_dirhandle *dh = get_dirhandle(llfi, &fi);
if (f->op.releasedir) {
char *path;
- struct fuse_file_info fi;
-
- memset(&fi, 0, sizeof(fi));
- fi.fh = dh->fh;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
f->op.releasedir(path ? path : "-", &fi);
free(path);
pthread_rwlock_unlock(&f->tree_lock);
@@ -1810,272 +1343,261 @@ static void do_releasedir(struct fuse *f, struct fuse_in_header *in,
pthread_mutex_destroy(&dh->lock);
free(dh->contents);
free(dh);
- send_reply(f, in, 0, NULL, 0);
+ reply_err(req, 0);
}
-static void do_fsyncdir(struct fuse *f, struct fuse_in_header *in,
- struct fuse_fsync_in *inarg)
+static void fuse_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
+ struct fuse_file_info *llfi)
{
- int res;
- char *path;
- struct fuse_dirhandle *dh = get_dirhandle(inarg->fh);
+ struct fuse *f = req_fuse_prepare(req);
struct fuse_file_info fi;
+ char *path;
+ int err;
- memset(&fi, 0, sizeof(fi));
- fi.fh = dh->fh;
+ get_dirhandle(llfi, &fi);
- res = -ENOENT;
+ err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
- path = get_path(f, in->nodeid);
+ path = get_path(f, ino);
if (path != NULL) {
- res = -ENOSYS;
+ err = -ENOSYS;
if (f->op.fsyncdir)
- res = f->op.fsyncdir(path, inarg->fsync_flags & 1, &fi);
+ err = f->op.fsyncdir(path, datasync, &fi);
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
- send_reply(f, in, res, NULL, 0);
+ reply_err(req, err);
}
-static void free_cmd(struct fuse_cmd *cmd)
+static int default_statfs(struct statfs *buf)
{
- free(cmd->buf);
- free(cmd);
+ buf->f_namelen = 255;
+ buf->f_bsize = 512;
+ return 0;
}
-void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
+static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
+ struct statfs *statfs)
{
- 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();
-
- fuse_dec_avail(f);
-
- if ((f->flags & FUSE_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);
- }
+ statfs->f_bsize = compatbuf->block_size;
+ statfs->f_blocks = compatbuf->blocks;
+ statfs->f_bfree = compatbuf->blocks_free;
+ statfs->f_bavail = compatbuf->blocks_free;
+ statfs->f_files = compatbuf->files;
+ statfs->f_ffree = compatbuf->files_free;
+ statfs->f_namelen = compatbuf->namelen;
+}
- if (!f->got_init && in->opcode != FUSE_INIT) {
- /* Old kernel version probably */
- send_reply(f, in, -EPROTO, NULL, 0);
- goto out;
- }
+static void fuse_statfs(fuse_req_t req)
+{
+ struct fuse *f = req_fuse_prepare(req);
+ struct statfs buf;
+ int err;
- if ((f->flags & FUSE_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);
- goto out;
+ memset(&buf, 0, sizeof(struct statfs));
+ if (f->op.statfs) {
+ if (!f->compat || f->compat > 11)
+ err = f->op.statfs("/", &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);
+ }
}
+ else
+ err = default_statfs(&buf);
- ctx->fuse = f;
- ctx->uid = in->uid;
- ctx->gid = in->gid;
- ctx->pid = in->pid;
- ctx->private_data = f->user_data;
-
- switch (in->opcode) {
- case FUSE_LOOKUP:
- do_lookup(f, in, (char *) inarg);
- break;
-
- case FUSE_GETATTR:
- do_getattr(f, in);
- break;
-
- case FUSE_SETATTR:
- do_setattr(f, in, (struct fuse_setattr_in *) inarg);
- break;
-
- case FUSE_READLINK:
- do_readlink(f, in);
- break;
-
- case FUSE_MKNOD:
- do_mknod(f, in, (struct fuse_mknod_in *) inarg);
- break;
-
- case FUSE_MKDIR:
- do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
- break;
-
- case FUSE_UNLINK:
- do_unlink(f, in, (char *) inarg);
- break;
-
- case FUSE_RMDIR:
- do_rmdir(f, in, (char *) inarg);
- break;
-
- case FUSE_SYMLINK:
- do_symlink(f, in, (char *) inarg,
- ((char *) inarg) + strlen((char *) inarg) + 1);
- break;
-
- case FUSE_RENAME:
- do_rename(f, in, (struct fuse_rename_in *) inarg);
- break;
-
- case FUSE_LINK:
- do_link(f, in, (struct fuse_link_in *) inarg);
- break;
-
- case FUSE_OPEN:
- do_open(f, in, (struct fuse_open_in *) inarg);
- break;
-
- case FUSE_FLUSH:
- do_flush(f, in, (struct fuse_flush_in *) inarg);
- break;
-
- case FUSE_RELEASE:
- do_release(f, in, (struct fuse_release_in *) inarg);
- break;
-
- case FUSE_READ:
- do_read(f, in, (struct fuse_read_in *) inarg);
- break;
-
- case FUSE_WRITE:
- do_write(f, in, (struct fuse_write_in *) inarg);
- break;
+ if (!err)
+ fuse_reply_statfs(req, &buf);
+ else
+ reply_err(req, err);
+}
- case FUSE_STATFS:
- do_statfs(f, in);
- break;
+static void fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+ const char *value, size_t size, int flags)
+{
+ struct fuse *f = req_fuse_prepare(req);
+ char *path;
+ int err;
- case FUSE_FSYNC:
- do_fsync(f, in, (struct fuse_fsync_in *) inarg);
- break;
+ err = -ENOENT;
+ pthread_rwlock_rdlock(&f->tree_lock);
+ path = get_path(f, ino);
+ if (path != NULL) {
+ err = -ENOSYS;
+ if (f->op.setxattr)
+ err = f->op.setxattr(path, name, value, size, flags);
+ free(path);
+ }
+ pthread_rwlock_unlock(&f->tree_lock);
+ reply_err(req, err);
+}
- case FUSE_SETXATTR:
- do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
- break;
+static int common_getxattr(struct fuse *f, fuse_ino_t ino, const char *name,
+ char *value, size_t size)
+{
+ int err;
+ char *path;
- case FUSE_GETXATTR:
- do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
- break;
+ err = -ENOENT;
+ pthread_rwlock_rdlock(&f->tree_lock);
+ path = get_path(f, ino);
+ if (path != NULL) {
+ err = -ENOSYS;
+ if (f->op.getxattr)
+ err = f->op.getxattr(path, name, value, size);
+ free(path);
+ }
+ pthread_rwlock_unlock(&f->tree_lock);
+ return err;
+}
- case FUSE_LISTXATTR:
- do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
- break;
+static void fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+ size_t size)
+{
+ struct fuse *f = req_fuse_prepare(req);
+ int res;
- case FUSE_REMOVEXATTR:
- do_removexattr(f, in, (char *) inarg);
- break;
+ if (size) {
+ char *value = (char *) malloc(size);
+ if (value == NULL) {
+ reply_err(req, -ENOMEM);
+ return;
+ }
+ res = common_getxattr(f, ino, name, value, size);
+ if (res > 0)
+ fuse_reply_buf(req, value, res);
+ else
+ reply_err(req, res);
+ free(value);
+ } else {
+ res = common_getxattr(f, ino, name, NULL, 0);
+ if (res >= 0)
+ fuse_reply_xattr(req, res);
+ else
+ reply_err(req, res);
+ }
+}
- case FUSE_INIT:
- do_init(f, in, (struct fuse_init_in_out *) inarg);
- break;
+static int common_listxattr(struct fuse *f, fuse_ino_t ino, char *list,
+ size_t size)
+{
+ char *path;
+ int err;
- case FUSE_OPENDIR:
- do_opendir(f, in, (struct fuse_open_in *) inarg);
- break;
+ err = -ENOENT;
+ pthread_rwlock_rdlock(&f->tree_lock);
+ path = get_path(f, ino);
+ if (path != NULL) {
+ err = -ENOSYS;
+ if (f->op.listxattr)
+ err = f->op.listxattr(path, list, size);
+ free(path);
+ }
+ pthread_rwlock_unlock(&f->tree_lock);
+ return err;
+}
- case FUSE_READDIR:
- do_readdir(f, in, (struct fuse_read_in *) inarg);
- break;
+static void fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+{
+ struct fuse *f = req_fuse_prepare(req);
+ int res;
- case FUSE_RELEASEDIR:
- do_releasedir(f, in, (struct fuse_release_in *) inarg);
- break;
+ 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);
+ }
+}
- case FUSE_FSYNCDIR:
- do_fsyncdir(f, in, (struct fuse_fsync_in *) inarg);
- break;
+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;
- default:
- send_reply(f, in, -ENOSYS, NULL, 0);
+ 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_ll_operations fuse_path_ops = {
+ .init = fuse_data_init,
+ .destroy = fuse_data_destroy,
+ .lookup = fuse_lookup,
+ .forget = fuse_forget,
+ .getattr = fuse_getattr,
+ .setattr = fuse_setattr,
+ .readlink = fuse_readlink,
+ .mknod = fuse_mknod,
+ .mkdir = fuse_mkdir,
+ .unlink = fuse_unlink,
+ .rmdir = fuse_rmdir,
+ .symlink = fuse_symlink,
+ .rename = fuse_rename,
+ .link = fuse_link,
+ .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,
+};
- out:
- free_cmd(cmd);
+void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
+{
+ fuse_ll_process_cmd(f->fll, cmd);
}
-int fuse_exited(struct fuse* f)
+int fuse_exited(struct fuse *f)
{
- return f->exited;
+ return fuse_ll_exited(f->fll);
}
struct fuse_cmd *fuse_read_cmd(struct fuse *f)
{
- ssize_t res;
- struct fuse_cmd *cmd;
- struct fuse_in_header *in;
- void *inarg;
-
- cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
- if (cmd == NULL) {
- fprintf(stderr, "fuse: failed to allocate cmd in read\n");
- return NULL;
- }
- cmd->buf = (char *) malloc(FUSE_MAX_IN);
- if (cmd->buf == NULL) {
- fprintf(stderr, "fuse: failed to allocate read buffer\n");
- free(cmd);
- return NULL;
- }
- in = (struct fuse_in_header *) cmd->buf;
- inarg = cmd->buf + SIZEOF_COMPAT(f, 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)
- return NULL;
-
- /* ENODEV means we got unmounted, so we silenty return failure */
- if (errno != ENODEV) {
- /* BAD... This will happen again */
- perror("fuse: reading device");
- }
-
- fuse_exit(f);
- return NULL;
- }
- if ((size_t) res < SIZEOF_COMPAT(f, fuse_in_header)) {
- free_cmd(cmd);
- /* Cannot happen */
- fprintf(stderr, "short read on fuse device\n");
- fuse_exit(f);
- return NULL;
- }
- cmd->buflen = res;
-
- /* Forget is special, it can be done without messing with threads. */
- if (in->opcode == FUSE_FORGET) {
- do_forget(f, in, (struct fuse_forget_in *) inarg);
- free_cmd(cmd);
- return NULL;
- }
-
- return cmd;
+ return fuse_ll_read_cmd(f->fll);
}
int fuse_loop(struct fuse *f)
{
- if (f == NULL)
+ if (f)
+ return fuse_ll_loop(f->fll);
+ else
return -1;
-
- while (1) {
- struct fuse_cmd *cmd;
-
- if (fuse_exited(f))
- break;
-
- cmd = fuse_read_cmd(f);
- if (cmd == NULL)
- continue;
-
- fuse_process_cmd(f, cmd);
- }
- f->exited = 0;
- return 0;
}
int fuse_invalidate(struct fuse *f, const char *path)
@@ -2087,7 +1609,7 @@ int fuse_invalidate(struct fuse *f, const char *path)
void fuse_exit(struct fuse *f)
{
- f->exited = 1;
+ fuse_ll_exit(f->fll);
}
struct fuse_context *fuse_get_context()
@@ -2114,7 +1636,8 @@ static int begins_with(const char *s, const char *beg)
int fuse_is_lib_option(const char *opt)
{
- if (strcmp(opt, "debug") == 0 ||
+ if (fuse_ll_is_lib_option(opt) ||
+ strcmp(opt, "debug") == 0 ||
strcmp(opt, "hard_remove") == 0 ||
strcmp(opt, "use_ino") == 0 ||
strcmp(opt, "allow_root") == 0 ||
@@ -2127,12 +1650,13 @@ int fuse_is_lib_option(const char *opt)
return 0;
}
-static int parse_lib_opts(struct fuse *f, const char *opts)
+static int parse_lib_opts(struct fuse *f, const char *opts, char **llopts)
{
if (opts) {
char *xopts = strdup(opts);
char *s = xopts;
char *opt;
+ char *d = xopts;
if (xopts == NULL) {
fprintf(stderr, "fuse: memory allocation failed\n");
@@ -2140,14 +1664,17 @@ static int parse_lib_opts(struct fuse *f, const char *opts)
}
while((opt = strsep(&s, ","))) {
- if (strcmp(opt, "debug") == 0)
- f->flags |= FUSE_DEBUG;
- else if (strcmp(opt, "hard_remove") == 0)
+ if (fuse_ll_is_lib_option(opt)) {
+ size_t optlen = strlen(opt);
+ if (strcmp(opt, "debug") == 0)
+ f->flags |= FUSE_DEBUG;
+ memmove(d, opt, optlen);
+ d += optlen;
+ *d++ = ',';
+ } else if (strcmp(opt, "hard_remove") == 0)
f->flags |= FUSE_HARD_REMOVE;
else if (strcmp(opt, "use_ino") == 0)
f->flags |= FUSE_USE_INO;
- 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)
@@ -2159,7 +1686,12 @@ static int parse_lib_opts(struct fuse *f, const char *opts)
else
fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
}
- free(xopts);
+ if (d != xopts) {
+ d[-1] = '\0';
+ *llopts = xopts;
+ }
+ else
+ free(xopts);
}
return 0;
}
@@ -2170,6 +1702,7 @@ struct fuse *fuse_new_common(int fd, const char *opts,
{
struct fuse *f;
struct node *root;
+ char *llopts = NULL;
if (sizeof(struct fuse_operations) < op_size) {
fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
@@ -2182,10 +1715,14 @@ struct fuse *fuse_new_common(int fd, const char *opts,
goto out;
}
- if (parse_lib_opts(f, opts) == -1)
+ if (parse_lib_opts(f, opts, &llopts) == -1)
+ goto out_free;
+
+ f->fll = fuse_ll_new(fd, llopts, &fuse_path_ops, sizeof(fuse_path_ops), f);
+ free(llopts);
+ if (f->fll == NULL)
goto out_free;
- f->fd = fd;
f->ctr = 0;
f->generation = 0;
/* FIXME: Dynamic hash table */
@@ -2206,12 +1743,8 @@ struct fuse *fuse_new_common(int fd, const char *opts,
}
mutex_init(&f->lock);
- mutex_init(&f->worker_lock);
- f->numworker = 0;
- f->numavail = 0;
memcpy(&f->op, op, op_size);
f->compat = compat;
- f->exited = 0;
root = (struct node *) calloc(1, sizeof(struct node));
if (root == NULL) {
@@ -2232,8 +1765,6 @@ struct fuse *fuse_new_common(int fd, const char *opts,
root->nlookup = 1;
hash_id(f, root);
- f->owner = getuid();
-
return f;
out_free_root:
@@ -2299,9 +1830,7 @@ void fuse_destroy(struct fuse *f)
free(f->id_table);
free(f->name_table);
pthread_mutex_destroy(&f->lock);
- pthread_mutex_destroy(&f->worker_lock);
- if (f->op.destroy)
- f->op.destroy(f->user_data);
+ fuse_ll_destroy(f->fll);
free(f);
}