*** empty log message ***
authorMiklos Szeredi <miklos@szeredi.hu>
Fri, 26 Oct 2001 14:55:42 +0000 (14:55 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Fri, 26 Oct 2001 14:55:42 +0000 (14:55 +0000)
Makefile
dev.c
dir.c
fuse.h
fuse_i.h
fusemount.c
inode.c
util.c

index f8810fd2046992d07cb7d44f5ed4a926f0f2b94f..f264b7850fbb1488d4f31328af7ff0b84367fde9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,8 @@ CC = gcc
 KCFLAGS = -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -pipe
 KCPPFLAGS = -I /lib/modules/`uname -r`/build/include/ -D__KERNEL__ -DMODULE -D_LOOSE_KERNEL_NAMES
 
-CFLAGS = -Wall -W -g
+CFLAGS = -Wall -W -g `glib-config --cflags`
+LDFLAGS = `glib-config --libs`
 CPPFLAGS = 
 
 all: fuse.o fusemount
diff --git a/dev.c b/dev.c
index b6b99300300c2e0b4df65102ad9b12ba8c843ac2..16d8ad1acd04b7a75fdf4b36d0f94aa35f195a6b 100644 (file)
--- a/dev.c
+++ b/dev.c
 #include <linux/kernel.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
+#include <linux/file.h>
+
+#define ICSIZE sizeof(struct fuse_in_common)
+#define OCSIZE sizeof(struct fuse_out_common)
 
 static struct proc_dir_entry *proc_fs_fuse;
 struct proc_dir_entry *proc_fuse_dev;
@@ -38,8 +42,8 @@ static int request_wait_answer(struct fuse_req *req)
        return ret;
 }
 
