aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--example/.cvsignore1
-rw-r--r--example/Makefile.am3
-rw-r--r--example/fusexmp.c18
-rw-r--r--example/fusexmp_fh.c355
-rw-r--r--example/hello.c14
-rw-r--r--include/fuse.h61
-rw-r--r--lib/fuse.c500
-rw-r--r--lib/fuse_kernel_compat5.h2
9 files changed, 637 insertions, 322 deletions
diff --git a/ChangeLog b/ChangeLog
index 8811780..d32280f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2005-04-07 Miklos Szeredi <miklos@szeredi.hu>
+
+ * lib: finalized new readdir() interface, which now supersedes the
+ getdir() method.
+
2005-04-03 Miklos Szeredi <miklos@szeredi.hu>
* Released 2.3-pre3
diff --git a/example/.cvsignore b/example/.cvsignore
index f9c7884..80eb82b 100644
--- a/example/.cvsignore
+++ b/example/.cvsignore
@@ -2,6 +2,7 @@ Makefile.in
Makefile
.deps
fusexmp
+fusexmp_fh
null
hello
.libs
diff --git a/example/Makefile.am b/example/Makefile.am
index e8c8a6d..be7a674 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -1,8 +1,9 @@
## Process this file with automake to produce Makefile.in
-noinst_PROGRAMS = fusexmp null hello
+noinst_PROGRAMS = fusexmp fusexmp_fh null hello
fusexmp_SOURCES = fusexmp.c
+fusexmp_fh_SOURCES = fusexmp_fh.c
null_SOURCES = null.c
hello_SOURCES = hello.c
diff --git a/example/fusexmp.c b/example/fusexmp.c
index 3230c36..95d26b3 100644
--- a/example/fusexmp.c
+++ b/example/fusexmp.c
@@ -49,24 +49,30 @@ static int xmp_readlink(const char *path, char *buf, size_t size)
}
-static int xmp_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
+static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ off_t offset, struct fuse_file_info *fi)
{
DIR *dp;
struct dirent *de;
- int res = 0;
+
+ (void) offset;
+ (void) fi;
dp = opendir(path);
if(dp == NULL)
return -errno;
while((de = readdir(dp)) != NULL) {
- res = filler(h, de->d_name, de->d_type, de->d_ino);
- if(res != 0)
+ struct stat st;
+ memset(&st, 0, sizeof(st));
+ st.st_ino = de->d_ino;
+ st.st_mode = de->d_type << 12;
+ if (filler(buf, de->d_name, &st, 0))
break;
}
closedir(dp);
- return res;
+ return 0;
}
static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
@@ -314,7 +320,7 @@ static int xmp_removexattr(const char *path, const char *name)
static struct fuse_operations xmp_oper = {
.getattr = xmp_getattr,
.readlink = xmp_readlink,
- .getdir = xmp_getdir,
+ .readdir = xmp_readdir,
.mknod = xmp_mknod,
.mkdir = xmp_mkdir,
.symlink = xmp_symlink,
diff --git a/example/fusexmp_fh.c b/example/fusexmp_fh.c
new file mode 100644
index 0000000..8a40c9e
--- /dev/null
+++ b/example/fusexmp_fh.c
@@ -0,0 +1,355 @@
+/*
+ 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 <config.h>
+
+#ifdef linux
+/* For pread()/pwrite() */
+#define _XOPEN_SOURCE 500
+#endif
+
+#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/statfs.h>
+#ifdef HAVE_SETXATTR
+#include <sys/xattr.h>
+#endif
+
+static int xmp_getattr(const char *path, struct stat *stbuf)
+{
+ int res;
+
+ res = lstat(path, stbuf);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_readlink(const char *path, char *buf, size_t size)
+{
+ int res;
+
+ res = readlink(path, buf, size - 1);
+ if(res == -1)
+ return -errno;
+
+ buf[res] = '\0';
+ return 0;
+}
+
+static int xmp_opendir(const char *path, struct fuse_file_info *fi)
+{
+ DIR *dp = opendir(path);
+ if (dp == NULL)
+ return -errno;
+
+ fi->fh = (unsigned long) dp;
+ return 0;
+}
+
+static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ off_t offset, struct fuse_file_info *fi)
+{
+ DIR *dp = (DIR *) fi->fh;
+ struct dirent *de;
+
+ (void) path;
+ seekdir(dp, offset);
+ while ((de = readdir(dp)) != NULL) {
+ struct stat st;
+ memset(&st, 0, sizeof(st));
+ st.st_ino = de->d_ino;
+ st.st_mode = de->d_type << 12;
+ if (filler(buf, de->d_name, &st, de->d_off))
+ break;
+ }
+
+ return 0;
+}
+
+static int xmp_releasedir(const char *path, struct fuse_file_info *fi)
+{
+ DIR *dp = (DIR *) fi->fh;
+ (void) path;
+ closedir(dp);
+ return 0;
+}
+
+static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
+{
+ int res;
+
+ res = mknod(path, mode, rdev);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_mkdir(const char *path, mode_t mode)
+{
+ int res;
+
+ res = mkdir(path, mode);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_unlink(const char *path)
+{
+ int res;
+
+ res = unlink(path);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_rmdir(const char *path)
+{
+ int res;
+
+ res = rmdir(path);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_symlink(const char *from, const char *to)
+{
+ int res;
+
+ res = symlink(from, to);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_rename(const char *from, const char *to)
+{
+ int res;
+
+ res = rename(from, to);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_link(const char *from, const char *to)
+{
+ int res;
+
+ res = link(from, to);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_chmod(const char *path, mode_t mode)
+{
+ int res;
+
+ res = chmod(path, mode);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_chown(const char *path, uid_t uid, gid_t gid)
+{
+ int res;
+
+ res = lchown(path, uid, gid);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_truncate(const char *path, off_t size)
+{
+ int res;
+
+ res = truncate(path, size);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_utime(const char *path, struct utimbuf *buf)
+{
+ int res;
+
+ res = utime(path, buf);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+
+static int xmp_open(const char *path, struct fuse_file_info *fi)
+{
+ int res;
+
+ res = open(path, fi->flags);
+ if(res == -1)
+ return -errno;
+
+ fi->fh = res;
+ return 0;
+}
+
+static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
+ struct fuse_file_info *fi)
+{
+ int res;
+
+ (void) path;
+ res = pread(fi->fh, buf, size, offset);
+ if(res == -1)
+ res = -errno;
+
+ return res;
+}
+
+static int xmp_write(const char *path, const char *buf, size_t size,
+ off_t offset, struct fuse_file_info *fi)
+{
+ int res;
+
+ (void) path;
+ res = pwrite(fi->fh, buf, size, offset);
+ if(res == -1)
+ res = -errno;
+
+ return res;
+}
+
+static int xmp_statfs(const char *path, struct statfs *stbuf)
+{
+ int res;
+
+ res = statfs(path, stbuf);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_release(const char *path, struct fuse_file_info *fi)
+{
+ (void) path;
+ close(fi->fh);
+
+ return 0;
+}
+
+static int xmp_fsync(const char *path, int isdatasync,
+ struct fuse_file_info *fi)
+{
+ int res;
+ (void) path;
+
+ if (isdatasync)
+ res = fdatasync(fi->fh);
+ else
+ res = fsync(fi->fh);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+#ifdef HAVE_SETXATTR
+/* xattr operations are optional and can safely be left unimplemented */
+static int xmp_setxattr(const char *path, const char *name, const char *value,
+ size_t size, int flags)
+{
+ int res = lsetxattr(path, name, value, size, flags);
+ if(res == -1)
+ return -errno;
+ return 0;
+}
+
+static int xmp_getxattr(const char *path, const char *name, char *value,
+ size_t size)
+{
+ int res = lgetxattr(path, name, value, size);
+ if(res == -1)
+ return -errno;
+ return res;
+}
+
+static int xmp_listxattr(const char *path, char *list, size_t size)
+{
+ int res = llistxattr(path, list, size);
+ if(res == -1)
+ return -errno;
+ return res;
+}
+
+static int xmp_removexattr(const char *path, const char *name)
+{
+ int res = lremovexattr(path, name);
+ if(res == -1)
+ return -errno;
+ return 0;
+}
+#endif /* HAVE_SETXATTR */
+
+static struct fuse_operations xmp_oper = {
+ .getattr = xmp_getattr,
+ .readlink = xmp_readlink,
+ .opendir = xmp_opendir,
+ .readdir = xmp_readdir,
+ .releasedir = xmp_releasedir,
+ .mknod = xmp_mknod,
+ .mkdir = xmp_mkdir,
+ .symlink = xmp_symlink,
+ .unlink = xmp_unlink,
+ .rmdir = xmp_rmdir,
+ .rename = xmp_rename,
+ .link = xmp_link,
+ .chmod = xmp_chmod,
+ .chown = xmp_chown,
+ .truncate = xmp_truncate,
+ .utime = xmp_utime,
+ .open = xmp_open,
+ .read = xmp_read,
+ .write = xmp_write,
+ .statfs = xmp_statfs,
+ .release = xmp_release,
+ .fsync = xmp_fsync,
+#ifdef HAVE_SETXATTR
+ .setxattr = xmp_setxattr,
+ .getxattr = xmp_getxattr,
+ .listxattr = xmp_listxattr,
+ .removexattr= xmp_removexattr,
+#endif
+};
+
+int main(int argc, char *argv[])
+{
+ return fuse_main(argc, argv, &xmp_oper);
+}
diff --git a/example/hello.c b/example/hello.c
index 9e4099b..b71bcd6 100644
--- a/example/hello.c
+++ b/example/hello.c
@@ -35,14 +35,18 @@ static int hello_getattr(const char *path, struct stat *stbuf)
return res;
}
-static int hello_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
+static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ off_t offset, struct fuse_file_info *fi)
{
+ (void) offset;
+ (void) fi;
+
if(strcmp(path, "/") != 0)
return -ENOENT;
- filler(h, ".", 0, 0);
- filler(h, "..", 0, 0);
- filler(h, hello_path + 1, 0, 0);
+ filler(buf, ".", NULL, 0);
+ filler(buf, "..", NULL, 0);
+ filler(buf, hello_path + 1, NULL, 0);
return 0;
}
@@ -79,7 +83,7 @@ static int hello_read(const char *path, char *buf, size_t size, off_t offset,
static struct fuse_operations hello_oper = {
.getattr = hello_getattr,
- .getdir = hello_getdir,
+ .readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
};
diff --git a/include/fuse.h b/include/fuse.h
index 35ec49f..336e8f3 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -47,33 +47,21 @@ extern "C" {
/** Handle for a FUSE filesystem */
struct fuse;
-/** Handle for a getdir() operation */
-typedef struct fuse_dirhandle *fuse_dirh_t;
-
-/** Function to add an entry in a getdir() operation
- *
- * @param h the handle passed to the getdir() operation
- * @param name the file name of the directory entry
- * @param type the file type (0 if unknown) see <dirent.h>
- * @param ino the inode number, ignored if "use_ino" mount option is
- * not specified
- * @return 0 on success, -errno on error
- */
-typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type,
- ino_t ino);
-
/** Function to add an entry in a readdir() operation
*
* @param buf the buffer passed to the readdir() operation
* @param name the file name of the directory entry
- * @param type the file type (0 if unknown) see <dirent.h>
- * @param ino the inode number, ignored if "use_ino" mount option is
- * not specified
- * @param off offset of the next entry
- * @return 0 on success, 1 if buffer is full
+ * @param stat file attributes, can be NULL
+ * @param off offset of the next entry or zero
+ * @return 1 if buffer is full, zero otherwise
*/
-typedef int (*fuse_dirfil5_t) (void *buf, const char *name, int type,
- ino_t ino, off_t off);
+typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
+ const struct stat *stat, off_t off);
+
+/* Used by deprecated getdir() method */
+typedef struct fuse_dirhandle *fuse_dirh_t;
+typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type,
+ ino_t ino);
/** Information about open files */
struct fuse_file_info {
@@ -99,7 +87,7 @@ struct fuse_file_info {
*
* All methods are optional, but some are essential for a useful
* filesystem (e.g. getattr). Flush, release, fsync, opendir,
- * readdir, releasedir, fsyncdir, init and destroy are special purpose
+ * releasedir, fsyncdir, init and destroy are special purpose
* methods, without which a full featured filesystem can still be
* implemented.
*/
@@ -122,12 +110,7 @@ struct fuse_operations {
*/
int (*readlink) (const char *, char *, size_t);
- /** Read the contents of a directory
- *
- * This operation is the opendir(), readdir(), ..., closedir()
- * sequence in one call. For each directory entry the filldir
- * function should be called.
- */
+ /* Deprecated, use readdir() instead */
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
/** Create a file node
@@ -265,10 +248,24 @@ struct fuse_operations {
/** Read directory
*
- * This is an alternative inteface to getdir(), and if defined
- * getdir() will not be called
+ * This supersedes the old getdir() interface. New applications
+ * should use this.
+ *
+ * The filesystem may choose between two modes of operation:
+ *
+ * 1) The readdir implementation ignores the offset parameter, and
+ * passes zero to the filler function's offset. The filler
+ * function will not return '1' (unless an error happens), so the
+ * whole directory is read in a single readdir operation. This
+ * works just like the old getdir() method.
+ *
+ * 2) The readdir implementation keeps track of the offsets of the
+ * directory entries. It uses the offset parameter and always
+ * passes non-zero offset to the filler function. When the buffer
+ * is full (or an error happens) the filler function will return
+ * '1'.
*/
- int (*readdir) (const char *, void *, fuse_dirfil5_t, off_t,
+ int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
struct fuse_file_info *);
/** Release directory */
diff --git a/lib/fuse.c b/lib/fuse.c
index 40230af..82adeb2 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -21,6 +21,7 @@
#include <assert.h>
#include <stdint.h>
#include <sys/param.h>
+#include <sys/uio.h>
/* FUSE flags: */
@@ -69,17 +70,15 @@ struct node {
};
struct fuse_dirhandle {
+ pthread_mutex_t lock;
struct fuse *fuse;
unsigned char *contents;
+ int allocated;
unsigned len;
+ unsigned needlen;
int filled;
unsigned long fh;
-};
-
-struct fuse_dirbuf {
- struct fuse *fuse;
- char *buf;
- unsigned len;
+ int error;
};
struct fuse_cmd {
@@ -90,6 +89,19 @@ struct fuse_cmd {
static struct fuse_context *(*fuse_getcontext)(void) = NULL;
+#ifndef USE_UCLIBC
+#define mutex_init(mut) pthread_mutex_init(mut, NULL)
+#else
+static void mutex_init(pthread_mutex_t mut)
+{
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
+ pthread_mutex_init(mut, &attr);
+ pthread_mutexattr_destroy(&attr);
+}
+#endif
+
static const char *opname(enum fuse_opcode opcode)
{
switch (opcode) {
@@ -453,103 +465,22 @@ static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
#endif
}
-static int fill_dir5(void *buf, const char *name, int type, ino_t ino,
- off_t off)
-{
- size_t namelen = strlen(name);
- size_t size;
- struct fuse_dirbuf *db = (struct fuse_dirbuf *) buf;
- struct fuse_dirent *dirent;
-
- if (db->len <= FUSE_NAME_OFFSET)
- return 1;
-
- dirent = (struct fuse_dirent *) db->buf;
- if ((db->fuse->flags & FUSE_USE_INO))
- dirent->ino = ino;
- else
- dirent->ino = (unsigned long) -1;
- dirent->off = off;
- dirent->namelen = namelen;
- dirent->type = type;
- size = FUSE_DIRENT_SIZE(dirent);
- if (db->len < size)
- return 1;
-
- strncpy(dirent->name, name, namelen);
- db->len -= size;
- db->buf += size;
- return db->len > FUSE_NAME_OFFSET ? 0 : 1;
-}
-
-static int fill_dir_compat5(struct fuse_dirhandle *dh, const char *name,
- int type, ino_t ino)
+static size_t iov_length(const struct iovec *iov, size_t count)
{
- size_t namelen = strlen(name);
- size_t entsize = sizeof(struct fuse_dirhandle) + namelen + 8;
- struct fuse_dirent_compat5 *dirent;
-
- if (namelen > FUSE_NAME_MAX)
- namelen = FUSE_NAME_MAX;
-
- dh->contents = realloc(dh->contents, dh->len + entsize);
- if (dh->contents == NULL)
- return -ENOMEM;
-
- dirent = (struct fuse_dirent_compat5 *) (dh->contents + dh->len);
- memset(dirent, 0, entsize);
- if ((dh->fuse->flags & FUSE_USE_INO))
- dirent->ino = ino;
- else
- dirent->ino = (unsigned long) -1;
- dirent->namelen = namelen;
- strncpy(dirent->name, name, namelen);
- dirent->type = type;
- dh->len += FUSE_DIRENT_SIZE_COMPAT5(dirent);
- return 0;
-}
-
-static int fill_dir_new(struct fuse_dirhandle *dh, const char *name, int type,
- ino_t ino)
-{
- size_t namelen = strlen(name);
- size_t entsize = sizeof(struct fuse_dirhandle) + namelen + 8;
- struct fuse_dirent *dirent;
-
- if (namelen > FUSE_NAME_MAX)
- namelen = FUSE_NAME_MAX;
-
- dh->contents = realloc(dh->contents, dh->len + entsize);
- if (dh->contents == NULL)
- return -ENOMEM;
-
- dirent = (struct fuse_dirent *) (dh->contents + dh->len);
- memset(dirent, 0, entsize);
- if ((dh->fuse->flags & FUSE_USE_INO))
- dirent->ino = ino;
- else
- dirent->ino = (unsigned long) -1;
- dirent->namelen = namelen;
- strncpy(dirent->name, name, namelen);
- dirent->type = type;
- dh->len += FUSE_DIRENT_SIZE(dirent);
- dirent->off = dh->len;
- return 0;
-}
+ size_t seg;
+ size_t ret = 0;
-static int fill_dir(struct fuse_dirhandle *dh, const char *name, int type,
- ino_t ino)
-{
- if (dh->fuse->major == 5)
- return fill_dir_compat5(dh, name, type, ino);
- else
- return fill_dir_new(dh, name, type, ino);
+ for (seg = 0; seg < count; seg++)
+ ret += iov[seg].iov_len;
+ return ret;
}
-static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
+static int send_reply_raw(struct fuse *f, const struct iovec iov[],
+ size_t count)
{
int res;
- struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
+ 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)) {
@@ -563,7 +494,7 @@ static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
increased long after the operation is done */
fuse_inc_avail(f);
- res = write(f->fd, outbuf, outsize);
+ res = writev(f->fd, iov, count);
if (res == -1) {
/* ENOENT means the operation was interrupted */
if (!f->exited && errno != ENOENT)
@@ -576,37 +507,26 @@ static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize)
static int send_reply(struct fuse *f, struct fuse_in_header *in, int error,
void *arg, size_t argsize)
{
- int res;
- char *outbuf;
- size_t outsize;
- struct fuse_out_header *out;
+ 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;
}
- if (error)
- argsize = 0;
-
- outsize = sizeof(struct fuse_out_header) + argsize;
- outbuf = (char *) malloc(outsize);
- if (outbuf == NULL) {
- fprintf(stderr, "fuse: failed to allocate reply buffer\n");
- res = -ENOMEM;
- } else {
- out = (struct fuse_out_header *) outbuf;
- memset(out, 0, sizeof(struct fuse_out_header));
- out->unique = in->unique;
- out->error = error;
- if (argsize != 0)
- memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
-
- res = send_reply_raw(f, outbuf, outsize);
- free(outbuf);
+ 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 res;
+ return send_reply_raw(f, iov, count);
}
static int is_open(struct fuse *f, nodeid_t dir, const char *name)
@@ -887,23 +807,6 @@ static void do_readlink(struct fuse *f, struct fuse_in_header *in)
send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
}
-static int common_getdir(struct fuse *f, struct fuse_in_header *in,
- struct fuse_dirhandle *dh)
-{
- int res;
- char *path;
-
- res = -ENOENT;
- path = get_path(f, in->nodeid);
- if (path != NULL) {
- res = -ENOSYS;
- if (f->op.getdir)
- res = f->op.getdir(path, dh, fill_dir);
- free(path);
- }
- return res;
-}
-
static void do_mknod(struct fuse *f, struct fuse_in_header *in,
struct fuse_mknod_in *inarg)
{
@@ -1237,52 +1140,47 @@ static void do_read(struct fuse *f, struct fuse_in_header *in,
{
int res;
char *path;
- char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
- if (outbuf == NULL)
- send_reply(f, in, -ENOMEM, NULL, 0);
- else {
- struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
- char *buf = outbuf + sizeof(struct fuse_out_header);
- size_t size;
- size_t outsize;
- struct fuse_file_info fi;
+ size_t size;
+ char *buf;
+ struct fuse_file_info fi;
- memset(&fi, 0, sizeof(fi));
- fi.fh = arg->fh;
+ buf = (char *) malloc(arg->size);
+ if (buf == NULL) {
+ send_reply(f, in, -ENOMEM, NULL, 0);
+ return;
+ }
- res = -ENOENT;
- path = get_path(f, in->nodeid);
- if (path != NULL) {
- if (f->flags & FUSE_DEBUG) {
- printf("READ[%lu] %u bytes from %llu\n",
- (unsigned long) arg->fh, arg->size, arg->offset);
- fflush(stdout);
- }
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
- res = -ENOSYS;
- if (f->op.read)
- res = f->op.read(path, buf, arg->size, arg->offset, &fi);
- free(path);
+ res = -ENOENT;
+ path = get_path(f, in->nodeid);
+ if (path != NULL) {
+ if (f->flags & FUSE_DEBUG) {
+ printf("READ[%lu] %u bytes from %llu\n",
+ (unsigned long) arg->fh, arg->size, arg->offset);
+ fflush(stdout);
}
- 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);
- fflush(stdout);
- }
- }
- memset(out, 0, sizeof(struct fuse_out_header));
- out->unique = in->unique;
- out->error = res;
- outsize = sizeof(struct fuse_out_header) + size;
+ res = -ENOSYS;
+ if (f->op.read)
+ res = f->op.read(path, buf, arg->size, arg->offset, &fi);
+ free(path);
+ }
- send_reply_raw(f, outbuf, outsize);
- free(outbuf);
+ 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);
+ fflush(stdout);
+ }
}
+
+ send_reply(f, in, res, buf, size);
+ free(buf);
}
static void do_write(struct fuse *f, struct fuse_in_header *in,
@@ -1313,6 +1211,7 @@ static void do_write(struct fuse *f, struct fuse_in_header *in,
free(path);
}
+ memset(&outarg, 0, sizeof(outarg));
if (res >= 0) {
outarg.size = res;
res = 0;
@@ -1443,26 +1342,19 @@ static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in,
const char *name, size_t size)
{
int res;
- char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
- if (outbuf == NULL)
+ char *value = (char *) malloc(size);
+ if (value == NULL) {
send_reply(f, in, -ENOMEM, NULL, 0);
- else {
- struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
- char *value = outbuf + sizeof(struct fuse_out_header);
-
- res = common_getxattr(f, in, name, value, size);
- size = 0;
- if (res > 0) {
- size = res;
- res = 0;
- }
- memset(out, 0, sizeof(struct fuse_out_header));
- out->unique = in->unique;
- out->error = res;
-
- send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
- free(outbuf);
+ return;
}
+ res = common_getxattr(f, in, name, value, size);
+ size = 0;
+ if (res > 0) {
+ size = res;
+ res = 0;
+ }
+ send_reply(f, in, res, value, size);
+ free(value);
}
static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
@@ -1471,6 +1363,7 @@ static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
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;
@@ -1511,26 +1404,19 @@ static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in,
size_t size)
{
int res;
- char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
- if (outbuf == NULL)
+ char *list = (char *) malloc(size);
+ if (list == NULL) {
send_reply(f, in, -ENOMEM, NULL, 0);
- else {
- struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
- char *list = outbuf + sizeof(struct fuse_out_header);
-
- res = common_listxattr(f, in, list, size);
- size = 0;
- if (res > 0) {
- size = res;
- res = 0;
- }
- memset(out, 0, sizeof(struct fuse_out_header));
- out->unique = in->unique;
- out->error = res;
-
- send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size);
- free(outbuf);
+ 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);
}
static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
@@ -1538,6 +1424,7 @@ static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
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;
@@ -1631,6 +1518,7 @@ static void do_opendir(struct fuse *f, struct fuse_in_header *in,
dh->contents = NULL;
dh->len = 0;
dh->filled = 0;
+ mutex_init(&dh->lock);
memset(&outarg, 0, sizeof(outarg));
outarg.fh = (unsigned long) dh;
@@ -1657,6 +1545,7 @@ static void do_opendir(struct fuse *f, struct fuse_in_header *in,
cancelled */
if(f->op.releasedir)
f->op.releasedir(path, &fi);
+ pthread_mutex_destroy(&dh->lock);
free(dh);
}
pthread_mutex_unlock(&f->lock);
@@ -1665,76 +1554,143 @@ static void do_opendir(struct fuse *f, struct fuse_in_header *in,
free(dh);
}
free(path);
- } else
+ } else
send_reply(f, in, 0, &outarg, SIZEOF_COMPAT(f, fuse_open_out));
}
-static void do_readdir(struct fuse *f, struct fuse_in_header *in,
- struct fuse_read_in *arg)
+static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
+ int type, ino_t ino, off_t off)
{
- int res;
- struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
- struct fuse_out_header *out;
- char *outbuf;
- char *buf;
- size_t size = 0;
- size_t outsize;
+ unsigned namelen = strlen(name);
+ unsigned entlen;
+ unsigned entsize;
+ unsigned padlen;
+ unsigned newlen;
+ unsigned char *newptr;
- outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
- if (outbuf == NULL) {
- send_reply(f, in, -ENOMEM, NULL, 0);
- return;
+ if (!(dh->fuse->flags & FUSE_USE_INO))
+ ino = (ino_t) -1;
+
+ if (namelen > FUSE_NAME_MAX)
+ namelen = FUSE_NAME_MAX;
+ else if (!namelen) {
+ dh->error = -EIO;
+ return 1;
}
- buf = outbuf + sizeof(struct fuse_out_header);
- if (f->op.readdir && f->major != 5) {
- struct fuse_dirbuf db;
- struct fuse_file_info fi;
- char *path;
+ entlen = (dh->fuse->major == 5 ?
+ FUSE_NAME_OFFSET_COMPAT5 : FUSE_NAME_OFFSET) + namelen;
+ entsize = FUSE_DIRENT_ALIGN(entlen);
+ padlen = entsize - entlen;
+ newlen = dh->len + entsize;
+ if (off && dh->fuse->major != 5) {
+ dh->filled = 0;
+ if (newlen > dh->needlen)
+ return 1;
+ }
+
+ newptr = realloc(dh->contents, newlen);
+ if (!newptr) {
+ dh->error = -ENOMEM;
+ 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);
+ dh->len = newlen;
+ return 0;
+}
- db.fuse = f;
- db.buf = buf;
- db.len = arg->size;
+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);
+}
+
+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);
+ return dh->error;
+}
+
+static int readdir_fill(struct fuse *f, struct fuse_in_header *in,
+ struct fuse_read_in *arg, struct fuse_dirhandle *dh)
+{
+ int err = -ENOENT;
+ char *path = get_path(f, in->nodeid);
+ if (path != NULL) {
+ struct fuse_file_info fi;
memset(&fi, 0, sizeof(fi));
fi.fh = dh->fh;
- path = get_path(f, in->nodeid);
- res = f->op.readdir(path ? path : "-", &db, fill_dir5, arg->offset, &fi);
+ dh->len = 0;
+ dh->error = 0;
+ dh->needlen = arg->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)
+ err = f->op.getdir(path, dh, fill_dir_old);
+ if (!err)
+ err = dh->error;
+ if (err)
+ dh->filled = 0;
free(path);
- if (res)
- goto err;
+ }
+ return err;
+}
- size = arg->size - db.len;
- } else {
- if (!dh->filled) {
- res = common_getdir(f, in, dh);
- if (res)
- goto err;
- dh->filled = 1;
- }
+static void do_readdir(struct fuse *f, struct fuse_in_header *in,
+ struct fuse_read_in *arg)
+{
+ int err = 0;
+ struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
+ size_t size = 0;
+ unsigned char *buf = NULL;
+ pthread_mutex_lock(&dh->lock);
+ if (!dh->filled) {
+ err = readdir_fill(f, in, arg, dh);
+ if (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;
-
- memcpy(buf, dh->contents + arg->offset, size);
+ buf = dh->contents + arg->offset;
}
+ } else {
+ size = dh->len;
+ buf = dh->contents;
}
- out = (struct fuse_out_header *) outbuf;
- memset(out, 0, sizeof(struct fuse_out_header));
- out->unique = in->unique;
- out->error = 0;
- outsize = sizeof(struct fuse_out_header) + size;
-
- send_reply_raw(f, outbuf, outsize);
- free(outbuf);
- return;
- err:
- send_reply(f, in, res, NULL, 0);
- free(outbuf);
+ 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,
@@ -1744,7 +1700,7 @@ static void do_releasedir(struct fuse *f, struct fuse_in_header *in,
if (f->op.releasedir) {
char *path;
struct fuse_file_info fi;
-
+
memset(&fi, 0, sizeof(fi));
fi.fh = dh->fh;
@@ -1752,6 +1708,9 @@ static void do_releasedir(struct fuse *f, struct fuse_in_header *in,
f->op.releasedir(path ? path : "-", &fi);
free(path);
}
+ pthread_mutex_lock(&dh->lock);
+ pthread_mutex_unlock(&dh->lock);
+ pthread_mutex_destroy(&dh->lock);
free(dh->contents);
free(dh);
send_reply(f, in, 0, NULL, 0);
@@ -2115,19 +2074,8 @@ struct fuse *fuse_new_common(int fd, const char *opts,
goto out_free_name_table;
}
-#ifndef USE_UCLIBC
- pthread_mutex_init(&f->lock, NULL);
- pthread_mutex_init(&f->worker_lock, NULL);
-#else
- {
- pthread_mutexattr_t attr;
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
- pthread_mutex_init(&f->lock, &attr);
- pthread_mutex_init(&f->worker_lock, &attr);
- pthread_mutexattr_destroy(&attr);
- }
-#endif
+ mutex_init(&f->lock);
+ mutex_init(&f->worker_lock);
f->numworker = 0;
f->numavail = 0;
memcpy(&f->op, op, op_size);
diff --git a/lib/fuse_kernel_compat5.h b/lib/fuse_kernel_compat5.h
index 8edca59..49936dc 100644
--- a/lib/fuse_kernel_compat5.h
+++ b/lib/fuse_kernel_compat5.h
@@ -38,5 +38,3 @@ struct fuse_dirent_compat5 {
};
#define FUSE_NAME_OFFSET_COMPAT5 ((unsigned) ((struct fuse_dirent_compat5 *) 0)->name)
-#define FUSE_DIRENT_SIZE_COMPAT5(d) \
- FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_COMPAT5 + (d)->namelen)