fix
authorMiklos Szeredi <miklos@szeredi.hu>
Tue, 18 Jan 2005 21:23:41 +0000 (21:23 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Tue, 18 Jan 2005 21:23:41 +0000 (21:23 +0000)
kernel/dir.c
kernel/file.c
kernel/fuse_i.h
kernel/fuse_kernel.h
lib/fuse.c
lib/helper.c

index 076d9662b4b311aa7ee550d8e4a41ca2b3955ca9..38611c5498515d4d93dec999c957ce09240f1f61 100644 (file)
@@ -534,9 +534,9 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
        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) {
index 41e8d4754629a2497a653240cdfec676e21a304f..0405f7be30da665a45098a425407a3137b069614 100644 (file)
@@ -411,7 +411,7 @@ static int fuse_file_bigread(struct file *file, struct inode *inode,
 #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;
index 92fb703a20b6774eab7692d153f05094348f0b55..e4d95880f70079cf3dc8d61f5082f61da6aab2e5 100644 (file)
@@ -321,11 +321,6 @@ struct fuse_conn {
 #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
@@ -384,6 +379,23 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
 void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
                      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
  */
index 378791b47dc734c960811a5023a3accb71604b35..cd8f46f2f7ffa4ec4fc2c042982d4af444ec28ee 100644 (file)
@@ -67,7 +67,6 @@ enum fuse_opcode {
        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 @@ enum fuse_opcode {
        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_out {
        struct fuse_attr attr;
 };
 
-struct fuse_getdir_out {
-       __u32   fd;
-};
-
 struct fuse_mknod_in {
        __u32   mode;
        __u32   rdev;
index 25b62a01caeb533be80b6cca671ba42dbc0cdd8a..8154feb5a34b5ae643e31cbaf2ef3368ab69bf5d 100644 (file)
@@ -60,8 +60,8 @@ struct node {
 
 struct fuse_dirhandle {
     struct fuse *fuse;
-    nodeid_t dir;
     FILE *fp;
+    int filled;
 };
 
 struct fuse_cmd {
@@ -72,6 +72,13 @@ struct fuse_cmd {
 
 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 @@ static const char *opname(enum fuse_opcode opcode)
     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 @@ 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_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 @@ static void do_init(struct fuse *f, struct fuse_in_header *in,
     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 @@ void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
         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);
     }
index 2b156282a7348845e9666d49c636acdb788b0288..365b813a59864220a00f2919ac91f6b4be26f1cc 100644 (file)
@@ -395,7 +395,7 @@ int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
 #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;
 }