-void request_send(struct fuse_conn *fc, struct fuse_inparam *in,
-                 struct fuse_outparam *out, int valuret)
+void request_send(struct fuse_conn *fc, struct fuse_in *in,
+                 struct fuse_out *out)
 {
        int ret;
        struct fuse_req *req;
@@ -50,13 +54,18 @@ void request_send(struct fuse_conn *fc, struct fuse_inparam *in,
                return;
        }
        
-       req->param.u.i = *in;
-       req->size = sizeof(req->param);
+       req->in = in;
+       req->out = out;
        req->done = 0;
        init_waitqueue_head(&req->waitq);
        
        spin_lock(&fuse_lock);
-       req->param.unique = fc->reqctr ++;
+       if(fc->file == NULL) {
+               ret = -ENOTCONN;
+               goto out;
+       }
+
+       req->in->h.unique = fc->reqctr ++;
        list_add_tail(&req->list, &fc->pending);
        fc->outstanding ++;
        /* FIXME: Wait until the number of outstanding requests drops
@@ -64,16 +73,17 @@ void request_send(struct fuse_conn *fc, struct fuse_inparam *in,
        wake_up(&fc->waitq);
        ret = request_wait_answer(req);
        fc->outstanding --;
-       *out = req->param.u.o;
        list_del(&req->list);
+
+  out:
        kfree(req);
        spin_unlock(&fuse_lock);
 
        if(ret)
                out->result = ret;
-       else if (out->result < -512 || (out->result > 0 && !valuret)) {
+       else if (out->result <= -512 || out->result > 0) {
                printk("Bad result from client: %i\n", out->result);
-               out->result = -EIO;
+               out->result = -EPROTO;
        }
 }
 
@@ -99,13 +109,13 @@ static int request_wait(struct fuse_conn *fc)
        return ret;
 }
 
+
 static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes,
                             loff_t *off)
 {
        ssize_t ret;
        struct fuse_conn *fc = file->private_data;
        struct fuse_req *req;
-       struct fuse_param param;
        size_t size;
 
        spin_lock(&fuse_lock);
@@ -113,13 +123,10 @@ static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes,
        if(ret)
                goto err;
        
-       printk(KERN_DEBUG "fuse_dev_read[%i]\n", fc->id);
-
        req = list_entry(fc->pending.next, struct fuse_req, list);
-       param = req->param;
-       size = req->size;
+       size = ICSIZE + req->in->argsize;
 
-       ret = -EIO;
+       ret = -EPROTO;
        if(nbytes < size) {
                printk("fuse_dev_read: buffer too small (%i)\n", size);
                goto err;
@@ -129,7 +136,8 @@ static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes,
        list_add_tail(&req->list, &fc->processing);
        spin_unlock(&fuse_lock);
 
-       if(copy_to_user(buf, &param, size))
+       if(copy_to_user(buf, &req->in->c, ICSIZE) ||
+          copy_to_user(buf + ICSIZE, req->in->arg, req->in->argsize))
                return -EFAULT;
        
        return size;
@@ -147,9 +155,8 @@ static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique)
        list_for_each(entry, &fc->processing) {
                struct fuse_req *tmp;
                tmp = list_entry(entry, struct fuse_req, list);
-               if(tmp->param.unique == unique) {
+               if(tmp->in->c.unique == unique) {
                        req = tmp;
-                       list_del_init(&req->list);
                        break;
                }
        }
@@ -161,25 +168,36 @@ static ssize_t fuse_dev_write(struct file *file, const char *buf,
                              size_t nbytes, loff_t *off)
 {
        struct fuse_conn *fc = file->private_data;
-       struct fuse_param param;
        struct fuse_req *req;
+       struct fuse_out_common oc;
+       char *tmpbuf;
 
-       printk(KERN_DEBUG "fuse_dev_write[%i]\n", fc->id);
-
-       if(nbytes < sizeof(param.unique) || nbytes > sizeof(param)) {
-               printk("fuse_dev_write: write is short or long\n");
-               return -EIO;
+       if(nbytes > 2 * PAGE_SIZE) {
+               printk("fuse_dev_write: write is too long\n");
+               return -EPROTO;
        }
+       
+       tmpbuf = (char *)  __get_free_pages(GFP_KERNEL, 1);
+       if(!tmpbuf)
+               return -ENOMEM;
 
-       if(copy_from_user(&param, buf, nbytes))
+       if(copy_from_user(tmpbuf, buf, nbytes))
                return -EFAULT;
-
+       
        spin_lock(&fuse_lock);
-       req = request_find(fc, param.unique);
+       req = request_find(fc, oc.unique);
+       
        if(req == NULL)
                printk("fuse_dev_write[%i]: unknown request: %i", fc->id,
-                      param.unique);
+                      oc.unique);
+
+               
+
        else {
+               struct fuse_outparam *out = &param.u.o;
+               if(req->param.u.i.opcode == FUSE_OPEN && out->result == 0)
+                       out->u.open_internal.file = fget(out->u.open.fd);
+
                req->param = param;
                req->done = 1;
                wake_up(&req->waitq);
@@ -231,8 +249,6 @@ static int fuse_dev_open(struct inode *inode, struct file *file)
 {
        struct fuse_conn *fc;
 
-       printk(KERN_DEBUG "fuse_dev_open\n");
-
        fc = new_conn();
        if(!fc)
                return -ENOMEM;
@@ -240,19 +256,29 @@ static int fuse_dev_open(struct inode *inode, struct file *file)
        fc->file = file;
        file->private_data = fc;
 
-       printk(KERN_DEBUG "new connection: %i\n", fc->id);
-
        return 0;
 }
 
+static void end_requests(struct list_head *head)
+{
+       while(!list_empty(head)) {
+               struct fuse_req *req;
+               req = list_entry(head->next, struct fuse_req, list);
+               list_del_init(&req->list);
+               req->done = 1;
+               req->param.u.o.result = -ECONNABORTED;
+               wake_up(&req->waitq);
+       }
+}
+
 static int fuse_dev_release(struct inode *inode, struct file *file)
 {
        struct fuse_conn *fc = file->private_data;
 
-       printk(KERN_DEBUG "fuse_dev_release[%i]\n", fc->id);
-
        spin_lock(&fuse_lock);
        fc->file = NULL;
+       end_requests(&fc->pending);
+       end_requests(&fc->processing);
        fuse_release_conn(fc);
        spin_unlock(&fuse_lock);
        return 0;
diff --git a/dir.c b/dir.c
index 6fa5959bf3ec5b643d31085b9917bdb40435a507..7a3ccc24a762bca30f72f28759adfefb4eb1ca1e 100644 (file)
--- a/dir.c
+++ b/dir.c
     See the file COPYING.
 */
 
-
 #include "fuse_i.h"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+
+static void change_attributes(struct inode *inode, struct fuse_attr *attr)
+{
+       inode->i_mode    = attr->mode;
+       inode->i_nlink   = attr->nlink;
+       inode->i_uid     = attr->uid;
+       inode->i_gid     = attr->gid;
+       inode->i_size    = attr->size;
+       inode->i_blksize = attr->blksize;
+       inode->i_blocks  = attr->blocks;
+       inode->i_atime   = attr->atime;
+       inode->i_mtime   = attr->mtime;
+       inode->i_ctime   = attr->ctime;
+}
+
+static void init_inode(struct inode *inode, struct fuse_attr *attr)
+{
+       change_attributes(inode, attr);
+       
+       if(S_ISREG(inode->i_mode))
+               fuse_file_init(inode);
+       else if(S_ISDIR(inode->i_mode))
+               fuse_dir_init(inode);
+       else if(S_ISLNK(inode->i_mode))
+               fuse_symlink_init(inode);
+       else
+               init_special_inode(inode, inode->i_mode, attr->rdev);
+}
 
 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
 {
-       printk(KERN_DEBUG "fuse_lookup: %li\n", dir->i_ino);
+       struct fuse_conn *fc = dir->i_sb->u.generic_sbp;
+       struct fuse_inparam in;
+       struct fuse_outparam out;
+       struct inode *inode;
+       
+       in.opcode = FUSE_LOOKUP;
+       in.ino = dir->i_ino;
+       strcpy(in.u.lookup.name, entry->d_name.name);
+
+       request_send(fc, &in, &out);
+       
+       if(out.result)
+               return ERR_PTR(out.result);
+
+       inode = iget(dir->i_sb, out.u.lookup.ino);
+       if(!inode) 
+               return ERR_PTR(-ENOMEM);
+
+       init_inode(inode, &out.u.lookup.attr);
 
+       d_add(entry, inode);
        return NULL;
 }
 
 static int fuse_permission(struct inode *inode, int mask)
 {
-       printk(KERN_DEBUG "fuse_permission: %li, 0%o\n", inode->i_ino, mask);
 
        return 0;
 }
 
 static int fuse_revalidate(struct dentry *dentry)
 {
-       printk(KERN_DEBUG "fuse_revalidate: %li\n",
-              dentry->d_inode->i_ino);
+       struct inode *inode = dentry->d_inode;
+       struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+       struct fuse_inparam in;
+       struct fuse_outparam out;
        
-       return 0;
+       in.opcode = FUSE_GETATTR;
+       in.ino = inode->i_ino;
+
+       request_send(fc, &in, &out);
+       
+       if(out.result == 0)
+               change_attributes(inode, &out.u.getattr.attr);
+
+       return out.result;
 }
-static int fuse_readdir(struct file *file, void *dirent, filldir_t filldir)
+
+
+#define DIR_BUFSIZE 2048
+
+static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
 {
-       printk(KERN_DEBUG "fuse_readdir: %li\n",
-              file->f_dentry->d_inode->i_ino);
+       struct file *cfile = file->private_data;
+       char *buf;
+       char *p;
+       int ret;
+       size_t nbytes;
        
+       buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
+       if(!buf)
+               return -ENOMEM;
+
+       ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
+       if(ret < 0) {
+               printk("fuse_readdir: failed to read container file\n");
+               goto out;
+       }
+       nbytes = ret;
+       p = buf;
+       ret = 0;
+       while(nbytes >= FUSE_NAME_OFFSET) {
+               struct fuse_dirent *dirent = (struct fuse_dirent *) p;
+               size_t reclen = FUSE_DIRENT_SIZE(dirent);
+               int err;
+               if(dirent->namelen > NAME_MAX) {
+                       printk("fuse_readdir: name too long\n");
+                       ret = -EPROTO;
+                       goto out;
+               }
+               if(reclen > nbytes)
+                       break;
+
+               err = filldir(dstbuf, dirent->name, dirent->namelen,
+                             file->f_pos, dirent->ino, dirent->type);
+               if(err) {
+                       ret = err;
+                       break;
+               }
+               p += reclen;
+               file->f_pos += reclen;
+               nbytes -= reclen;
+               ret ++;
+       }
+
+  out:
+       kfree(buf);     
+       return ret;
+}
+
+
+
+static int read_link(struct dentry *dentry, char **bufp)
+{
+       struct inode *inode = dentry->d_inode;
+       struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+       struct fuse_in in;
+       struct fuse_out out;
+       unsigned long page;
+
+       page = __get_free_page(GFP_KERNEL);
+       if(!page)
+               return -ENOMEM;
+
+       in.c.opcode = FUSE_READLINK;
+       in.c.ino = inode->i_ino;
+       in.argsize = 0;
+       out.arg = (void *) page;
+       out.argsize = PAGE_SIZE;
+       
+       request_send(fc, &in, &out);
+       if(out.c.result) {
+               __free_page(page);
+               return out.c.result;
+       }
+
+       *bufp = (char *) page;
+       (*bufp)[PAGE_SIZE - 1] = 0;
        return 0;
 }
 
+static void free_link(char *link)
+{
+       __free_page((unsigned long) link);
+}
+
+static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+       int ret;
+       char *link;
+
+       ret = read_link(dentry, &link);
+       if(ret)
+               return ret;
+
+       ret = vfs_readlink(dentry, buffer, buflen, link);
+       free_link(link);
+       return ret;
+}
+
+static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+       int ret;
+       char *link;
+
+       ret = read_link(dentry, &link);
+       if(ret)
+               return ret;
+
+       ret = vfs_follow_link(nd, link);
+       free_link(link);
+       return ret;
+}
+
 static int fuse_open(struct inode *inode, struct file *file)
 {
        struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
        struct fuse_inparam in;
        struct fuse_outparam out;
+       struct file *cfile = NULL;
        
-       printk(KERN_DEBUG "fuse_open: %li\n", inode->i_ino);
-
        in.opcode = FUSE_OPEN;
-       in.u.open.ino = inode->i_ino;
+       in.ino = inode->i_ino;
        in.u.open.flags = file->f_flags & ~O_EXCL;
 
-       request_send(fc, &in, &out, 0);
+       request_send(fc, &in, &out);
+       
+       if(out.result == 0) {
+               struct inode *inode;
+               cfile = out.u.open_internal.file;
+               if(!cfile) {
+                       printk("fuse_open: invalid container file\n");
+                       return -EPROTO;
+               }
+               inode = cfile->f_dentry->d_inode;
+               if(!S_ISREG(inode->i_mode)) {
+                       printk("fuse_open: container is not a regular file\n");
+                       fput(cfile);
+                       return -EPROTO;
+               }
 
-       printk(KERN_DEBUG "  fuse_open: <%i> %i\n", out.result, out.u.open.fd);
+               file->private_data = cfile;
+       }
 
        return out.result;
 }
 
 static int fuse_release(struct inode *inode, struct file *file)
 {
-       printk(KERN_DEBUG "fuse_release: %li\n", inode->i_ino);
+       struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+       struct file *cfile = file->private_data;
+       struct fuse_inparam in;
+       struct fuse_outparam out;
 
-       return 0;
+       if(cfile)
+               fput(cfile);
+
+       in.opcode = FUSE_RELEASE;
+       request_send(fc, &in, &out);
+
+       return out.result;
 }
 
 static struct inode_operations fuse_dir_inode_operations =
