fix
diff --git a/kernel/dir.c b/kernel/dir.c
index 076d966..38611c5 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -534,9 +534,9 @@
struct page *page;
struct inode *inode = file->f_dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req = fuse_get_request(fc);
+ struct fuse_req *req = fuse_get_request_nonint(fc);
if (!req)
- return -ERESTARTNOINTR;
+ return -EINTR;
page = alloc_page(GFP_KERNEL);
if (!page) {
diff --git a/kernel/file.c b/kernel/file.c
index 41e8d47..0405f7b 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -411,7 +411,7 @@
#endif /* KERNEL_2_6 */
static size_t fuse_send_write(struct fuse_req *req, struct file *file,
- struct inode *inode, loff_t pos, size_t count)
+ struct inode *inode, loff_t pos, size_t count)
{
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data;
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index 92fb703..e4d9588 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -321,11 +321,6 @@
#endif
};
-struct fuse_getdir_out_i {
- int fd;
- void *file; /* Used by kernel only */
-};
-
static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb)
{
#ifdef KERNEL_2_6
@@ -385,6 +380,23 @@
unsigned long nodeid, int version);
/**
+ * Send READ or READDIR request
+ */
+size_t fuse_send_read_common(struct fuse_req *req, struct file *file,
+ struct inode *inode, loff_t pos, size_t count,
+ int isdir);
+
+/**
+ * Send OPEN or OPENDIR request
+ */
+int fuse_open_common(struct inode *inode, struct file *file, int isdir);
+
+/**
+ * Send RELEASE or RELEASEDIR request
+ */
+int fuse_release_common(struct inode *inode, struct file *file, int isdir);
+
+/**
* Initialise file operations on a regular file
*/
void fuse_init_file_inode(struct inode *inode);
diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h
index 378791b..cd8f46f 100644
--- a/kernel/fuse_kernel.h
+++ b/kernel/fuse_kernel.h
@@ -67,7 +67,6 @@
FUSE_SETATTR = 4,
FUSE_READLINK = 5,
FUSE_SYMLINK = 6,
- FUSE_GETDIR = 7,
FUSE_MKNOD = 8,
FUSE_MKDIR = 9,
FUSE_UNLINK = 10,
@@ -85,7 +84,10 @@
FUSE_LISTXATTR = 23,
FUSE_REMOVEXATTR = 24,
FUSE_FLUSH = 25,
- FUSE_INIT = 26
+ FUSE_INIT = 26,
+ FUSE_OPENDIR = 27,
+ FUSE_READDIR = 28,
+ FUSE_RELEASEDIR = 29
};
/* Conservative buffer size for the client */
@@ -117,10 +119,6 @@
struct fuse_attr attr;
};
-struct fuse_getdir_out {
- __u32 fd;
-};
-
struct fuse_mknod_in {
__u32 mode;
__u32 rdev;
diff --git a/lib/fuse.c b/lib/fuse.c
index 25b62a0..8154feb 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -60,8 +60,8 @@
struct fuse_dirhandle {
struct fuse *fuse;
- nodeid_t dir;
FILE *fp;
+ int filled;
};
struct fuse_cmd {
@@ -72,6 +72,13 @@
static struct fuse_context *(*fuse_getcontext)(void) = NULL;
+/* Compatibility with kernel ABI version 5.1 */
+struct fuse_getdir_out {
+ __u32 fd;
+};
+
+#define FUSE_GETDIR 7
+
static const char *opname(enum fuse_opcode opcode)
{
switch (opcode) {
@@ -100,6 +107,9 @@
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";
default: return "???";
}
}
@@ -805,29 +815,37 @@
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_getdir(struct fuse *f, struct fuse_in_header *in)
{
int res;
struct fuse_getdir_out arg;
struct fuse_dirhandle dh;
- char *path;
dh.fuse = f;
dh.fp = tmpfile();
- dh.dir = in->nodeid;
res = -EIO;
if (dh.fp == NULL)
perror("fuse: failed to create temporary file");
else {
- 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);
- }
+ res = common_getdir(f, in, &dh);
fflush(dh.fp);
}
memset(&arg, 0, sizeof(struct fuse_getdir_out));
@@ -1520,6 +1538,88 @@
send_reply(f, in, 0, &outarg, sizeof(outarg));
}
+static struct fuse_dirhandle *get_dirhandle(unsigned long fh)
+{
+ return (struct fuse_dirhandle *) fh;
+}
+
+static void do_opendir(struct fuse *f, struct fuse_in_header *in,
+ struct fuse_open_in *arg)
+{
+ int res;
+ struct fuse_open_out outarg;
+ struct fuse_dirhandle *dh;
+
+ (void) arg;
+
+ res = -ENOMEM;
+ dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
+ if (dh != NULL) {
+ dh->fuse = f;
+ dh->fp = tmpfile();
+ dh->filled = 0;
+
+ res = -EIO;
+ if (dh->fp == NULL) {
+ perror("fuse: failed to create temporary file");
+ free(dh);
+ } else {
+ outarg.fh = (unsigned long) dh;
+ res = 0;
+ }
+ }
+ send_reply(f, in, res, &outarg, sizeof(outarg));
+}
+
+static void do_readdir(struct fuse *f, struct fuse_in_header *in,
+ struct fuse_read_in *arg)
+{
+ int res;
+ char *outbuf;
+ struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
+
+ if (!dh->filled) {
+ res = common_getdir(f, in, dh);
+ if (res)
+ send_reply(f, in, res, NULL, 0);
+ dh->filled = 1;
+ }
+ 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 = 0;
+ size_t outsize;
+ fseek(dh->fp, arg->offset, SEEK_SET);
+ res = fread(buf, 1, arg->size, dh->fp);
+ if (res == 0 && ferror(dh->fp))
+ res = -EIO;
+ else {
+ size = res;
+ res = 0;
+ }
+ memset(out, 0, sizeof(struct fuse_out_header));
+ out->unique = in->unique;
+ out->error = res;
+ outsize = sizeof(struct fuse_out_header) + size;
+
+ send_reply_raw(f, outbuf, outsize);
+ free(outbuf);
+ }
+}
+
+static void do_releasedir(struct fuse *f, struct fuse_in_header *in,
+ struct fuse_release_in *arg)
+{
+ struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
+ fclose(dh->fp);
+ free(dh);
+ send_reply(f, in, 0, NULL, 0);
+}
+
+
static void free_cmd(struct fuse_cmd *cmd)
{
free(cmd->buf);
@@ -1653,6 +1753,18 @@
do_init(f, in, (struct fuse_init_in_out *) inarg);
break;
+ case FUSE_OPENDIR:
+ do_opendir(f, in, (struct fuse_open_in *) inarg);
+ break;
+
+ case FUSE_READDIR:
+ do_readdir(f, in, (struct fuse_read_in *) inarg);
+ break;
+
+ case FUSE_RELEASEDIR:
+ do_releasedir(f, in, (struct fuse_release_in *) inarg);
+ break;
+
default:
send_reply(f, in, -ENOSYS, NULL, 0);
}
diff --git a/lib/helper.c b/lib/helper.c
index 2b15628..365b813 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -395,7 +395,7 @@
#undef fuse_main
int fuse_main()
{
- fprintf(stderr, "This function does not exist\n");
+ fprintf(stderr, "fuse_main(): This function does not exist\n");
return -1;
}