KCFLAGS = -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -pipe
KCPPFLAGS = -I /lib/modules/`uname -r`/build/include/ -D__KERNEL__ -DMODULE -D_LOOSE_KERNEL_NAMES
-CFLAGS = -Wall -W -g
+CFLAGS = -Wall -W -g `glib-config --cflags`
+LDFLAGS = `glib-config --libs`
CPPFLAGS =
all: fuse.o fusemount
#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;
return ret;
}
-void request_send(struct fuse_conn *fc, struct fuse_inparam *in,
- struct fuse_outparam *out, int valuret)
+void request_send(struct fuse_conn *fc, struct fuse_in *in,
+ struct fuse_out *out)
{
int ret;
struct fuse_req *req;
return;
}
- req->param.u.i = *in;
- req->size = sizeof(req->param);
+ req->in = in;
+ req->out = out;
req->done = 0;
init_waitqueue_head(&req->waitq);
spin_lock(&fuse_lock);
- req->param.unique = fc->reqctr ++;
+ if(fc->file == NULL) {
+ ret = -ENOTCONN;
+ goto out;
+ }
+
+ req->in->h.unique = fc->reqctr ++;
list_add_tail(&req->list, &fc->pending);
fc->outstanding ++;
/* FIXME: Wait until the number of outstanding requests drops
wake_up(&fc->waitq);
ret = request_wait_answer(req);
fc->outstanding --;
- *out = req->param.u.o;
list_del(&req->list);
+
+ out:
kfree(req);
spin_unlock(&fuse_lock);
if(ret)
out->result = ret;
- else if (out->result < -512 || (out->result > 0 && !valuret)) {
+ else if (out->result <= -512 || out->result > 0) {
printk("Bad result from client: %i\n", out->result);
- out->result = -EIO;
+ out->result = -EPROTO;
}
}
return ret;
}
+
static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes,
loff_t *off)
{
ssize_t ret;
struct fuse_conn *fc = file->private_data;
struct fuse_req *req;
- struct fuse_param param;
size_t size;
spin_lock(&fuse_lock);
if(ret)
goto err;
- printk(KERN_DEBUG "fuse_dev_read[%i]\n", fc->id);
-
req = list_entry(fc->pending.next, struct fuse_req, list);
- param = req->param;
- size = req->size;
+ size = ICSIZE + req->in->argsize;
- ret = -EIO;
+ ret = -EPROTO;
if(nbytes < size) {
printk("fuse_dev_read: buffer too small (%i)\n", size);
goto err;
list_add_tail(&req->list, &fc->processing);
spin_unlock(&fuse_lock);
- if(copy_to_user(buf, ¶m, size))
+ if(copy_to_user(buf, &req->in->c, ICSIZE) ||
+ copy_to_user(buf + ICSIZE, req->in->arg, req->in->argsize))
return -EFAULT;
return size;
list_for_each(entry, &fc->processing) {
struct fuse_req *tmp;
tmp = list_entry(entry, struct fuse_req, list);
- if(tmp->param.unique == unique) {
+ if(tmp->in->c.unique == unique) {
req = tmp;
- list_del_init(&req->list);
break;
}
}
size_t nbytes, loff_t *off)
{
struct fuse_conn *fc = file->private_data;
- struct fuse_param param;
struct fuse_req *req;
+ struct fuse_out_common oc;
+ char *tmpbuf;
- printk(KERN_DEBUG "fuse_dev_write[%i]\n", fc->id);
-
- if(nbytes < sizeof(param.unique) || nbytes > sizeof(param)) {
- printk("fuse_dev_write: write is short or long\n");
- return -EIO;
+ if(nbytes > 2 * PAGE_SIZE) {
+ printk("fuse_dev_write: write is too long\n");
+ return -EPROTO;
}
+
+ tmpbuf = (char *) __get_free_pages(GFP_KERNEL, 1);
+ if(!tmpbuf)
+ return -ENOMEM;
- if(copy_from_user(¶m, buf, nbytes))
+ if(copy_from_user(tmpbuf, buf, nbytes))
return -EFAULT;
-
+
spin_lock(&fuse_lock);
- req = request_find(fc, param.unique);
+ req = request_find(fc, oc.unique);
+
if(req == NULL)
printk("fuse_dev_write[%i]: unknown request: %i", fc->id,
- param.unique);
+ oc.unique);
+
+
+
else {
+ struct fuse_outparam *out = ¶m.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);
{
struct fuse_conn *fc;
- printk(KERN_DEBUG "fuse_dev_open\n");
-
fc = new_conn();
if(!fc)
return -ENOMEM;
fc->file = file;
file->private_data = fc;
- printk(KERN_DEBUG "new connection: %i\n", fc->id);
-
return 0;
}
+static void end_requests(struct list_head *head)
+{
+ while(!list_empty(head)) {
+ struct fuse_req *req;
+ req = list_entry(head->next, struct fuse_req, list);
+ list_del_init(&req->list);
+ req->done = 1;
+ req->param.u.o.result = -ECONNABORTED;
+ wake_up(&req->waitq);
+ }
+}
+
static int fuse_dev_release(struct inode *inode, struct file *file)
{
struct fuse_conn *fc = file->private_data;
- printk(KERN_DEBUG "fuse_dev_release[%i]\n", fc->id);
-
spin_lock(&fuse_lock);
fc->file = NULL;
+ end_requests(&fc->pending);
+ end_requests(&fc->processing);
fuse_release_conn(fc);
spin_unlock(&fuse_lock);
return 0;
See the file COPYING.
*/
-
#include "fuse_i.h"
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+
+static void change_attributes(struct inode *inode, struct fuse_attr *attr)
+{
+ inode->i_mode = attr->mode;
+ inode->i_nlink = attr->nlink;
+ inode->i_uid = attr->uid;
+ inode->i_gid = attr->gid;
+ inode->i_size = attr->size;
+ inode->i_blksize = attr->blksize;
+ inode->i_blocks = attr->blocks;
+ inode->i_atime = attr->atime;
+ inode->i_mtime = attr->mtime;
+ inode->i_ctime = attr->ctime;
+}
+
+static void init_inode(struct inode *inode, struct fuse_attr *attr)
+{
+ change_attributes(inode, attr);
+
+ if(S_ISREG(inode->i_mode))
+ fuse_file_init(inode);
+ else if(S_ISDIR(inode->i_mode))
+ fuse_dir_init(inode);
+ else if(S_ISLNK(inode->i_mode))
+ fuse_symlink_init(inode);
+ else
+ init_special_inode(inode, inode->i_mode, attr->rdev);
+}
static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
{
- printk(KERN_DEBUG "fuse_lookup: %li\n", dir->i_ino);
+ struct fuse_conn *fc = dir->i_sb->u.generic_sbp;
+ struct fuse_inparam in;
+ struct fuse_outparam out;
+ struct inode *inode;
+
+ in.opcode = FUSE_LOOKUP;
+ in.ino = dir->i_ino;
+ strcpy(in.u.lookup.name, entry->d_name.name);
+
+ request_send(fc, &in, &out);
+
+ if(out.result)
+ return ERR_PTR(out.result);
+
+ inode = iget(dir->i_sb, out.u.lookup.ino);
+ if(!inode)
+ return ERR_PTR(-ENOMEM);
+
+ init_inode(inode, &out.u.lookup.attr);
+ d_add(entry, inode);
return NULL;
}
static int fuse_permission(struct inode *inode, int mask)
{
- printk(KERN_DEBUG "fuse_permission: %li, 0%o\n", inode->i_ino, mask);
return 0;
}
static int fuse_revalidate(struct dentry *dentry)
{
- printk(KERN_DEBUG "fuse_revalidate: %li\n",
- dentry->d_inode->i_ino);
+ struct inode *inode = dentry->d_inode;
+ struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+ struct fuse_inparam in;
+ struct fuse_outparam out;
- return 0;
+ in.opcode = FUSE_GETATTR;
+ in.ino = inode->i_ino;
+
+ request_send(fc, &in, &out);
+
+ if(out.result == 0)
+ change_attributes(inode, &out.u.getattr.attr);
+
+ return out.result;
}
-static int fuse_readdir(struct file *file, void *dirent, filldir_t filldir)
+
+
+#define DIR_BUFSIZE 2048
+
+static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
{
- printk(KERN_DEBUG "fuse_readdir: %li\n",
- file->f_dentry->d_inode->i_ino);
+ struct file *cfile = file->private_data;
+ char *buf;
+ char *p;
+ int ret;
+ size_t nbytes;
+ buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
+ if(!buf)
+ return -ENOMEM;
+
+ ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
+ if(ret < 0) {
+ printk("fuse_readdir: failed to read container file\n");
+ goto out;
+ }
+ nbytes = ret;
+ p = buf;
+ ret = 0;
+ while(nbytes >= FUSE_NAME_OFFSET) {
+ struct fuse_dirent *dirent = (struct fuse_dirent *) p;
+ size_t reclen = FUSE_DIRENT_SIZE(dirent);
+ int err;
+ if(dirent->namelen > NAME_MAX) {
+ printk("fuse_readdir: name too long\n");
+ ret = -EPROTO;
+ goto out;
+ }
+ if(reclen > nbytes)
+ break;
+
+ err = filldir(dstbuf, dirent->name, dirent->namelen,
+ file->f_pos, dirent->ino, dirent->type);
+ if(err) {
+ ret = err;
+ break;
+ }
+ p += reclen;
+ file->f_pos += reclen;
+ nbytes -= reclen;
+ ret ++;
+ }
+
+ out:
+ kfree(buf);
+ return ret;
+}
+
+
+
+static int read_link(struct dentry *dentry, char **bufp)
+{
+ struct inode *inode = dentry->d_inode;
+ struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+ struct fuse_in in;
+ struct fuse_out out;
+ unsigned long page;
+
+ page = __get_free_page(GFP_KERNEL);
+ if(!page)
+ return -ENOMEM;
+
+ in.c.opcode = FUSE_READLINK;
+ in.c.ino = inode->i_ino;
+ in.argsize = 0;
+ out.arg = (void *) page;
+ out.argsize = PAGE_SIZE;
+
+ request_send(fc, &in, &out);
+ if(out.c.result) {
+ __free_page(page);
+ return out.c.result;
+ }
+
+ *bufp = (char *) page;
+ (*bufp)[PAGE_SIZE - 1] = 0;
return 0;
}
+static void free_link(char *link)
+{
+ __free_page((unsigned long) link);
+}
+
+static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+ int ret;
+ char *link;
+
+ ret = read_link(dentry, &link);
+ if(ret)
+ return ret;
+
+ ret = vfs_readlink(dentry, buffer, buflen, link);
+ free_link(link);
+ return ret;
+}
+
+static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ int ret;
+ char *link;
+
+ ret = read_link(dentry, &link);
+ if(ret)
+ return ret;
+
+ ret = vfs_follow_link(nd, link);
+ free_link(link);
+ return ret;
+}
+
static int fuse_open(struct inode *inode, struct file *file)
{
struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
struct fuse_inparam in;
struct fuse_outparam out;
+ struct file *cfile = NULL;
- printk(KERN_DEBUG "fuse_open: %li\n", inode->i_ino);
-
in.opcode = FUSE_OPEN;
- in.u.open.ino = inode->i_ino;
+ in.ino = inode->i_ino;
in.u.open.flags = file->f_flags & ~O_EXCL;
- request_send(fc, &in, &out, 0);
+ request_send(fc, &in, &out);
+
+ if(out.result == 0) {
+ struct inode *inode;
+ cfile = out.u.open_internal.file;
+ if(!cfile) {
+ printk("fuse_open: invalid container file\n");
+ return -EPROTO;
+ }
+ inode = cfile->f_dentry->d_inode;
+ if(!S_ISREG(inode->i_mode)) {
+ printk("fuse_open: container is not a regular file\n");
+ fput(cfile);
+ return -EPROTO;
+ }
- printk(KERN_DEBUG " fuse_open: <%i> %i\n", out.result, out.u.open.fd);
+ file->private_data = cfile;
+ }
return out.result;
}
static int fuse_release(struct inode *inode, struct file *file)
{
- printk(KERN_DEBUG "fuse_release: %li\n", inode->i_ino);
+ struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+ struct file *cfile = file->private_data;
+ struct fuse_inparam in;
+ struct fuse_outparam out;
- return 0;
+ if(cfile)
+ fput(cfile);
+
+ in.opcode = FUSE_RELEASE;
+ request_send(fc, &in, &out);
+
+ return out.result;
}
static struct inode_operations fuse_dir_inode_operations =
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:
See the file COPYING.
*/
+#include <linux/limits.h>
#define FUSE_MOUNT_VERSION 1
int fd;
};
+#define FUSE_ROOT_INO 1
+
+struct fuse_attr {
+ unsigned short mode;
+ unsigned short nlink;
+ unsigned short uid;
+ unsigned short gid;
+ unsigned short rdev;
+ unsigned long size;
+ unsigned long blksize;
+ unsigned long blocks;
+ unsigned long atime;
+ unsigned long mtime;
+ unsigned long ctime;
+};
+
enum fuse_opcode {
+ FUSE_LOOKUP,
+ FUSE_GETATTR,
+ FUSE_READLINK,
FUSE_OPEN,
FUSE_RELEASE,
};
-struct fuse_inparam {
- enum fuse_opcode opcode;
- union {
- struct {
- unsigned int ino;
- int flags;
- } open;
- } u;
+/* Conservative buffer size for the client */
+#define FUSE_MAX_IN 8192
+
+struct fuse_in_open {
+ int flag;
};
-struct fuse_outparam {
- int result;
- union {
- struct {
- int fd;
- } open;
- } u;
+struct fuse_out_open {
+ int fd;
+};
+
+struct fuse_in_lookup {
+ char name[NAME_MAX + 1];
+};
+
+struct fuse_out_lookup {
+ unsigned long ino;
+ struct fuse_attr attr;
+};
+
+struct fuse_out_getattr {
+ struct fuse_attr attr;
};
-struct fuse_param {
+struct fuse_out_readlink {
+ char link[PATH_MAX + 1];
+};
+
+struct fuse_in_common {
+ int unique;
+ enum fuse_opcode opcode;
+ unsigned long ino;
+};
+
+struct fuse_out_common {
int unique;
int result;
- union {
- struct fuse_inparam i;
- struct fuse_outparam o;
- } u;
};
+struct fuse_in {
+ struct fuse_in_common c;
+ size_t argsize;
+ void *arg;
+};
+
+struct fuse_out {
+ struct fuse_out_common c;
+ size_t argsize;
+ void *arg;
+};
+
+struct fuse_dirent {
+ unsigned long ino;
+ unsigned short namelen;
+ unsigned char type;
+ char name[NAME_MAX + 1];
+};
+
+#define FUSE_NAME_OFFSET ((size_t) ((struct fuse_dirent *) 0)->name)
+#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(long) - 1) & ~(sizeof(long) - 1))
+#define FUSE_DIRENT_SIZE(d) \
+ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
/*
* Local Variables:
/** The request list */
struct list_head list;
- /** The size of the parameters */
- size_t size;
+ /** The request input parameters */
+ struct fuse_in *in;
- /** The request parameters */
- struct fuse_param param;
+ /** The request result */
+ struct fuse_out *out;
+
+ /** The file returned by open */
+ struct file *file;
/** The request wait queue */
wait_queue_head_t waitq;
int done;
};
+struct fuse_out_open_internal {
+ file *file;
+};
+
+
/**
* The proc entry for the client device ("/proc/fs/fuse/dev")
*/
*/
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
/**
* Send a request
*
- * @valuret: if true then the request can return a positive value
*/
-void request_send(struct fuse_conn *fc, struct fuse_inparam *in,
- struct fuse_outparam *out, int valuret);
+void request_send(struct fuse_conn *fc, struct fuse_in *in,
+ struct fuse_out *out);
/*
* Local Variables:
#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, ¶m, sizeof(param));
perror("read");
exit(1);
}
-
+
printf("unique: %i, opcode: %i\n", param.unique, param.u.i.opcode);
- param.u.o.result = 0;
-
+
+ dirfd = -1;
+ in = param.u.i;
+ switch(in.opcode) {
+ case FUSE_LOOKUP:
+ out.u.lookup.ino = find_node(in.ino, in.u.lookup.name);
+ if(out.u.lookup.ino == 0)
+ out.result = -ENOENT;
+ else
+ out.result = get_attributes(out.u.lookup.ino,
+ &out.u.lookup.attr);
+ break;
+
+ case FUSE_GETATTR:
+ out.result = get_attributes(in.ino, &out.u.getattr.attr);
+ break;
+
+ case FUSE_OPEN:
+ dirfd = get_dir(in.ino);
+ if(dirfd >= 0) {
+ out.u.open.fd = dirfd;
+ out.result = 0;
+ }
+ else
+ out.result = dirfd;
+ break;
+
+ case FUSE_RELEASE:
+ out.result = 0;
+ break;
+
+ default:
+ out.result = -EOPNOTSUPP;
+ }
+ param.u.o = out;
+
res = write(devfd, ¶m, sizeof(param));
if(res == -1) {
perror("write");
exit(1);
}
+ if(dirfd != -1) {
+ close(dirfd);
+ unlink("/tmp/dirtmp");
+ }
}
}
return 0;
}
+int unmount_fuse(const char *dir)
+{
+ int res;
+ FILE *fdold, *fdnew;
+ struct mntent *entp;
+
+ res = umount(dir);
+
+ if(res == -1) {
+ fprintf(stderr, "umount failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ fdold = setmntent("/etc/mtab", "r");
+ if(fdold == NULL) {
+ fprintf(stderr, "setmntent(\"/etc/mtab\") failed: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ fdnew = setmntent("/etc/mtab~", "w");
+ if(fdnew == NULL) {
+ fprintf(stderr, "setmntent(\"/etc/mtab~\") failed: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ do {
+ entp = getmntent(fdold);
+ if(entp != NULL) {
+ if(strcmp(entp->mnt_dir, dir) != 0) {
+ res = addmntent(fdnew, entp);
+ if(res != 0) {
+ fprintf(stderr, "addmntent() failed: %s\n",
+ strerror(errno));
+ }
+ }
+ }
+ } while(entp != NULL);
+
+ endmntent(fdold);
+ endmntent(fdnew);
+
+ res = rename("/etc/mtab~", "/etc/mtab");
+ if(res == -1) {
+ fprintf(stderr, "rename(\"/etc/mtab~\", \"/etc/mtab\") failed: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+void cleanup()
+{
+ unmount_fuse(mount_dir);
+}
+
+
+void exit_handler()
+{
+ exit(0);
+}
+
+void set_signal_handlers()
+{
+ struct sigaction sa;
+
+ sa.sa_handler = exit_handler;
+ sigemptyset(&(sa.sa_mask));
+ sa.sa_flags = 0;
+
+ if (sigaction(SIGHUP, &sa, NULL) == -1 ||
+ sigaction(SIGINT, &sa, NULL) == -1 ||
+ sigaction(SIGTERM, &sa, NULL) == -1) {
+
+ perror("Cannot set exit signal handlers");
+ exit(1);
+ }
+
+ sa.sa_handler = SIG_IGN;
+
+ if(sigaction(SIGPIPE, &sa, NULL) == -1) {
+ perror("Cannot set ignored signals");
+ exit(1);
+ }
+}
+
+
int main(int argc, char *argv[])
{
const char *dev;
- const char *dir;
int devfd;
if(argc < 3) {
}
dev = argv[1];
- dir = argv[2];
+ mount_dir = argv[2];
devfd = open(dev, O_RDWR);
if(devfd == -1) {
exit(1);
}
- mount_fuse(dev, dir, devfd);
+ mount_fuse(dev, mount_dir, devfd);
+
+ set_signal_handlers();
+ atexit(cleanup);
+
+ root = new_node("/", FUSE_ROOT_INO);
+ nodetab = g_hash_table_new(NULL, NULL);
+ g_hash_table_insert(nodetab, (gpointer) FUSE_ROOT_INO, root);
loop(devfd);
return 0;
}
+
+
+
static void fuse_read_inode(struct inode *inode)
{
- printk(KERN_DEBUG "fuse_read_inode: %li\n", inode->i_ino);
-
-
+ /* No op */
}
static void fuse_put_super(struct super_block *sb)
{
struct fuse_conn *fc = sb->u.generic_sbp;
- printk(KERN_DEBUG "fuse_put_super[%i]\n", fc->id);
-
spin_lock(&fuse_lock);
fc->sb = NULL;
fuse_release_conn(fc);
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;
return NULL;
}
- printk(KERN_DEBUG "root inode: %ld/%d\n", root->i_ino, root->i_dev);
-
spin_lock(&fuse_lock);
fc = get_conn(data);
if(fc == NULL)
void fuse_release_conn(struct fuse_conn *fc)
{
if(fc->sb == NULL && fc->file == NULL) {
- printk(KERN_DEBUG "fuse: release connection: %i\n", fc->id);
kfree(fc);
}
}