@@ -81,12 +271,38 @@ static struct file_operations fuse_dir_operations = {
        release:        fuse_release,
 };
 
+static struct inode_operations fuse_file_inode_operations =
+{
+       permission:     fuse_permission,
+        revalidate:    fuse_revalidate,
+};
+
+static struct file_operations fuse_file_operations = {
+};
+
+static struct inode_operations fuse_symlink_inode_operations =
+{
+       readlink:       fuse_readlink,
+       follow_link:    fuse_follow_link,
+        revalidate:    fuse_revalidate,
+};
+
 void fuse_dir_init(struct inode *inode)
 {
        inode->i_op = &fuse_dir_inode_operations;
        inode->i_fop = &fuse_dir_operations;
 }
 
+void fuse_file_init(struct inode *inode)
+{
+       inode->i_op = &fuse_file_inode_operations;
+       inode->i_fop = &fuse_file_operations;
+}
+
+void fuse_symlink_init(struct inode *inode)
+{
+       inode->i_op = &fuse_symlink_inode_operations;
+}
 
 /* 
  * Local Variables:
diff --git a/fuse.h b/fuse.h
index 32c2609336893fe97b2a925d5493c539f1a5fa6f..04faf9d7deb30c2de93bbe3ca97421db62a012e0 100644 (file)
--- a/fuse.h
+++ b/fuse.h
@@ -6,6 +6,7 @@
     See the file COPYING.
 */
 
