x
authorMiklos Szeredi <miklos@szeredi.hu>
Sun, 28 Oct 2001 19:44:14 +0000 (19:44 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Sun, 28 Oct 2001 19:44:14 +0000 (19:44 +0000)
21 files changed:
Makefile
dev.c [deleted file]
dir.c [deleted file]
fuse.h [deleted file]
fuse_i.h [deleted file]
fusemount.c [deleted file]
fusepro.c [new file with mode: 0644]
include/fuse.h [new file with mode: 0644]
include/linux/fuse.h [new file with mode: 0644]
inode.c [deleted file]
kernel/Makefile [new file with mode: 0644]
kernel/dev.c [new file with mode: 0644]
kernel/dir.c [new file with mode: 0644]
kernel/fuse_i.h [new file with mode: 0644]
kernel/inode.c [new file with mode: 0644]
kernel/util.c [new file with mode: 0644]
lib/Makefile [new file with mode: 0644]
lib/fuse.c [new file with mode: 0644]
lib/fuse_i.h [new file with mode: 0644]
lib/mount.c [new file with mode: 0644]
util.c [deleted file]

index f264b7850fbb1488d4f31328af7ff0b84367fde9..9f6ff4b10129f100a31940eccea1217c209cce9d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,34 +1,25 @@
 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 `glib-config --cflags`
 LDFLAGS = `glib-config --libs`
-CPPFLAGS = 
-
-all: fuse.o fusemount
+CPPFLAGS = -Iinclude
 
-dev.o: dev.c
-       $(CC) $(KCFLAGS) $(KCPPFLAGS) -c dev.c
 
-inode.o: inode.c
-       $(CC) $(KCFLAGS) $(KCPPFLAGS) -c inode.c
 
-dir.o: dir.c
-       $(CC) $(KCFLAGS) $(KCPPFLAGS) -c dir.c
+all: kernel/fuse.o fusepro
 
-util.o: util.c
-       $(CC) $(KCFLAGS) $(KCPPFLAGS) -c util.c
+kernel/fuse.o: FORCE
+       make -C kernel fuse.o
 
-fuse_objs = dev.o inode.o dir.o util.o
+lib/libfuse.a: FORCE
+       make -C lib libfuse.a
 
-fuse.o: $(fuse_objs)
-       ld -r -o fuse.o $(fuse_objs)
-
-fusemount: fusemount.o
+fusepro: fusepro.o lib/libfuse.a
 
 clean:
+       make -C kernel clean
+       make -C lib clean
        rm -f *.o
-       rm -f fusemount
+       rm -f fusepro
        rm -f *~
+
+FORCE:
diff --git a/dev.c b/dev.c
deleted file mode 100644 (file)
index 16d8ad1..0000000
--- a/dev.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
-    FUSE: Filesystem in Userspace
-    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
-
-    This program can be distributed under the terms of the GNU GPL.
-    See the file COPYING.
-*/
-
-#include "fuse_i.h"
-
-#include <linux/module.h>
-#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;
-
-static int request_wait_answer(struct fuse_req *req)
-{
-       int ret = 0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(&req->waitq, &wait);
-       while(!req->done) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if(signal_pending(current)) {
-                       ret = -EINTR;
-                       break;
-               }
-               spin_unlock(&fuse_lock);
-               schedule();
-               spin_lock(&fuse_lock);
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&req->waitq, &wait);
-
-       return ret;
-}
-
-void request_send(struct fuse_conn *fc, struct fuse_in *in,
-                 struct fuse_out *out)
-{
-       int ret;
-       struct fuse_req *req;
-
-       req = kmalloc(sizeof(*req), GFP_KERNEL);
-       if(req == NULL) {
-               out->result = -ENOMEM;
-               return;
-       }
-       
-       req->in = in;
-       req->out = out;
-       req->done = 0;
-       init_waitqueue_head(&req->waitq);
-       
-       spin_lock(&fuse_lock);
-       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
-           below a certain level */
-       wake_up(&fc->waitq);
-       ret = request_wait_answer(req);
-       fc->outstanding --;
-       list_del(&req->list);
-
-  out:
-       kfree(req);
-       spin_unlock(&fuse_lock);
-
-       if(ret)
-               out->result = ret;
-       else if (out->result <= -512 || out->result > 0) {
-               printk("Bad result from client: %i\n", out->result);
-               out->result = -EPROTO;
-       }
-}
-
-static int request_wait(struct fuse_conn *fc)
-{
-       int ret = 0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(&fc->waitq, &wait);
-       while(list_empty(&fc->pending)) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if(signal_pending(current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-               spin_unlock(&fuse_lock);
-               schedule();
-               spin_lock(&fuse_lock);
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&fc->waitq, &wait);
-
-       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;
-       size_t size;
-
-       spin_lock(&fuse_lock);
-       ret = request_wait(fc);
-       if(ret)
-               goto err;
-       
-       req = list_entry(fc->pending.next, struct fuse_req, list);
-       size = ICSIZE + req->in->argsize;
-
-       ret = -EPROTO;
-       if(nbytes < size) {
-               printk("fuse_dev_read: buffer too small (%i)\n", size);
-               goto err;
-       }
-       
-       list_del(&req->list);
-       list_add_tail(&req->list, &fc->processing);
-       spin_unlock(&fuse_lock);
-
-       if(copy_to_user(buf, &req->in->c, ICSIZE) ||
-          copy_to_user(buf + ICSIZE, req->in->arg, req->in->argsize))
-               return -EFAULT;
-       
-       return size;
-
-  err:
-       spin_unlock(&fuse_lock);
-       return ret;
-}
-
-static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique)
-{
-       struct list_head *entry;
-       struct fuse_req *req = NULL;
-
-       list_for_each(entry, &fc->processing) {
-               struct fuse_req *tmp;
-               tmp = list_entry(entry, struct fuse_req, list);
-               if(tmp->in->c.unique == unique) {
-                       req = tmp;
-                       break;
-               }
-       }
-
-       return req;
-}
-
-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_req *req;
-       struct fuse_out_common oc;
-       char *tmpbuf;
-
-       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(tmpbuf, buf, nbytes))
-               return -EFAULT;
-       
-       spin_lock(&fuse_lock);
-       req = request_find(fc, oc.unique);
-       
-       if(req == NULL)
-               printk("fuse_dev_write[%i]: unknown request: %i", fc->id,
-                      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);
-       }
-       spin_unlock(&fuse_lock);
-
-       return nbytes;
-}
-
-
-static unsigned int fuse_dev_poll(struct file *file, poll_table *wait)
-{
-       struct fuse_conn *fc = file->private_data;
-       unsigned int mask = POLLOUT | POLLWRNORM;
-
-       poll_wait(file, &fc->waitq, wait);
-
-       spin_lock(&fuse_lock);
-       if (!list_empty(&fc->pending))
-                mask |= POLLIN | POLLRDNORM;
-       spin_unlock(&fuse_lock);
-
-       return mask;
-}
-
-static struct fuse_conn *new_conn(void)
-{
-       static int connctr = 1;
-       struct fuse_conn *fc;
-
-       fc = kmalloc(sizeof(*fc), GFP_KERNEL);
-       if(fc != NULL) {
-               fc->sb = NULL;
-               fc->file = NULL;
-               init_waitqueue_head(&fc->waitq);
-               INIT_LIST_HEAD(&fc->pending);
-               INIT_LIST_HEAD(&fc->processing);
-               fc->outstanding = 0;
-               fc->reqctr = 0;
-               
-               spin_lock(&fuse_lock);
-               fc->id = connctr ++;
-               spin_unlock(&fuse_lock);
-       }
-       return fc;
-}
-
-static int fuse_dev_open(struct inode *inode, struct file *file)
-{
-       struct fuse_conn *fc;
-
-       fc = new_conn();
-       if(!fc)
-               return -ENOMEM;
-
-       fc->file = file;
-       file->private_data = fc;
-
-       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;
-
-       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;
-}
-
-static struct file_operations fuse_dev_operations = {
-       owner:          THIS_MODULE,
-       read:           fuse_dev_read,
-       write:          fuse_dev_write,
-       poll:           fuse_dev_poll,
-       open:           fuse_dev_open,
-       release:        fuse_dev_release,
-};
-
-int fuse_dev_init()
-{
-       int ret;
-
-       proc_fs_fuse = NULL;
-       proc_fuse_dev = NULL;
-
-       ret = -EIO;
-       proc_fs_fuse = proc_mkdir("fuse", proc_root_fs);
-       if(!proc_fs_fuse) {
-               printk("fuse: failed to create directory in /proc/fs\n");
-               goto err;
-       }
-
-       proc_fs_fuse->owner = THIS_MODULE;
-       proc_fuse_dev = create_proc_entry("dev", S_IFSOCK | S_IRUGO | S_IWUGO,
-                                         proc_fs_fuse);
-       if(!proc_fuse_dev) {
-               printk("fuse: failed to create entry in /proc/fs/fuse\n");
-               goto err;
-       }
-
-       proc_fuse_dev->proc_fops = &fuse_dev_operations;
-
-       return 0;
-
-  err:
-       fuse_dev_cleanup();
-       return ret;
-}
-
-void fuse_dev_cleanup()
-{
-       if(proc_fs_fuse) {
-               remove_proc_entry("dev", proc_fs_fuse);
-               remove_proc_entry("fuse", proc_root_fs);
-       }
-}
-
-/* 
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */
diff --git a/dir.c b/dir.c
deleted file mode 100644 (file)
index 7a3ccc2..0000000
--- a/dir.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
-    FUSE: Filesystem in Userspace
-    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
-
-    This program can be distributed under the terms of the GNU GPL.
-    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)
-{
-       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)
-{
-
-       return 0;
-}
-
-static int fuse_revalidate(struct dentry *dentry)
-{
-       struct inode *inode = dentry->d_inode;
-       struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
-       struct fuse_inparam in;
-       struct fuse_outparam out;
-       
-       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;
-}
-
-
-#define DIR_BUFSIZE 2048
-
-static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
-{
-       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;
-       
-       in.opcode = FUSE_OPEN;
-       in.ino = inode->i_ino;
-       in.u.open.flags = file->f_flags & ~O_EXCL;
-
-       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;
-               }
-
-               file->private_data = cfile;
-       }
-
-       return out.result;
-}
-
-static int fuse_release(struct inode *inode, struct file *file)
-{
-       struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
-       struct file *cfile = file->private_data;
-       struct fuse_inparam in;
-       struct fuse_outparam out;
-
-       if(cfile)
-               fput(cfile);
-
-       in.opcode = FUSE_RELEASE;
-       request_send(fc, &in, &out);
-
-       return out.result;
-}
-
-static struct inode_operations fuse_dir_inode_operations =
-{
-       lookup:         fuse_lookup,
-       permission:     fuse_permission,
-        revalidate:    fuse_revalidate,
-};
-
-static struct file_operations fuse_dir_operations = {
-       read:           generic_read_dir,
-       readdir:        fuse_readdir,
-       open:           fuse_open,
-       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:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */
diff --git a/fuse.h b/fuse.h
deleted file mode 100644 (file)
index 04faf9d..0000000
--- a/fuse.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
-    FUSE: Filesystem in Userspace
-    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
-
-    This program can be distributed under the terms of the GNU GPL.
-    See the file COPYING.
-*/
-
-#include <linux/limits.h>
-
-#define FUSE_MOUNT_VERSION 1
-
-struct fuse_mount_data {
-       int version;
-       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,
-};
-
-/* Conservative buffer size for the client */
-#define FUSE_MAX_IN 8192
-
-struct fuse_in_open {
-       int flag;
-};
-
-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_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;
-};
-
-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:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */
diff --git a/fuse_i.h b/fuse_i.h
deleted file mode 100644 (file)
index 5f80620..0000000
--- a/fuse_i.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
-    FUSE: Filesystem in Userspace
-    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
-
-    This program can be distributed under the terms of the GNU GPL.
-    See the file COPYING.
-*/
-
-#include "fuse.h"
-
-#include <linux/fs.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-
-#define FUSE_VERSION "0.1"
-
-/**
- * A Fuse connection.
- *
- * This structure is created, when the client device is opened, and is
- * destroyed, when the client device is closed _and_ the filesystem is
- * umounted.
- */
-struct fuse_conn {
-       /** The superblock of the mounted filesystem */
-       struct super_block *sb;
-       
-       /** The opened client device */
-       struct file *file;
-
-       /** The client wait queue */
-       wait_queue_head_t waitq;
-
-       /** The list of pending requests */
-       struct list_head pending;
-
-       /** The list of requests being processed */
-       struct list_head processing;
-
-       /** The number of outstanding requests */
-       int outstanding;
-
-       /** Connnection number (for debuging) */
-       int id;
-
-       /** The request id */
-       int reqctr;
-};
-
-/**
- * A request to the client
- */
-struct fuse_req {
-       /** The request list */
-       struct list_head list;
-
-       /** The request input parameters */
-       struct fuse_in *in;
-
-       /** The request result */
-       struct fuse_out *out;
-
-       /** The file returned by open */
-       struct file *file;
-
-       /** The request wait queue */
-       wait_queue_head_t waitq;
-
-       /** True if the request is finished */
-       int done;
-};
-
-struct fuse_out_open_internal {
-       file *file;
-};
-
-
-/**
- * The proc entry for the client device ("/proc/fs/fuse/dev")
- */
-extern struct proc_dir_entry *proc_fuse_dev;
-
-/**
- * The lock to protect fuses structures
- */
-extern spinlock_t fuse_lock;
-
-/**
- * Fill in the directory operations
- */
-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
- */
-void fuse_release_conn(struct fuse_conn *fc);
-
-/**
- * Initialize the client device
- */
-int fuse_dev_init(void);
-
-/**
- * Cleanup the client device
- */
-void fuse_dev_cleanup(void);
-
-/**
- * Initialize the fuse filesystem 
- */
-int fuse_fs_init(void);
-
-/**
- * Cleanup the fuse filesystem
- */
-void fuse_fs_cleanup(void);
-
-/**
- * Send a request
- *
- */
-void request_send(struct fuse_conn *fc, struct fuse_in *in,
-                 struct fuse_out *out);
-
-/*
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- */
diff --git a/fusemount.c b/fusemount.c
deleted file mode 100644 (file)
index 574a3fd..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
-    AVFS: A Virtual File System Library
-    Copyright (C) 1998-2001  Miklos Szeredi (mszeredi@inf.bme.hu)
-
-    This program can be distributed under the terms of the GNU GPL.
-    See the file COPYING.
-*/
-
-#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));
-        if(res == -1) {
-            perror("read");
-            exit(1);
-        }
-
-        printf("unique: %i, opcode: %i\n", param.unique, param.u.i.opcode);
-
-        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");
-        }
-    }
-}
-
-static int mount_fuse(const char *dev, const char *dir, int devfd)
-{
-    int res;
-    const char *type;
-    FILE *fd;
-    struct mntent ent;
-    struct fuse_mount_data data;
-    
-    data.version = FUSE_MOUNT_VERSION;
-    data.fd = devfd;
-
-    type = "fuse";
-    res = mount(dev, dir, type, MS_MGC_VAL | MS_NOSUID | MS_NODEV, &data);
-    
-    if(res == -1) {
-        fprintf(stderr, "mount failed: %s\n", strerror(errno));
-       return -1;
-    }
-    
-    fd = setmntent("/etc/mtab", "a");
-    if(fd == NULL) {
-       fprintf(stderr, "setmntent(\"/etc/mtab\") failed: %s\n",
-               strerror(errno));
-       return -1;
-    }
-    
-    ent.mnt_fsname = (char *) dev;
-    ent.mnt_dir = (char *) dir;
-    ent.mnt_type = (char *) type;
-    ent.mnt_opts = "rw,nosuid,nodev";
-    ent.mnt_freq = 0;
-    ent.mnt_passno = 0;
-    res = addmntent(fd, & ent);
-    if(res != 0)
-       fprintf(stderr, "addmntent() failed: %s\n", strerror(errno));
-    
-    endmntent(fd);
-    
-    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;
-    int devfd;
-
-    if(argc < 3) {
-        fprintf(stderr, "usage: %s dev dir\n", argv[0]);
-        exit(1);
-    }
-
-    dev = argv[1];
-    mount_dir = argv[2];
-
-    devfd = open(dev, O_RDWR);
-    if(devfd == -1) {
-        fprintf(stderr, "failed to open %s: %s\n", dev, strerror(errno));
-        exit(1);
-    }
-
-    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/fusepro.c b/fusepro.c
new file mode 100644 (file)
index 0000000..4c0582c
--- /dev/null
+++ b/fusepro.c
@@ -0,0 +1,125 @@
+#include <fuse.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+
+static struct fuse *pro_fuse;
+
+static int pro_getattr(const char *path, struct stat *stbuf)
+{
+    int res;
+
+    res = lstat(path, stbuf);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int pro_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 pro_getdir(const char *path, struct fuse_dh *h, dirfiller_t filler)
+{
+    DIR *dp;
+    struct dirent *de;
+    int res;
+
+    dp = opendir(path);
+    if(dp == NULL)
+        return -errno;
+
+    while((de = readdir(dp)) != NULL) {
+        res = filler(h, de->d_name, de->d_type);
+        if(res != 0)
+            break;
+    }
+
+    closedir(dp);
+    return res;
+}
+
+static int pro_mknod(const char *path, int mode, int rdev)
+{
+    int res;
+
+    res = mknod(path, mode, rdev);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static void exit_handler()
+{
+    exit(0);
+}
+
+static 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);
+    }
+}
+
+static void cleanup()
+{
+    fuse_unmount(pro_fuse);
+    fuse_destroy(pro_fuse);
+}
+
+static struct fuse_operations pro_oper = {
+    getattr:   pro_getattr,
+    readlink:  pro_readlink,
+    getdir:     pro_getdir,
+    mknod:     pro_mknod,
+};
+
+int main(int argc, char *argv[])
+{
+    if(argc != 2) {
+        fprintf(stderr, "usage: %s mount_dir\n", argv[0]);
+        exit(1);
+    }
+
+    set_signal_handlers();
+    atexit(cleanup);
+
+    pro_fuse = fuse_new();
+    fuse_mount(pro_fuse, argv[1]);
+    fuse_set_operations(pro_fuse, &pro_oper);
+    fuse_loop(pro_fuse);
+
+    return 0;
+}
diff --git a/include/fuse.h b/include/fuse.h
new file mode 100644 (file)
index 0000000..6b1a151
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+/* This file defines the library interface of FUSE */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+struct fuse;
+struct fuse_dh;
+
+typedef int (*dirfiller_t) (struct fuse_dh *, const char *, int type);
+
+
+struct fuse_operations {
+    int (*getattr) (const char *path, struct stat *stbuf);
+    int (*readlink) (const char *path, char *buf, size_t size);
+    int (*mknod) (const char *path, int mode, int rdev);
+    int (*getdir) (const char *path, struct fuse_dh *h, dirfiller_t filler);
+};
+
+struct fuse *fuse_new();
+
+int fuse_mount(struct fuse *f, const char *dir);
+
+void fuse_set_operations(struct fuse *f, const struct fuse_operations *op);
+
+void fuse_loop(struct fuse *f);
+
+int fuse_unmount(struct fuse *f);
+
+void fuse_destroy(struct fuse *f);
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
new file mode 100644 (file)
index 0000000..fb3aca0
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+/* This file defines the kernel interface of FUSE */
+
+
+#define FUSE_MOUNT_VERSION 1
+
+struct fuse_mount_data {
+       int version;
+       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 long  size;
+       unsigned long       blksize;
+       unsigned long       blocks;
+       unsigned long       atime;
+       unsigned long       mtime;
+       unsigned long       ctime;
+};
+
+enum fuse_opcode {
+       FUSE_LOOKUP     = 1,
+       FUSE_FORGET,
+       FUSE_GETATTR,
+       FUSE_READLINK,
+       FUSE_GETDIR,
+       FUSE_MKNOD,
+};
+
+/* Conservative buffer size for the client */
+#define FUSE_MAX_IN 8192
+
+struct fuse_lookup_out {
+       unsigned long ino;
+       struct fuse_attr attr;
+};
+
+struct fuse_getattr_out {
+       struct fuse_attr attr;
+};
+
+struct fuse_getdir_out {
+       int fd;
+       void *file; /* Used by kernel only */
+};
+
+struct fuse_mknod_in {
+       unsigned short mode;
+       unsigned short rdev;
+       char name[1];
+};
+
+struct fuse_mknod_out {
+       unsigned long ino;
+       struct fuse_attr attr;
+};
+
+struct fuse_in_header {
+       int unique;
+       enum fuse_opcode opcode;
+       unsigned long ino;      
+};
+
+struct fuse_out_header {
+       int unique;
+       int result;
+};
+
+struct fuse_dirent {
+       unsigned long ino;
+       unsigned short namelen;
+       unsigned char type;
+       char name[256];
+};
+
+#define FUSE_NAME_OFFSET ((unsigned int) ((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:
+ * indent-tabs-mode: t
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/inode.c b/inode.c
deleted file mode 100644 (file)
index 5c2b743..0000000
--- a/inode.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
-    FUSE: Filesystem in Userspace
-    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
-
-    This program can be distributed under the terms of the GNU GPL.
-    See the file COPYING.
-*/
-
-#include "fuse_i.h"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/file.h>
-
-#define FUSE_SUPER_MAGIC 0x65735546
-
-static void fuse_read_inode(struct inode *inode)
-{
-       /* No op */
-}
-
-static void fuse_put_super(struct super_block *sb)
-{
-       struct fuse_conn *fc = sb->u.generic_sbp;
-
-       spin_lock(&fuse_lock);
-       fc->sb = NULL;
-       fuse_release_conn(fc);
-       spin_unlock(&fuse_lock);
-
-}
-
-static struct super_operations fuse_super_operations = {
-       read_inode:     fuse_read_inode,
-       put_super:      fuse_put_super,
-};
-
-
-static struct fuse_conn *get_conn(struct fuse_mount_data *d)
-{
-       struct fuse_conn *fc = NULL;
-       struct file *file;
-       struct inode *ino;
-
-       if(d == NULL) {
-               printk("fuse_read_super: Bad mount data\n");
-               return NULL;
-       }
-
-       if(d->version != FUSE_MOUNT_VERSION) {
-               printk("fuse_read_super: Bad mount version: %i\n", d->version);
-               return NULL;
-       }
-
-       file = fget(d->fd);
-       ino = NULL;
-       if(file)
-               ino = file->f_dentry->d_inode;
-       
-       if(!ino || ino->u.generic_ip != proc_fuse_dev) {
-               printk("fuse_read_super: Bad file: %i\n", d->fd);
-               goto out;
-       }
-
-       fc = file->private_data;
-
-  out:
-       fput(file);
-       return fc;
-
-}
-
-static struct inode *get_root_inode(struct super_block *sb)
-{
-       struct inode *root      ;
-
-       root = iget(sb, 1);
-       if(root) {
-               root->i_mode = S_IFDIR;
-               root->i_uid = 0;
-               root->i_gid = 0;
-               root->i_nlink = 2;
-               root->i_size = 0;
-               root->i_blksize = 1024;
-               root->i_blocks = 0;
-               root->i_atime = CURRENT_TIME;
-               root->i_mtime = CURRENT_TIME;
-               root->i_ctime = CURRENT_TIME;
-               fuse_dir_init(root);
-       }
-
-       return root;
-}
-
-static struct super_block *fuse_read_super(struct super_block *sb, 
-                                          void *data, int silent)
-{      
-       struct fuse_conn *fc;
-       struct inode *root;
-
-        sb->s_blocksize = 1024;
-        sb->s_blocksize_bits = 10;
-        sb->s_magic = FUSE_SUPER_MAGIC;
-        sb->s_op = &fuse_super_operations;
-
-       root = get_root_inode(sb);
-       if(root == NULL) {
-               printk("fuse_read_super: failed to get root inode\n");
-               return NULL;
-       }
-
-       spin_lock(&fuse_lock);
-       fc = get_conn(data);
-       if(fc == NULL)
-               goto err;
-
-       if(fc->sb != NULL) {
-               printk("fuse_read_super: connection %i already mounted\n",
-                      fc->id);
-               goto err;
-       }
-
-        sb->u.generic_sbp = fc;
-       sb->s_root = d_alloc_root(root);
-       fc->sb = sb;
-       spin_unlock(&fuse_lock);
-       
-       return sb;
-
-  err:
-       spin_unlock(&fuse_lock);
-       iput(root);
-       return NULL;
-}
-
-
-static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super, 0);
-
-int fuse_fs_init()
-{
-       int res;
-
-       res = register_filesystem(&fuse_fs_type);
-       if(res)
-               printk("fuse: failed to register filesystem\n");
-
-       return res;
-}
-
-void fuse_fs_cleanup()
-{
-       unregister_filesystem(&fuse_fs_type);
-}
-
-/* 
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- * End:
- */
-
diff --git a/kernel/Makefile b/kernel/Makefile
new file mode 100644 (file)
index 0000000..f7769d5
--- /dev/null
@@ -0,0 +1,16 @@
+CC = gcc
+CFLAGS = -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -pipe
+CPPFLAGS = -I /lib/modules/`uname -r`/build/include/ -D__KERNEL__ -DMODULE -D_LOOSE_KERNEL_NAMES -I../include
+
+
+all: fuse.o
+
+fuse_objs = dev.o inode.o dir.o util.o
+
+fuse.o: $(fuse_objs)
+       ld -r -o fuse.o $(fuse_objs)
+
+
+clean:
+       rm -f *.o
+       rm -f *~
diff --git a/kernel/dev.c b/kernel/dev.c
new file mode 100644 (file)
index 0000000..a91a176
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include "fuse_i.h"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/file.h>
+
+#define IHSIZE sizeof(struct fuse_in_header)
+#define OHSIZE sizeof(struct fuse_out_header)
+
+static struct proc_dir_entry *proc_fs_fuse;
+struct proc_dir_entry *proc_fuse_dev;
+
+static int request_wait_answer(struct fuse_req *req)
+{
+       int ret = 0;
+       DECLARE_WAITQUEUE(wait, current);
+
+       add_wait_queue(&req->waitq, &wait);
+       while(!list_empty(&req->list)) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if(signal_pending(current)) {
+                       ret = -EINTR;
+                       break;
+               }
+               spin_unlock(&fuse_lock);
+               schedule();
+               spin_lock(&fuse_lock);
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&req->waitq, &wait);
+
+       return ret;
+}
+
+static int request_check(struct fuse_req *req, struct fuse_out *outp)
+{
+       struct fuse_out_header *oh;
+       unsigned int size;
+
+       if(!req->out)
+               return -ECONNABORTED;
+
+       oh = (struct fuse_out_header *) req->out;
+       size = req->outsize - OHSIZE;
+       
+       if (oh->result <= -512 || oh->result > 0) {
+               printk("fuse: bad result\n");
+               return -EPROTO;
+       }
+
+       if(size > outp->argsize || 
+          (oh->result == 0 && !outp->argvar && size != outp->argsize) ||
+          (oh->result != 0 && size != 0)) {
+               printk("fuse: invalid argument length: %i (%i)\n", size,
+                      req->opcode);
+               return -EPROTO;
+       }
+       
+       memcpy(&outp->h, oh, OHSIZE);
+       outp->argsize = size;
+       if(size)
+               memcpy(outp->arg, req->out + OHSIZE, size);
+       
+       return oh->result;
+}
+
+static void request_free(struct fuse_req *req)
+{
+       kfree(req->in);
+       kfree(req->out);
+       kfree(req);
+}
+
+
+static struct fuse_req *request_new(struct fuse_conn *fc, struct fuse_in *inp,
+                                   struct fuse_out *outp)
+{
+       struct fuse_req *req;
+       
+       req = kmalloc(sizeof(*req), GFP_KERNEL);
+       if(!req)
+               return NULL;
+
+       if(outp)
+               req->outsize = OHSIZE + outp->argsize;
+       else
+               req->outsize = 0;
+       req->out = NULL;
+
+       req->insize = IHSIZE + inp->argsize;
+       req->in = kmalloc(req->insize, GFP_KERNEL);
+       if(!req->in) {
+               request_free(req);
+               return NULL;
+       }
+       memcpy(req->in, &inp->h, IHSIZE);
+       if(inp->argsize)
+               memcpy(req->in + IHSIZE, inp->arg, inp->argsize);
+
+       req->opcode = inp->h.opcode;
+       init_waitqueue_head(&req->waitq);
+
+       return req;
+}
+
+/* If 'outp' is NULL then the request this is asynchronous */
+void request_send(struct fuse_conn *fc, struct fuse_in *inp,
+                 struct fuse_out *outp)
+{
+       int ret;
+       struct fuse_in_header *ih;
+       struct fuse_req *req;
+
+       ret = -ENOMEM;
+       req = request_new(fc, inp, outp);
+       if(!req)
+               goto out;
+
+       spin_lock(&fuse_lock);
+       ret = -ENOTCONN;
+       if(fc->file == NULL)
+               goto out_unlock_free;
+       
+       ih = (struct fuse_in_header *) req->in;
+       if(outp) {
+               do fc->reqctr++;
+               while(!fc->reqctr);
+               ih->unique = req->unique = fc->reqctr;
+       }
+       else
+               ih->unique = req->unique = 0;
+
+       list_add_tail(&req->list, &fc->pending);
+       wake_up(&fc->waitq);
+
+       /* Async reqests are freed in fuse_dev_read() */
+       if(!outp) 
+               goto out_unlock; 
+       
+       ret = request_wait_answer(req);
+       list_del(&req->list);
+       if(!ret)
+               ret = request_check(req, outp);
+
+  out_unlock_free:
+       request_free(req);
+  out_unlock:
+       spin_unlock(&fuse_lock);
+  out:
+       if(outp)
+               outp->h.result = ret;
+}
+
+static int request_wait(struct fuse_conn *fc)
+{
+       int ret = 0;
+       DECLARE_WAITQUEUE(wait, current);
+
+       add_wait_queue(&fc->waitq, &wait);
+       while(list_empty(&fc->pending)) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if(signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               spin_unlock(&fuse_lock);
+               schedule();
+               spin_lock(&fuse_lock);
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&fc->waitq, &wait);
+
+       return ret;
+}
+
+
+static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes,
+                            loff_t *off)
+{
+       int ret;
+       struct fuse_conn *fc = file->private_data;
+       struct fuse_req *req;
+       char *tmpbuf;
+       unsigned int size;
+
+       if(fc->sb == NULL)
+               return -EPERM;
+       
+       spin_lock(&fuse_lock);
+       ret = request_wait(fc);
+       if(ret)
+               goto err;
+       
+       req = list_entry(fc->pending.next, struct fuse_req, list);
+       size = req->insize;
+       if(nbytes < size) {
+               printk("fuse_dev_read[%i]: buffer too small\n", fc->id);
+               ret = -EIO;
+               goto err;
+       }
+       tmpbuf = req->in;
+       req->in = NULL;
+
+       list_del(&req->list);
+       if(req->outsize)
+               list_add_tail(&req->list, &fc->processing);
+       else
+               request_free(req);
+       spin_unlock(&fuse_lock);
+
+       if(copy_to_user(buf, tmpbuf, size))
+               return -EFAULT;
+       
+       return size;
+
+  err:
+       spin_unlock(&fuse_lock);
+       return ret;
+}
+
+static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique)
+{
+       struct list_head *entry;
+       struct fuse_req *req = NULL;
+
+       list_for_each(entry, &fc->processing) {
+               struct fuse_req *tmp;
+               tmp = list_entry(entry, struct fuse_req, list);
+               if(tmp->unique == unique) {
+                       req = tmp;
+                       break;
+               }
+       }
+
+       return req;
+}
+
+static ssize_t fuse_dev_write(struct file *file, const char *buf,
+                             size_t nbytes, loff_t *off)
+{
+       ssize_t ret;
+       struct fuse_conn *fc = file->private_data;
+       struct fuse_req *req;
+       char *tmpbuf;
+       struct fuse_out_header *oh;
+
+       if(!fc->sb)
+               return -EPERM;
+
+       ret = -EIO;
+       if(nbytes < OHSIZE || nbytes > OHSIZE + PAGE_SIZE) {
+               printk("fuse_dev_write[%i]: write is short or long\n", fc->id);
+               goto out;
+       }
+       
+       ret = -ENOMEM;
+       tmpbuf = kmalloc(nbytes, GFP_KERNEL);
+       if(!tmpbuf)
+               goto out;
+       
+       ret = -EFAULT;
+       if(copy_from_user(tmpbuf, buf, nbytes))
+               goto out_free;
+       
+       spin_lock(&fuse_lock);
+       oh =  (struct fuse_out_header *) tmpbuf;
+       req = request_find(fc, oh->unique);
+       if(req == NULL) {
+               ret = -ENOENT;
+               goto out_free_unlock;
+       }
+       list_del_init(&req->list);
+       if(req->opcode == FUSE_GETDIR) {
+               /* fget() needs to be done in this context */
+               struct fuse_getdir_out *arg;
+               arg = (struct fuse_getdir_out *) (tmpbuf + OHSIZE);
+               arg->file = fget(arg->fd);
+       }
+       req->out = tmpbuf;
+       req->outsize = nbytes;
+       tmpbuf = NULL;
+       ret = nbytes;
+       wake_up(&req->waitq);
+  out_free_unlock:
+       spin_unlock(&fuse_lock);
+  out_free:
+       kfree(tmpbuf);
+  out:
+       return ret;
+}
+
+
+static unsigned int fuse_dev_poll(struct file *file, poll_table *wait)
+{
+       struct fuse_conn *fc = file->private_data;
+       unsigned int mask = POLLOUT | POLLWRNORM;
+
+       if(!fc->sb)
+               return -EPERM;
+
+       poll_wait(file, &fc->waitq, wait);
+
+       spin_lock(&fuse_lock);
+       if (!list_empty(&fc->pending))
+                mask |= POLLIN | POLLRDNORM;
+       spin_unlock(&fuse_lock);
+
+       return mask;
+}
+
+static struct fuse_conn *new_conn(void)
+{
+       static int connctr = 1;
+       struct fuse_conn *fc;
+
+       fc = kmalloc(sizeof(*fc), GFP_KERNEL);
+       if(fc != NULL) {
+               fc->sb = NULL;
+               fc->file = NULL;
+               init_waitqueue_head(&fc->waitq);
+               INIT_LIST_HEAD(&fc->pending);
+               INIT_LIST_HEAD(&fc->processing);
+               fc->reqctr = 1;
+               fc->cleared = NULL;
+               fc->numcleared = 0;
+               
+               spin_lock(&fuse_lock);
+               fc->id = connctr ++;
+               spin_unlock(&fuse_lock);
+       }
+       return fc;
+}
+
+static int fuse_dev_open(struct inode *inode, struct file *file)
+{
+       struct fuse_conn *fc;
+
+       fc = new_conn();
+       if(!fc)
+               return -ENOMEM;
+
+       fc->file = file;
+       file->private_data = fc;
+
+       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);
+               if(req->outsize)
+                       wake_up(&req->waitq);
+               else
+                       request_free(req);
+       }
+}
+
+static int fuse_dev_release(struct inode *inode, struct file *file)
+{
+       struct fuse_conn *fc = file->private_data;
+
+       spin_lock(&fuse_lock);
+       fc->file = NULL;
+       end_requests(&fc->pending);
+       end_requests(&fc->processing);
+       kfree(fc->cleared);
+       fc->cleared = NULL;
+       fc->numcleared = 0;
+       fuse_release_conn(fc);
+       spin_unlock(&fuse_lock);
+       return 0;
+}
+
+static struct file_operations fuse_dev_operations = {
+       owner:          THIS_MODULE,
+       read:           fuse_dev_read,
+       write:          fuse_dev_write,
+       poll:           fuse_dev_poll,
+       open:           fuse_dev_open,
+       release:        fuse_dev_release,
+};
+
+int fuse_dev_init()
+{
+       int ret;
+
+       proc_fs_fuse = NULL;
+       proc_fuse_dev = NULL;
+
+       ret = -EIO;
+       proc_fs_fuse = proc_mkdir("fuse", proc_root_fs);
+       if(!proc_fs_fuse) {
+               printk("fuse: failed to create directory in /proc/fs\n");
+               goto err;
+       }
+
+       proc_fs_fuse->owner = THIS_MODULE;
+       proc_fuse_dev = create_proc_entry("dev", S_IFSOCK | S_IRUGO | S_IWUGO,
+                                         proc_fs_fuse);
+       if(!proc_fuse_dev) {
+               printk("fuse: failed to create entry in /proc/fs/fuse\n");
+               goto err;
+       }
+
+       proc_fuse_dev->proc_fops = &fuse_dev_operations;
+
+       return 0;
+
+  err:
+       fuse_dev_cleanup();
+       return ret;
+}
+
+void fuse_dev_cleanup()
+{
+       if(proc_fs_fuse) {
+               remove_proc_entry("dev", proc_fs_fuse);
+               remove_proc_entry("fuse", proc_root_fs);
+       }
+}
+
+/* 
+ * Local Variables:
+ * indent-tabs-mode: t
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/kernel/dir.c b/kernel/dir.c
new file mode 100644 (file)
index 0000000..92ddc55
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    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 {
+               fuse_special_init(inode);
+               init_special_inode(inode, inode->i_mode, attr->rdev);
+       }
+}
+
+
+static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
+{
+       struct fuse_conn *fc = dir->i_sb->u.generic_sbp;
+       struct fuse_in in = FUSE_IN_INIT;
+       struct fuse_out out = FUSE_OUT_INIT;
+       struct fuse_lookup_out arg;
+       struct inode *inode;
+       
+       in.h.opcode = FUSE_LOOKUP;
+       in.h.ino = dir->i_ino;
+       in.argsize = entry->d_name.len + 1;
+       in.arg = entry->d_name.name;
+       out.argsize = sizeof(arg);
+       out.arg = &arg;
+       request_send(fc, &in, &out);
+       
+       if(out.h.result) {
+               /* Negative dentries are not hashed */
+               if(out.h.result == -ENOENT)
+                       return NULL;
+               else
+                       return ERR_PTR(out.h.result);
+       }
+
+       inode = iget(dir->i_sb, arg.ino);
+       if(!inode) 
+               return ERR_PTR(-ENOMEM);
+
+       init_inode(inode, &arg.attr);
+       d_add(entry, inode);
+       return NULL;
+}
+
+static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
+                     int rdev)
+{
+       struct fuse_conn *fc = dir->i_sb->u.generic_sbp;
+       struct fuse_in in = FUSE_IN_INIT;
+       struct fuse_out out = FUSE_OUT_INIT;
+       struct fuse_mknod_in *inarg;
+       unsigned int insize;
+       struct fuse_mknod_out outarg;
+       struct inode *inode;
+       
+       insize = offsetof(struct fuse_mknod_in, name) + entry->d_name.len + 1;
+       inarg = kmalloc(insize, GFP_KERNEL);
+       if(!inarg)
+               return -ENOMEM;
+       
+       inarg->mode = mode;
+       inarg->rdev = rdev;
+       strcpy(inarg->name, entry->d_name.name);
+
+       in.h.opcode = FUSE_MKNOD;
+       in.h.ino = dir->i_ino;
+       in.argsize = insize;
+       in.arg = inarg;
+       out.argsize = sizeof(outarg);
+       out.arg = &outarg;
+       request_send(fc, &in, &out);
+       kfree(inarg);
+       if(out.h.result)
+               return out.h.result;
+
+       inode = iget(dir->i_sb, outarg.ino);
+       if(!inode) 
+               return -ENOMEM;
+
+       init_inode(inode, &outarg.attr);
+       d_add(entry, inode);
+       return 0;
+}
+
+static int fuse_create(struct inode *dir, struct dentry *entry, int mode)
+{
+       return fuse_mknod(dir, entry, mode, 0);
+}
+
+static int fuse_permission(struct inode *inode, int mask)
+{
+
+       return 0;
+}
+
+static int fuse_revalidate(struct dentry *dentry)
+{
+       struct inode *inode = dentry->d_inode;
+       struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+       struct fuse_in in = FUSE_IN_INIT;
+       struct fuse_out out = FUSE_OUT_INIT;
+       struct fuse_getattr_out arg;
+       
+       in.h.opcode = FUSE_GETATTR;
+       in.h.ino = inode->i_ino;
+       out.argsize = sizeof(arg);
+       out.arg = &arg;
+       request_send(fc, &in, &out);
+       
+       if(out.h.result == 0)
+               change_attributes(inode, &arg.attr);
+
+       return out.h.result;
+}
+
+
+#define DIR_BUFSIZE 2048
+
+static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
+{
+       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 over;
+               if(dirent->namelen > NAME_MAX) {
+                       printk("fuse_readdir: name too long\n");
+                       ret = -EPROTO;
+                       goto out;
+               }
+               if(reclen > nbytes)
+                       break;
+
+               over = filldir(dstbuf, dirent->name, dirent->namelen,
+                             file->f_pos, dirent->ino, dirent->type);
+               if(over)
+                       break;
+
+               p += reclen;
+               file->f_pos += reclen;
+               nbytes -= reclen;
+       }
+
+  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 = FUSE_IN_INIT;
+       struct fuse_out out = FUSE_OUT_INIT;
+       unsigned long page;
+
+       page = __get_free_page(GFP_KERNEL);
+       if(!page)
+               return -ENOMEM;
+
+       in.h.opcode = FUSE_READLINK;
+       in.h.ino = inode->i_ino;
+       out.arg = (void *) page;
+       out.argsize = PAGE_SIZE - 1;
+       out.argvar = 1;
+       request_send(fc, &in, &out);
+       if(out.h.result) {
+               free_page(page);
+               return out.h.result;
+       }
+
+       *bufp = (char *) page;
+       (*bufp)[out.argsize] = '\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_dir_open(struct inode *inode, struct file *file)
+{
+       struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+       struct fuse_in in = FUSE_IN_INIT;
+       struct fuse_out out = FUSE_OUT_INIT;
+       struct fuse_getdir_out outarg;
+
+       if(!(file->f_flags & O_DIRECTORY))
+               return -EISDIR;
+       
+       in.h.opcode = FUSE_GETDIR;
+       in.h.ino = inode->i_ino;
+       out.argsize = sizeof(outarg);
+       out.arg = &outarg;
+       request_send(fc, &in, &out);
+       if(out.h.result == 0) {
+               struct file *cfile = outarg.file;
+               struct inode *inode;
+               if(!cfile) {
+                       printk("fuse_getdir: invalid file\n");
+                       return -EPROTO;
+               }
+               inode = cfile->f_dentry->d_inode;
+               if(!S_ISREG(inode->i_mode)) {
+                       printk("fuse_getdir: not a regular file\n");
+                       fput(cfile);
+                       return -EPROTO;
+               }
+
+               file->private_data = cfile;
+       }
+
+       return out.h.result;
+}
+
+static int fuse_dir_release(struct inode *inode, struct file *file)
+{
+       struct file *cfile = file->private_data;
+
+       if(!cfile)
+               BUG();
+       
+       fput(cfile);
+
+       return 0;
+}
+
+static struct inode_operations fuse_dir_inode_operations =
+{
+       lookup:         fuse_lookup,
+       create:         fuse_create,
+       mknod:          fuse_mknod,
+#if 0
+
+       link:           fuse_link,
+       unlink:         fuse_unlink,
+       symlink:        fuse_symlink,
+       mkdir:          fuse_mkdir,
+       rmdir:          fuse_rmdir,
+       rename:         fuse_rename,
+#endif
+       permission:     fuse_permission,
+        revalidate:    fuse_revalidate,
+};
+
+static struct file_operations fuse_dir_operations = {
+       read:           generic_read_dir,
+       readdir:        fuse_readdir,
+       open:           fuse_dir_open,
+       release:        fuse_dir_release,
+};
+
+static struct inode_operations fuse_file_inode_operations = {
+       permission:     fuse_permission,
+        revalidate:    fuse_revalidate,
+};
+
+static struct inode_operations fuse_special_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;
+}
+
+void fuse_special_init(struct inode *inode)
+{
+       inode->i_op = &fuse_special_inode_operations;
+}
+
+/* 
+ * Local Variables:
+ * indent-tabs-mode: t
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
new file mode 100644 (file)
index 0000000..1eb0bb4
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include <linux/fuse.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#define FUSE_VERSION "0.1"
+
+#define MAX_CLEARED 256
+
+/**
+ * A Fuse connection.
+ *
+ * This structure is created, when the client device is opened, and is
+ * destroyed, when the client device is closed _and_ the filesystem is
+ * umounted.
+ */
+struct fuse_conn {
+       /** The superblock of the mounted filesystem */
+       struct super_block *sb;
+       
+       /** The opened client device */
+       struct file *file;
+
+       /** The client wait queue */
+       wait_queue_head_t waitq;
+
+       /** The list of pending requests */
+       struct list_head pending;
+
+       /** The list of requests being processed */
+       struct list_head processing;
+
+       /** The number of cleared inodes */
+       unsigned int numcleared;
+       
+       /** The array of cleared inode numbers */
+       unsigned long *cleared;
+
+       /** Connnection number (for debuging) */
+       int id;
+
+       /** The request id */
+       int reqctr;
+};
+
+/**
+ * A request to the client
+ */
+struct fuse_req {
+       /** The request list */
+       struct list_head list;
+
+       /** The request ID */
+       int unique;
+
+       /** The opcode */
+       enum fuse_opcode opcode;
+       
+       /** The request input size */
+       unsigned int insize;
+
+       /** The request input */
+       char *in;
+       
+       /** The maximum request output size, if zero, then the request is
+            asynchronous */
+       unsigned int outsize;
+
+       /** The request output */
+       char *out;
+
+       /** The request wait queue */
+       wait_queue_head_t waitq;
+};
+
+
+struct fuse_in {
+       struct fuse_in_header h;
+       unsigned int argsize;
+       const void *arg;
+};
+
+struct fuse_out {
+       struct fuse_out_header h;
+       unsigned int argsize;
+       unsigned int argvar;
+       void *arg;
+};
+
+#define FUSE_IN_INIT { {0, 0, 0}, 0, 0 }
+#define FUSE_OUT_INIT { {0, 0}, 0, 0, 0 }
+
+
+/**
+ * The proc entry for the client device ("/proc/fs/fuse/dev")
+ */
+extern struct proc_dir_entry *proc_fuse_dev;
+
+/**
+ * The lock to protect fuses structures
+ */
+extern spinlock_t fuse_lock;
+
+/**
+ * Fill in the directory operations
+ */
+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);
+
+/**
+ * Fill in the special inode operaions
+ */
+void fuse_special_init(struct inode *inode);
+
+/**
+ * Check if the connection can be released, and if yes, then free the
+ * connection structure
+ */
+void fuse_release_conn(struct fuse_conn *fc);
+
+/**
+ * Initialize the client device
+ */
+int fuse_dev_init(void);
+
+/**
+ * Cleanup the client device
+ */
+void fuse_dev_cleanup(void);
+
+/**
+ * Initialize the fuse filesystem 
+ */
+int fuse_fs_init(void);
+
+/**
+ * Cleanup the fuse filesystem
+ */
+void fuse_fs_cleanup(void);
+
+/**
+ * Send a request
+ *
+ */
+void request_send(struct fuse_conn *fc, struct fuse_in *in,
+                 struct fuse_out *out);
+
+/*
+ * Local Variables:
+ * indent-tabs-mode: t
+ * c-basic-offset: 8
+ */
diff --git a/kernel/inode.c b/kernel/inode.c
new file mode 100644 (file)
index 0000000..ac2d6be
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include "fuse_i.h"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/file.h>
+
+#define FUSE_SUPER_MAGIC 0x65735546
+
+static void fuse_read_inode(struct inode *inode)
+{
+       /* No op */
+}
+
+static void send_forget(struct fuse_conn *fc, unsigned long *forget,
+                       unsigned int numforget)
+{
+       struct fuse_in in = FUSE_IN_INIT;
+       
+       in.h.opcode = FUSE_FORGET;
+       in.h.ino = 0;
+       in.argsize = numforget * sizeof(unsigned long);
+       in.arg = forget;
+       
+       request_send(fc, &in, NULL);
+}
+
+static int alloc_cleared(struct fuse_conn *fc)
+{
+       unsigned long *tmp;
+       
+       spin_unlock(&fuse_lock);
+       tmp = kmalloc(sizeof(unsigned long) * MAX_CLEARED, GFP_KERNEL);
+       spin_lock(&fuse_lock);
+
+       if(!fc->file || fc->cleared != NULL)
+               kfree(tmp);
+       else if(!tmp)
+               printk("fuse_clear_inode: Cannot allocate memory\n");
+       else
+               fc->cleared = tmp;
+
+       return fc->cleared != NULL;
+}
+
+static unsigned long *add_cleared(struct fuse_conn *fc, unsigned long ino)
+{
+       if(!fc->file || (!fc->cleared && !alloc_cleared(fc)))
+               return NULL;
+
+       fc->cleared[fc->numcleared] = ino;
+       fc->numcleared ++;
+       
+       if(fc->numcleared == MAX_CLEARED) {
+               unsigned long *tmp = fc->cleared;
+               fc->cleared = NULL;
+               fc->numcleared = 0;
+               return tmp;
+       }
+       
+       return NULL;
+}
+
+static void fuse_clear_inode(struct inode *inode)
+{
+       struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+       unsigned long *forget;
+
+       spin_lock(&fuse_lock);
+       forget = add_cleared(fc, inode->i_ino);
+       spin_unlock(&fuse_lock);
+
+       if(forget) {
+               send_forget(fc, forget, MAX_CLEARED);
+               kfree(forget);
+       }
+}
+
+static void fuse_put_super(struct super_block *sb)
+{
+       struct fuse_conn *fc = sb->u.generic_sbp;
+
+       spin_lock(&fuse_lock);
+       fc->sb = NULL;
+       fuse_release_conn(fc);
+       spin_unlock(&fuse_lock);
+
+}
+
+static struct super_operations fuse_super_operations = {
+       read_inode:     fuse_read_inode,
+       clear_inode:    fuse_clear_inode,
+       put_super:      fuse_put_super,
+};
+
+
+static struct fuse_conn *get_conn(struct fuse_mount_data *d)
+{
+       struct fuse_conn *fc = NULL;
+       struct file *file;
+       struct inode *ino;
+
+       if(d == NULL) {
+               printk("fuse_read_super: Bad mount data\n");
+               return NULL;
+       }
+
+       if(d->version != FUSE_MOUNT_VERSION) {
+               printk("fuse_read_super: Bad mount version: %i\n", d->version);
+               return NULL;
+       }
+
+       file = fget(d->fd);
+       ino = NULL;
+       if(file)
+               ino = file->f_dentry->d_inode;
+       
+       if(!ino || ino->u.generic_ip != proc_fuse_dev) {
+               printk("fuse_read_super: Bad file: %i\n", d->fd);
+               goto out;
+       }
+
+       fc = file->private_data;
+
+  out:
+       fput(file);
+       return fc;
+
+}
+
+static struct inode *get_root_inode(struct super_block *sb)
+{
+       struct inode *root      ;
+
+       root = iget(sb, 1);
+       if(root) {
+               root->i_mode = S_IFDIR;
+               root->i_uid = 0;
+               root->i_gid = 0;
+               root->i_nlink = 2;
+               root->i_size = 0;
+               root->i_blksize = 1024;
+               root->i_blocks = 0;
+               root->i_atime = CURRENT_TIME;
+               root->i_mtime = CURRENT_TIME;
+               root->i_ctime = CURRENT_TIME;
+               fuse_dir_init(root);
+       }
+
+       return root;
+}
+
+static struct super_block *fuse_read_super(struct super_block *sb, 
+                                          void *data, int silent)
+{      
+       struct fuse_conn *fc;
+       struct inode *root;
+
+        sb->s_blocksize = 1024;
+        sb->s_blocksize_bits = 10;
+        sb->s_magic = FUSE_SUPER_MAGIC;
+        sb->s_op = &fuse_super_operations;
+
+       root = get_root_inode(sb);
+       if(root == NULL) {
+               printk("fuse_read_super: failed to get root inode\n");
+               return NULL;
+       }
+
+       spin_lock(&fuse_lock);
+       fc = get_conn(data);
+       if(fc == NULL)
+               goto err;
+
+       if(fc->sb != NULL) {
+               printk("fuse_read_super: connection %i already mounted\n",
+                      fc->id);
+               goto err;
+       }
+
+        sb->u.generic_sbp = fc;
+       sb->s_root = d_alloc_root(root);
+       fc->sb = sb;
+       spin_unlock(&fuse_lock);
+       
+       return sb;
+
+  err:
+       spin_unlock(&fuse_lock);
+       iput(root);
+       return NULL;
+}
+
+
+static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super, 0);
+
+int fuse_fs_init()
+{
+       int res;
+
+       res = register_filesystem(&fuse_fs_type);
+       if(res)
+               printk("fuse: failed to register filesystem\n");
+
+       return res;
+}
+
+void fuse_fs_cleanup()
+{
+       unregister_filesystem(&fuse_fs_type);
+}
+
+/* 
+ * Local Variables:
+ * indent-tabs-mode: t
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/kernel/util.c b/kernel/util.c
new file mode 100644 (file)
index 0000000..57b1a90
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include "fuse_i.h"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#define FUSE_VERSION "0.1"
+
+spinlock_t fuse_lock = SPIN_LOCK_UNLOCKED;
+
+/* Must be called with the fuse lock held */
+void fuse_release_conn(struct fuse_conn *fc)
+{
+       if(fc->sb == NULL && fc->file == NULL) {
+               kfree(fc);
+       }
+}
+
+int init_module(void)
+{
+       int res;
+
+       printk(KERN_DEBUG "fuse init (version %s)\n", FUSE_VERSION);
+
+       res = fuse_fs_init();
+       if(res)
+               goto err;
+       
+       res = fuse_dev_init();
+       if(res)
+               goto err_fs_cleanup;
+       
+       return 0;
+
+  err_fs_cleanup:
+       fuse_fs_cleanup();
+  err:
+       return res;
+}
+
+void cleanup_module(void)
+{
+       printk(KERN_DEBUG "fuse cleanup\n");
+       
+       fuse_fs_cleanup();
+       fuse_dev_cleanup();
+}
+
+/*
+ * Local Variables:
+ * indent-tabs-mode: t
+ * c-basic-offset: 8
+ */
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644 (file)
index 0000000..e72a39d
--- /dev/null
@@ -0,0 +1,16 @@
+CC = gcc
+CFLAGS = -Wall -W -g `glib-config --cflags`
+LDFLAGS = `glib-config --libs`
+CPPFLAGS = -I../include
+
+
+all: libfuse.a
+
+libfuse_objs = mount.o fuse.o
+
+libfuse.a: $(libfuse_objs)
+       ar cr libfuse.a $(libfuse_objs)
+
+clean:
+       rm -f *.o *.a
+       rm -f *~
diff --git a/lib/fuse.c b/lib/fuse.c
new file mode 100644 (file)
index 0000000..f846f74
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include "fuse_i.h"
+#include <linux/fuse.h>
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+static guint name_hash(const struct node *node)
+{
+    return g_str_hash(node->name) ^ node->parent;
+}
+
+static gint name_compare(const struct node *node1, const struct node *node2)
+{
+    return
+        node1->parent == node2->parent &&
+        strcmp(node1->name, node2->name) == 0;
+}
+
+static struct node *new_node(fino_t parent, const char *name)
+{
+    struct node *node = g_new0(struct node, 1);
+    node->name = strdup(name);
+    node->parent = parent;
+    return node;
+}
+
+static int free_node(struct node *node)
+{
+    g_free(node->name);
+    g_free(node);
+    return 1;
+}
+
+static inline struct node *get_node(fino_t ino)
+{
+    return (struct node *) ino;
+}
+
+static inline fino_t get_ino(struct node *node)
+{
+    return (fino_t) node;
+}
+
+
+static fino_t find_node(struct fuse *f, fino_t parent, char *name, int create)
+{
+    struct node *node;
+    struct node tmp;
+    
+    tmp.name = name;
+    tmp.parent = parent;
+
+    node = g_hash_table_lookup(f->nametab, &tmp);
+    if(node != NULL)
+        return get_ino(node);
+
+    if(!create)
+        return (fino_t) -1;
+
+    node = new_node(parent, name);
+    g_hash_table_insert(f->nametab, node, node);
+    return get_ino(node);
+}
+
+static char *get_path(fino_t ino)
+{
+    GString *s;
+    char *ss;
+
+    s = g_string_new("");
+    if(ino == FUSE_ROOT_INO)
+        g_string_prepend_c(s, '/');
+    else {
+        struct node *node;
+        for(; ino != FUSE_ROOT_INO; ino = node->parent) {
+            node = get_node(ino);
+            g_string_prepend(s, node->name);
+            g_string_prepend_c(s, '/');
+        }
+    }
+
+    ss = s->str;
+    g_string_free(s, FALSE);
+    
+    return ss;
+}
+
+static void remove_node(struct fuse *f, fino_t ino)
+{
+    struct node *node = get_node(ino);
+    g_hash_table_remove(f->nametab, node);
+    free_node(node);
+}
+
+
+static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
+{
+    attr->mode    = stbuf->st_mode;
+    attr->nlink   = stbuf->st_nlink;
+    attr->uid     = stbuf->st_uid;
+    attr->gid     = stbuf->st_gid;
+    attr->rdev    = stbuf->st_rdev;
+    attr->size    = stbuf->st_size;
+    attr->blksize = stbuf->st_blksize;
+    attr->blocks  = stbuf->st_blocks;
+    attr->atime   = stbuf->st_atime;
+    attr->mtime   = stbuf->st_mtime;
+    attr->ctime   = stbuf->st_ctime;
+}
+
+static int get_attributes(struct fuse *f, fino_t ino, struct fuse_attr *attr)
+{
+    char *path;
+    struct stat buf;
+    int res;
+
+    if(f->op.getattr == NULL)
+        return -ENOSYS;
+    
+    path = get_path(ino);
+    res = f->op.getattr(path, &buf);
+    g_free(path);
+    if(res == 0) 
+        convert_stat(&buf, attr);
+    
+    return res;
+}
+
+static int read_link(struct fuse *f, fino_t ino, char *buf, size_t size)
+{
+    char *path;
+    int res;
+    
+    if(f->op.readlink == NULL)
+        return -ENOSYS;
+
+    path = get_path(ino);
+    res = f->op.readlink(path, buf, size);
+    g_free(path);
+
+    return res;
+}
+
+static int fill_dir(struct fuse_dh *dh, char *name, int type)
+{
+    struct fuse_dirent dirent;
+    size_t reclen;
+    size_t res;
+
+    dirent.ino = find_node(dh->fuse, dh->dir, name, 0);
+    dirent.namelen = strlen(name);
+    strncpy(dirent.name, name, sizeof(dirent.name));
+    dirent.type = type;
+    reclen = FUSE_DIRENT_SIZE(&dirent);
+    res = fwrite(&dirent, reclen, 1, dh->fp);
+    if(res == 0) {
+        perror("writing directory file");
+        return -EIO;
+    }
+    return 0;
+}
+
+static int get_dir(struct fuse *f, fino_t ino, FILE *fp)
+{
+    char *path;
+    int res;
+    struct fuse_dh dh;
+    
+    if(f->op.getdir == NULL)
+        return -ENOSYS;
+
+    dh.fuse = f;
+    dh.fp = fp;
+    dh.dir = ino;
+        
+    path = get_path(ino);
+    res = f->op.getdir(path, &dh, (dirfiller_t) fill_dir);
+    g_free(path);
+
+    return res;
+}
+
+
+static void send_reply(struct fuse *f, struct fuse_in_header *in, int result,
+                       void *arg, size_t argsize)
+{
+    int res;
+    char *outbuf;
+    size_t outsize;
+    struct fuse_out_header *out;
+
+    if(result > 0) {
+        fprintf(stderr, "positive result to operation %i : %i\n", in->opcode,
+                result);
+        result = -ERANGE;
+    }
+
+    if(result != 0)
+        argsize = 0;
+
+    outsize = sizeof(struct fuse_out_header) + argsize;
+    outbuf = (char *) g_malloc(outsize);
+    out = (struct fuse_out_header *) outbuf;
+    out->unique = in->unique;
+    out->result = result;
+    if(argsize != 0)
+        memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
+
+    printf("   unique: %i, result: %i (%s), outsize: %i\n", out->unique,
+           out->result, strerror(-out->result), outsize);
+                
+    res = write(f->fd, outbuf, outsize);
+    if(res == -1)
+        perror("writing fuse device");
+
+    g_free(outbuf);
+}
+
+static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
+{
+    int res;
+    struct fuse_lookup_out arg;
+
+    arg.ino = find_node(f, in->ino, name, 1);
+    res = get_attributes(f, arg.ino, &arg.attr);
+
+    send_reply(f, in, res, &arg, sizeof(arg));
+}
+
+
+static void do_forget(struct fuse *f, unsigned long *inos, size_t num)
+{
+    size_t i;
+
+    for(i = 0; i < num; i++)
+        remove_node(f, inos[i]);
+}
+
+static void do_getattr(struct fuse *f, struct fuse_in_header *in)
+{
+    int res;
+    struct fuse_getattr_out arg;
+
+    res = get_attributes(f, in->ino, &arg.attr);
+    send_reply(f, in, res, &arg, sizeof(arg));
+}
+
+static void do_readlink(struct fuse *f, struct fuse_in_header *in)
+{
+    int res;
+    char link[PATH_MAX + 1];
+
+    res = read_link(f, in->ino, link, PATH_MAX + 1);
+    send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
+}
+
+static void do_mknod(struct fuse *f, struct fuse_in_header *in,
+                     struct fuse_mknod_in *inarg)
+{
+    int res;
+    struct fuse_mknod_out outarg;
+    
+    res = -ENOSYS;
+    if(f->op.mknod != NULL && f->op.getattr != NULL) {
+        char *path;
+        struct stat buf;
+
+        outarg.ino = find_node(f, in->ino, inarg->name, 1);
+        path = get_path(outarg.ino);
+        res = f->op.mknod(path, inarg->mode, inarg->rdev);
+        if(res == 0)
+            res = f->op.getattr(path, &buf);
+        g_free(path);
+
+        if(res == 0)
+            convert_stat(&buf, &outarg.attr);
+        else
+            remove_node(f, outarg.ino);
+    }
+    send_reply(f, in, res, &outarg, sizeof(outarg));
+}
+
+static void do_getdir(struct fuse *f, struct fuse_in_header *in)
+{
+    int res;
+    struct fuse_getdir_out arg;
+    FILE *fp = tmpfile();
+
+    res = get_dir(f, in->ino, fp);
+    fflush(fp);
+    arg.fd = fileno(fp);
+    send_reply(f, in, res, &arg, sizeof(arg));
+    fclose(fp);
+}
+
+void fuse_loop(struct fuse *f)
+{
+    int res;
+    char inbuf[FUSE_MAX_IN];
+    struct fuse_in_header *in = (struct fuse_in_header *) inbuf;
+    void *inarg = inbuf + sizeof(struct fuse_in_header);
+    size_t insize;
+    size_t argsize;
+    
+    while(1) {
+        res = read(f->fd, inbuf, sizeof(inbuf));
+        if(res == -1) {
+            perror("reading fuse device");
+            continue;
+        }
+        insize = res;
+        
+        if(insize < sizeof(struct fuse_in_header)) {
+            fprintf(stderr, "short read on fuse device\n");
+            continue;
+        }
+        printf("unique: %i, opcode: %i, ino: %li, insize: %i (%i)\n",
+               in->unique, in->opcode, in->ino, insize, 
+               g_hash_table_size(f->nametab));
+
+        argsize = insize - sizeof(struct fuse_in_header);
+
+        switch(in->opcode) {
+        case FUSE_LOOKUP:
+            do_lookup(f, in, (char *) inarg);
+            break;
+
+        case FUSE_FORGET:
+            do_forget(f, (unsigned long *) inarg,
+                      argsize / sizeof(unsigned long));
+            break;
+
+        case FUSE_GETATTR:
+            do_getattr(f, in);
+            break;
+
+        case FUSE_READLINK:
+            do_readlink(f, in);
+            break;
+
+        case FUSE_GETDIR:
+            do_getdir(f, in);
+            break;
+
+        case FUSE_MKNOD:
+            do_mknod(f, in, (struct fuse_mknod_in *) inarg);
+            break;
+
+        default:
+            fprintf(stderr, "Operation %i not implemented\n", in->opcode);
+            /* No need to send reply to async requests */
+            if(in->unique != 0)
+                send_reply(f, in, -ENOSYS, NULL, 0);
+        }
+    }
+}
+
+struct fuse *fuse_new()
+{
+    struct fuse *f = g_new0(struct fuse, 1);
+
+    f->fd = -1;
+    f->dir = NULL;
+    f->nametab = g_hash_table_new((GHashFunc) name_hash,
+                                  (GCompareFunc) name_compare);
+
+    return f;
+}
+
+
+void fuse_set_operations(struct fuse *f, const struct fuse_operations *op)
+{
+    f->op = *op;
+}
+
+void fuse_destroy(struct fuse *f)
+{
+    fuse_unmount(f);
+    g_hash_table_foreach_remove(f->nametab, (GHRFunc) free_node, NULL);
+    g_hash_table_destroy(f->nametab);
+    g_free(f);
+}
+
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
new file mode 100644 (file)
index 0000000..b3b907b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include "fuse.h"
+#include <glib.h>
+#include <stdio.h>
+
+#define FUSE_DEV "/proc/fs/fuse/dev"
+
+typedef unsigned long fino_t;
+
+struct node {
+    char *name;
+    fino_t parent;
+};
+
+struct fuse {
+    char *dir;
+    int fd;
+    struct fuse_operations op;
+    GHashTable *nametab;
+};
+
+struct fuse_dh {
+    struct fuse *fuse;
+    fino_t dir;
+    FILE *fp;
+};
diff --git a/lib/mount.c b/lib/mount.c
new file mode 100644 (file)
index 0000000..ace3c65
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include "fuse_i.h"
+#include <linux/fuse.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <mntent.h>
+
+static int do_mount(const char *dev, const char *dir, const char *type, int fd)
+{
+    int res;
+    struct fuse_mount_data data;
+    
+    data.version = FUSE_MOUNT_VERSION;
+    data.fd = fd;
+
+    res = mount(dev, dir, type, MS_MGC_VAL | MS_NOSUID | MS_NODEV, &data);
+    if(res == -1) {
+        perror("mount failed");
+       return -1;
+    }
+    
+    return 0;
+}
+
+static void add_mntent(const char *dev, const char *dir, const char *type)
+{
+    int res;
+    FILE *fp;
+    struct mntent ent;
+    
+    fp = setmntent("/etc/mtab", "a");
+    if(fp == NULL) {
+        perror("setmntent");
+       return;
+    }
+    
+    ent.mnt_fsname = (char *) dev;
+    ent.mnt_dir = (char *) dir;
+    ent.mnt_type = (char *) type;
+    ent.mnt_opts = "rw,nosuid,nodev";
+    ent.mnt_freq = 0;
+    ent.mnt_passno = 0;
+    res = addmntent(fp, & ent);
+    if(res != 0)
+       perror("addmntent");
+    
+    endmntent(fp);
+
+}
+
+static void remove_mntent(const char *dir)
+{
+    int res;
+    FILE *fdold, *fdnew;
+    struct mntent *entp;
+        
+    fdold = setmntent("/etc/mtab", "r");
+    if(fdold == NULL) {
+        perror("/etc/mtab");
+       return;
+    }
+
+    fdnew = setmntent("/etc/mtab~", "w");
+    if(fdnew == NULL) {
+        perror("/etc/mtab~");
+       return;
+    }
+
+    do {
+       entp = getmntent(fdold);
+       if(entp != NULL && strcmp(entp->mnt_dir, dir) != 0) {
+            res = addmntent(fdnew, entp);
+            if(res != 0)
+                perror("addmntent");
+        }
+    } while(entp != NULL);
+
+    endmntent(fdold);
+    endmntent(fdnew);
+
+    res = rename("/etc/mtab~", "/etc/mtab");
+    if(res == -1)
+        perror("renameing /etc/mtab~ to /etc/mtab");
+}
+
+int fuse_mount(struct fuse *f, const char *dir)
+{
+    int res;
+    const char *dev = FUSE_DEV;
+    const char *type = "fuse";
+
+    if(f->dir != NULL)
+        return 0;
+
+    f->dir = g_strdup(dir);
+    f->fd = open(dev, O_RDWR);
+    if(f->fd == -1) {
+        perror(dev);
+        return -1;
+    }
+    
+    res = do_mount(dev, dir, type, f->fd);
+    if(res == -1)
+        return -1;
+
+    add_mntent(dev, dir, type);
+    
+    return 0;
+}
+
+int fuse_unmount(struct fuse *f)
+{
+    int res;
+
+    if(f->dir == NULL)
+        return 0;
+
+    close(f->fd);
+    f->fd = -1;
+
+    res = umount(f->dir);
+    if(res == -1)
+        perror("umount failed");
+    else
+        remove_mntent(f->dir);
+
+    g_free(f->dir);
+    f->dir = NULL;
+
+    return res;
+}
diff --git a/util.c b/util.c
deleted file mode 100644 (file)
index 57b1a90..0000000
--- a/util.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-    FUSE: Filesystem in Userspace
-    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
-
-    This program can be distributed under the terms of the GNU GPL.
-    See the file COPYING.
-*/
-
-#include "fuse_i.h"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#define FUSE_VERSION "0.1"
-
-spinlock_t fuse_lock = SPIN_LOCK_UNLOCKED;
-
-/* Must be called with the fuse lock held */
-void fuse_release_conn(struct fuse_conn *fc)
-{
-       if(fc->sb == NULL && fc->file == NULL) {
-               kfree(fc);
-       }
-}
-
-int init_module(void)
-{
-       int res;
-
-       printk(KERN_DEBUG "fuse init (version %s)\n", FUSE_VERSION);
-
-       res = fuse_fs_init();
-       if(res)
-               goto err;
-       
-       res = fuse_dev_init();
-       if(res)
-               goto err_fs_cleanup;
-       
-       return 0;
-
-  err_fs_cleanup:
-       fuse_fs_cleanup();
-  err:
-       return res;
-}
-
-void cleanup_module(void)
-{
-       printk(KERN_DEBUG "fuse cleanup\n");
-       
-       fuse_fs_cleanup();
-       fuse_dev_cleanup();
-}
-
-/*
- * Local Variables:
- * indent-tabs-mode: t
- * c-basic-offset: 8
- */