From bc22e7bec727bc72d91a3001fbda976f1adf352d Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Tue, 23 Oct 2001 19:26:04 +0000 Subject: [PATCH] Imported sources --- Makefile | 33 +++++++++++ dev.c | 133 +++++++++++++++++++++++++++++++++++++++++++ dir.c | 87 ++++++++++++++++++++++++++++ fuse.h | 17 ++++++ fuse_i.h | 69 ++++++++++++++++++++++ fusemount.c | 87 ++++++++++++++++++++++++++++ inode.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 61 ++++++++++++++++++++ 8 files changed, 648 insertions(+) create mode 100644 Makefile create mode 100644 dev.c create mode 100644 dir.c create mode 100644 fuse.h create mode 100644 fuse_i.h create mode 100644 fusemount.c create mode 100644 inode.c create mode 100644 main.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..aedd26d --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +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 +CPPFLAGS = + +all: fuse.o fusemount + +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 + +main.o: main.c + $(CC) $(KCFLAGS) $(KCPPFLAGS) -c main.c + +fuse_objs = dev.o inode.o dir.o main.o + +fuse.o: $(fuse_objs) + ld -r -o fuse.o $(fuse_objs) + +fusemount: fusemount.o + +clean: + rm -f *.o + rm -f fusemount + rm -f *~ diff --git a/dev.c b/dev.c new file mode 100644 index 0000000..c7dd247 --- /dev/null +++ b/dev.c @@ -0,0 +1,133 @@ +/* + 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/smp_lock.h> +#include <linux/poll.h> +#include <linux/file.h> +#include <linux/proc_fs.h> + +static struct proc_dir_entry *proc_fs_fuse; +struct proc_dir_entry *proc_fuse_dev; + +static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, + loff_t *off) +{ + printk(KERN_DEBUG "fuse_dev_read\n"); + return 0; +} + +static ssize_t fuse_dev_write(struct file *file, const char *buf, + size_t nbytes, loff_t *off) +{ + printk(KERN_DEBUG "fuse_dev_write <%.*s>\n", (int) nbytes, buf); + return nbytes; +} + + +static unsigned int fuse_dev_poll(struct file *file, poll_table *wait) +{ + printk(KERN_DEBUG "fuse_dev_poll\n"); + return 0; +} + +static int fuse_dev_open(struct inode *inode, struct file *file) +{ + int res; + struct fuse_conn *fc; + + printk(KERN_DEBUG "fuse_dev_open\n"); + + res = -ENOMEM; + fc = kmalloc(sizeof(*fc), GFP_KERNEL); + if(!fc) + goto out; + + fc->sb = NULL; + fc->file = file; + + lock_kernel(); + file->private_data = fc; + unlock_kernel(); + res = 0; + + out: + return res; +} + +static int fuse_dev_release(struct inode *inode, struct file *file) +{ + struct fuse_conn *fc = file->private_data; + + printk(KERN_DEBUG "fuse_dev_release\n"); + + lock_kernel(); + fc->file = NULL; + fuse_release_conn(fc); + unlock_kernel(); + 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 res; + + proc_fs_fuse = NULL; + proc_fuse_dev = NULL; + + res = -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 res; + +} + +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 new file mode 100644 index 0000000..afa6106 --- /dev/null +++ b/dir.c @@ -0,0 +1,87 @@ +/* + 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/module.h> +#include <linux/kernel.h> +#include <linux/smp_lock.h> +#include <linux/sched.h> +#include <linux/file.h> + +static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry) +{ + printk(KERN_DEBUG "fuse_lookup: %li\n", dir->i_ino); + + return NULL; +} + +static int fuse_permission(struct inode *inode, int mask) +{ + printk(KERN_DEBUG "fuse_permission: %li, 0%o\n", inode->i_ino, mask); + + return 0; +} + +static int fuse_revalidate(struct dentry *dentry) +{ + printk(KERN_DEBUG "fuse_revalidate: %li\n", + dentry->d_inode->i_ino); + + return 0; +} +static int fuse_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + printk(KERN_DEBUG "fuse_readdir: %li\n", + file->f_dentry->d_inode->i_ino); + + return 0; +} + +static int fuse_open(struct inode *inode, struct file *file) +{ + printk(KERN_DEBUG "fuse_open: %li\n", inode->i_ino); + + return 0; +} + +static int fuse_release(struct inode *inode, struct file *file) +{ + printk(KERN_DEBUG "fuse_release: %li\n", inode->i_ino); + + return 0; +} + +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, +}; + +void fuse_dir_init(struct inode *inode) +{ + inode->i_op = &fuse_dir_inode_operations; + inode->i_fop = &fuse_dir_operations; +} + + +/* + * Local Variables: + * indent-tabs-mode: t + * c-basic-offset: 8 + * End: + */ diff --git a/fuse.h b/fuse.h new file mode 100644 index 0000000..df71221 --- /dev/null +++ b/fuse.h @@ -0,0 +1,17 @@ +/* -*- indent-tabs-mode: t; c-basic-offset: 8; -*- */ +/* + 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. +*/ + + +#define FUSE_MOUNT_VERSION 1 + +struct fuse_mount_data { + int version; + int fd; +}; + diff --git a/fuse_i.h b/fuse_i.h new file mode 100644 index 0000000..5e1cc1c --- /dev/null +++ b/fuse_i.h @@ -0,0 +1,69 @@ +/* + 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/fs.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 proc entry for the client device ("/proc/fs/fuse/dev") + */ +extern struct proc_dir_entry *proc_fuse_dev; + +/** + * Fill in the directory operations + */ +void fuse_dir_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); + +/* + * Local Variables: + * indent-tabs-mode: t + * c-basic-offset: 8 + */ diff --git a/fusemount.c b/fusemount.c new file mode 100644 index 0000000..b4d3bc0 --- /dev/null +++ b/fusemount.c @@ -0,0 +1,87 @@ +/* + 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 <string.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/mount.h> +#include <mntent.h> + + +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 main(int argc, char *argv[]) +{ + const char *dev; + const char *dir; + int devfd; + + if(argc < 3) { + fprintf(stderr, "usage: %s dev dir\n", argv[0]); + exit(1); + } + + dev = argv[1]; + 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, dir, devfd); + + sleep(1000); + + return 0; +} diff --git a/inode.c b/inode.c new file mode 100644 index 0000000..77040fc --- /dev/null +++ b/inode.c @@ -0,0 +1,161 @@ +/* + 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 "fuse_i.h" + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/smp_lock.h> +#include <linux/sched.h> +#include <linux/file.h> + +#define FUSE_SUPER_MAGIC 0x65735546 + +static void fuse_read_inode(struct inode *inode) +{ + printk(KERN_DEBUG "fuse_read_inode: %li\n", inode->i_ino); + + +} + +static void fuse_put_super(struct super_block *sb) +{ + struct fuse_conn *fc = sb->u.generic_sbp; + + printk(KERN_DEBUG "fuse_put_super\n"); + + fc->sb = NULL; + fuse_release_conn(fc); +} + +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; + + printk(KERN_DEBUG "fuse_read_super\n"); + + 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 super_block *fuse_read_super(struct super_block *sb, + void *data, int silent) +{ + struct fuse_conn *fc; + struct inode *root; + + fc = get_conn(data); + if(fc == NULL) + goto err; + + if(fc->sb != NULL) { + printk("fuse_read_super: file already mounted\n"); + goto err; + } + + sb->u.generic_sbp = fc; + sb->s_blocksize = 1024; + sb->s_blocksize_bits = 10; + sb->s_magic = FUSE_SUPER_MAGIC; + sb->s_op = &fuse_super_operations; + + root = iget(sb, 1); + if(!root) { + printk("fuse_read_super: failed to get root inode\n"); + goto err; + } + + printk(KERN_DEBUG "root inode: %ld/%d\n", root->i_ino, root->i_dev); + + 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); + + sb->s_root = d_alloc_root(root); + if(!sb->s_root) { + printk("fuse_read_super: failed to allocate root dentry\n"); + goto err_iput; + } + + fc->sb = sb; + + return sb; + + err_iput: + iput(root); + err: + 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/main.c b/main.c new file mode 100644 index 0000000..fa4ca8c --- /dev/null +++ b/main.c @@ -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/smp_lock.h> +#include <linux/slab.h> + +#define FUSE_VERSION "0.1" + + +void fuse_release_conn(struct fuse_conn *fc) +{ + if(fc->sb == NULL && fc->file == NULL) { + printk(KERN_DEBUG "fuse: release connection\n"); + 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 + */ -- 2.30.2