+#include <linux/limits.h>
 
 #define FUSE_MOUNT_VERSION 1
 
@@ -14,39 +15,92 @@ struct fuse_mount_data {
        int fd;
 };
 
+#define FUSE_ROOT_INO 1
+
+struct fuse_attr {
+       unsigned short mode;
+       unsigned short nlink;
+       unsigned short uid;
+       unsigned short gid;
+       unsigned short rdev;
+       unsigned long  size;
+       unsigned long  blksize;
+       unsigned long  blocks;
+       unsigned long  atime;
+       unsigned long  mtime;
+       unsigned long  ctime;
+};
+
 enum fuse_opcode {
+       FUSE_LOOKUP,
+       FUSE_GETATTR,
+       FUSE_READLINK,
        FUSE_OPEN,
        FUSE_RELEASE,
 };
 
-struct fuse_inparam {
-       enum fuse_opcode opcode;
-       union {
-               struct {
-                       unsigned int ino;
-                       int flags;
-               } open;
-       } u;
+/* Conservative buffer size for the client */
+#define FUSE_MAX_IN 8192
+
+struct fuse_in_open {
+       int flag;
 };
 
-struct fuse_outparam {
-       int result;
-       union {
-               struct {
-                       int fd;
-               } open;
-       } u;
+struct fuse_out_open {
+       int fd;
+};
+
+struct fuse_in_lookup {
+       char name[NAME_MAX + 1];
+};
+
+struct fuse_out_lookup {
+       unsigned long ino;
+       struct fuse_attr attr;
+};
+
+struct fuse_out_getattr {
+       struct fuse_attr attr;
 };
 
-struct fuse_param {
+struct fuse_out_readlink {
+       char link[PATH_MAX + 1];
+};
+
+struct fuse_in_common {
+       int unique;
+       enum fuse_opcode opcode;
+       unsigned long ino;      
+};
+
+struct fuse_out_common {
        int unique;
        int result;
-       union {
-               struct fuse_inparam i;
-               struct fuse_outparam o;
-       } u;
 };
 
+struct fuse_in {
+       struct fuse_in_common c;
+       size_t argsize;
+       void *arg;
+};
+
+struct fuse_out {
+       struct fuse_out_common c;
+       size_t argsize;
+       void *arg;
+};
+
+struct fuse_dirent {
+       unsigned long ino;
+       unsigned short namelen;
+       unsigned char type;
+       char name[NAME_MAX + 1];
+};
+
+#define FUSE_NAME_OFFSET ((size_t) ((struct fuse_dirent *) 0)->name)
+#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(long) - 1) & ~(sizeof(long) - 1))
+#define FUSE_DIRENT_SIZE(d) \
+       FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
 
 /* 
  * Local Variables:
index a7a907feddfb6f0bd983dcd4dcce84f21acf0b3f..5f80620f1e1ecc3a630fe863fc4a2fe819f805f5 100644 (file)
--- a/fuse_i.h
+++ b/fuse_i.h
@@ -54,11 +54,14 @@ struct fuse_req {
        /** The request list */
        struct list_head list;
 
-       /** The size of the parameters */
-       size_t size;
+       /** The request input parameters */
+       struct fuse_in *in;
 
-       /** The request parameters */
-       struct fuse_param param;
+       /** The request result */
+       struct fuse_out *out;
+
+       /** The file returned by open */
+       struct file *file;
 
        /** The request wait queue */
        wait_queue_head_t waitq;
@@ -67,6 +70,11 @@ struct fuse_req {
        int done;
 };
 
+struct fuse_out_open_internal {
+       file *file;
+};
+
+
 /**
  * The proc entry for the client device ("/proc/fs/fuse/dev")
  */
@@ -82,6 +90,16 @@ extern spinlock_t fuse_lock;
  */
 void fuse_dir_init(struct inode *inode);
 
+/**
+ * Fill in the file operations
+ */
+void fuse_file_init(struct inode *inode);
+
+/**
+ * Fill in the symlink operations
+ */
+void fuse_symlink_init(struct inode *inode);
+
 /**
  * Check if the connection can be released, and if yes, then free the
  * connection structure
@@ -111,10 +129,9 @@ void fuse_fs_cleanup(void);
 /**
  * Send a request
  *
- * @valuret: if true then the request can return a positive value
  */
-void request_send(struct fuse_conn *fc, struct fuse_inparam *in,
-                 struct fuse_outparam *out, int valuret);
+void request_send(struct fuse_conn *fc, struct fuse_in *in,
+                 struct fuse_out *out);
 
 /*
  * Local Variables:
index 3ae293221d4d0484937a38e49c634dfe40456552..574a3fd8f9ec5f2dba5f078d3880c32317ea6435 100644 (file)
 #include "fuse.h"
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <signal.h>
+#include <dirent.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/mount.h>
 #include <mntent.h>
+#include <glib.h>
+
+static char *mount_dir;
+
+const char *basedir = "/tmp/pro";
+
+struct node {
+    char *name;
+    unsigned long ino;
+};
+
+static GNode *root;
+static GHashTable *nodetab;
+static unsigned long inoctr = FUSE_ROOT_INO;
+
+static GNode *new_node(const char *name, unsigned long ino)
+{
+    struct node *node = g_new0(struct node, 1);
+    GNode *gn = g_node_new(node);
+    
+    node->name = g_strdup(name);
+    node->ino = ino;
+
+    return gn;
+}
+
+static unsigned long find_node(unsigned long ino, const char *name)
+{
+    GNode *cn;
+    GNode *pn = g_hash_table_lookup(nodetab, (gpointer) ino);
+    if(pn == NULL) {
+        fprintf(stderr, "Can't find parent node %li\n", ino);
+        return 0;
+    }
+    
+    for(cn = pn->children; cn != NULL; cn = cn->next) {
+        struct node *node = (struct node *) cn->data;
+        if(strcmp(node->name, name) == 0)
+            return node->ino;
+    }
+
+    do inoctr++;
+    while(!inoctr && g_hash_table_lookup(nodetab, (gpointer) ino) != NULL);
+    
+    cn = new_node(name, inoctr);
+    g_node_insert(pn, -1, cn);
+    g_hash_table_insert(nodetab, (gpointer) inoctr, cn);
+    
+    return inoctr;
+}
+
+static char *real_path(unsigned long ino)
+{
+    GString *s;
+    char *ss;
+    GNode *gn = g_hash_table_lookup(nodetab, (gpointer) ino);
+
+    if(gn == NULL) {
+        fprintf(stderr, "Can't find node %li\n", ino);
+        return NULL;
+    }
+    
+    s = g_string_new("");
+    for(; gn != NULL; gn = gn->parent) {
+        g_string_prepend(s, ((struct node *) gn->data)->name);
+        g_string_prepend_c(s, '/');
+    }
+    g_string_prepend(s, basedir);
+    ss = s->str;
+    g_string_free(s, FALSE);
+    
+    return ss;
+}
+
+static int get_dir(unsigned long dir)
+{
+    int dirfd;
+    struct fuse_dirent dirent;
+    DIR *dp;
+    struct dirent *de;
+    size_t reclen;
+    char *path;
+    
+    path = real_path(dir);
+    if(path == NULL)
+        return -ENOENT;
+
+    dp = opendir(path);
+    g_free(path);
+    if(dp == NULL) {
+        perror(path);
+        return -errno;
+    }
+    dirfd = open("/tmp/dirtmp", O_RDWR | O_TRUNC | O_CREAT, 0600);
+    if(dirfd == -1) {
+        perror("/tmp/dirtmp");
+        exit(1);
+    }
+    while((de = readdir(dp)) != NULL) {
+        unsigned long ino = find_node(dir, de->d_name);
+        assert(ino != 0);
+
+        dirent.ino = ino;
+        dirent.namelen = strlen(de->d_name);
+        assert(dirent.namelen <= NAME_MAX);
+        strcpy(dirent.name, de->d_name);
+        dirent.type = de->d_type;
+
+        reclen = FUSE_DIRENT_SIZE(&dirent);
+        write(dirfd, &dirent, reclen);
+    }
+    closedir(dp);
+
+    return dirfd;
+}
+
+static int get_attributes(unsigned long ino, struct fuse_attr *attr)
+{
+    char *path;
+    struct stat buf;
+    int res;
+    
+    path = real_path(ino);
+    if(path == NULL)
+        return -ENOENT;
+
+    res = stat(path, &buf);
+    g_free(path);
+    if(res == -1)
+        return -errno;
+
+    attr->mode    = buf.st_mode;
+    attr->nlink   = buf.st_nlink;
+    attr->uid     = buf.st_uid;
+    attr->gid     = buf.st_gid;
+    attr->rdev    = buf.st_rdev;
+    attr->size    = buf.st_size;
+    attr->blksize = buf.st_blksize;
+    attr->blocks  = buf.st_blocks;
+    attr->atime   = buf.st_atime;
+    attr->mtime   = buf.st_mtime;
+    attr->ctime   = buf.st_ctime;
+    
+    return 0;
+}
 
 static void loop(int devfd)
 {
     int res;
     struct fuse_param param;
+    struct fuse_outparam out;
+    struct fuse_inparam in;
+    int dirfd;
     
     while(1) {
         res = read(devfd, &param, sizeof(param));
@@ -28,15 +182,53 @@ static void loop(int devfd)
             perror("read");
             exit(1);
         }
-        
+
         printf("unique: %i, opcode: %i\n", param.unique, param.u.i.opcode);
-        param.u.o.result = 0;
-        
+
+        dirfd = -1;
+        in = param.u.i;
+        switch(in.opcode) {
+        case FUSE_LOOKUP:
+            out.u.lookup.ino = find_node(in.ino, in.u.lookup.name);
+            if(out.u.lookup.ino == 0)
+                out.result = -ENOENT;
+            else
+                out.result = get_attributes(out.u.lookup.ino,
+                                            &out.u.lookup.attr);
+            break;
+
+        case FUSE_GETATTR:
+            out.result = get_attributes(in.ino, &out.u.getattr.attr);
+            break;
+
+        case FUSE_OPEN:
+            dirfd = get_dir(in.ino);
+            if(dirfd >= 0) {
+                out.u.open.fd = dirfd;
+                out.result = 0;
+            }
+            else
+                out.result = dirfd;
+            break;
+
+        case FUSE_RELEASE:
+            out.result = 0;
+            break;
+
+        default:
+            out.result = -EOPNOTSUPP;
+        }
+        param.u.o = out;
+                
         res = write(devfd, &param, sizeof(param));
         if(res == -1) {
             perror("write");
             exit(1);
         }
+        if(dirfd != -1) {
+            close(dirfd);
+            unlink("/tmp/dirtmp");
+        }
     }
 }
 
@@ -81,10 +273,98 @@ static int mount_fuse(const char *dev, const char *dir, int devfd)
     return 0;
 }
 
+int unmount_fuse(const char *dir)
+{
+    int res;
+    FILE *fdold, *fdnew;
+    struct mntent *entp;
+    
+    res = umount(dir);
+    
+    if(res == -1) {
+        fprintf(stderr, "umount failed: %s\n", strerror(errno));
+       return -1;
+    }
+    
+    fdold = setmntent("/etc/mtab", "r");
+    if(fdold == NULL) {
+       fprintf(stderr, "setmntent(\"/etc/mtab\") failed: %s\n",
+               strerror(errno));
+       return -1;
+    }
+
+    fdnew = setmntent("/etc/mtab~", "w");
+    if(fdnew == NULL) {
+       fprintf(stderr, "setmntent(\"/etc/mtab~\") failed: %s\n",
+               strerror(errno));
+       return -1;
+    }
+
+    do {
+       entp = getmntent(fdold);
+       if(entp != NULL) {
+           if(strcmp(entp->mnt_dir, dir) != 0) {
+               res = addmntent(fdnew, entp);
+               if(res != 0) {
+                   fprintf(stderr, "addmntent() failed: %s\n",
+                           strerror(errno));
+               }
+           }
+       }
+    } while(entp != NULL);
+
+    endmntent(fdold);
+    endmntent(fdnew);
+
+    res = rename("/etc/mtab~", "/etc/mtab");
+    if(res == -1) {
+       fprintf(stderr, "rename(\"/etc/mtab~\", \"/etc/mtab\") failed: %s\n", 
+               strerror(errno));
+       return -1;
+    }
+    
+    return 0;
+}
+
+void cleanup()
+{
+    unmount_fuse(mount_dir);
+}
+
+
+void exit_handler()
+{
+    exit(0);
+}
+
+void set_signal_handlers()
+{
+    struct sigaction sa;
+
+    sa.sa_handler = exit_handler;
+    sigemptyset(&(sa.sa_mask));
+    sa.sa_flags = 0;
+
+    if (sigaction(SIGHUP, &sa, NULL) == -1 || 
+       sigaction(SIGINT, &sa, NULL) == -1 || 
+       sigaction(SIGTERM, &sa, NULL) == -1) {
+       
+       perror("Cannot set exit signal handlers");
+        exit(1);
+    }
+
+    sa.sa_handler = SIG_IGN;
+    
+    if(sigaction(SIGPIPE, &sa, NULL) == -1) {
+       perror("Cannot set ignored signals");
+        exit(1);
+    }
+}
+
+
 int main(int argc, char *argv[])
 {
     const char *dev;
-    const char *dir;
     int devfd;
 
     if(argc < 3) {
@@ -93,7 +373,7 @@ int main(int argc, char *argv[])
     }
 
     dev = argv[1];
-    dir = argv[2];
+    mount_dir = argv[2];
 
     devfd = open(dev, O_RDWR);
     if(devfd == -1) {
@@ -101,9 +381,19 @@ int main(int argc, char *argv[])
         exit(1);
     }
 
-    mount_fuse(dev, dir, devfd);
+    mount_fuse(dev, mount_dir, devfd);
+
+    set_signal_handlers();
+    atexit(cleanup);
+
+    root = new_node("/", FUSE_ROOT_INO);
+    nodetab = g_hash_table_new(NULL, NULL);
+    g_hash_table_insert(nodetab, (gpointer) FUSE_ROOT_INO, root);
 
     loop(devfd);
     
     return 0;
 }
+
+
+
diff --git a/inode.c b/inode.c
index 590a80db5b2aa5e365bebbae78d7b50b2c2204f6..5c2b743f80e2ef7c0b4dac06209f4ef990978054 100644 (file)
--- a/inode.c
+++ b/inode.c
 
 static void fuse_read_inode(struct inode *inode)
 {
-       printk(KERN_DEBUG "fuse_read_inode: %li\n", inode->i_ino);
-
-       
+       /* No op */
 }
 
 static void fuse_put_super(struct super_block *sb)
 {
        struct fuse_conn *fc = sb->u.generic_sbp;
 
-       printk(KERN_DEBUG "fuse_put_super[%i]\n", fc->id);
-
        spin_lock(&fuse_lock);
        fc->sb = NULL;
        fuse_release_conn(fc);
@@ -47,8 +43,6 @@ static struct fuse_conn *get_conn(struct fuse_mount_data *d)
        struct file *file;
        struct inode *ino;
 
-       printk(KERN_DEBUG "fuse_read_super\n");
-
        if(d == NULL) {
                printk("fuse_read_super: Bad mount data\n");
                return NULL;
@@ -116,8 +110,6 @@ static struct super_block *fuse_read_super(struct super_block *sb,
                return NULL;
        }
 
-       printk(KERN_DEBUG "root inode: %ld/%d\n", root->i_ino, root->i_dev);
-
        spin_lock(&fuse_lock);
        fc = get_conn(data);
        if(fc == NULL)
diff --git a/util.c b/util.c
index c20ab64e1fd9524fdee964b8f75d5ef70a222016..57b1a90665bda064ef3d762ebb027d2a4408626e 100644 (file)
--- a/util.c
+++ b/util.c
@@ -20,7 +20,6 @@ spinlock_t fuse_lock = SPIN_LOCK_UNLOCKED;
 void fuse_release_conn(struct fuse_conn *fc)
 {
        if(fc->sb == NULL && fc->file == NULL) {
-               printk(KERN_DEBUG "fuse: release connection: %i\n", fc->id);
                kfree(fc);
        }
 }