x
authorMiklos Szeredi <miklos@szeredi.hu>
Wed, 31 Oct 2001 14:52:35 +0000 (14:52 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Wed, 31 Oct 2001 14:52:35 +0000 (14:52 +0000)
12 files changed:
fusepro.c
include/fuse.h
include/linux/fuse.h
kernel/Makefile
kernel/dev.c
kernel/dir.c
kernel/file.c [new file with mode: 0644]
kernel/fuse_i.h
kernel/inode.c
lib/fuse.c
lib/fuse_i.h
lib/mount.c

index 4f593e7a0ca8f1d8d403f5f98b0d046d2ad71fa1..ff998bf7844f393e17488c39bf14f9f8b5fc1b86 100644 (file)
--- a/fusepro.c
+++ b/fusepro.c
@@ -1,11 +1,17 @@
-#include <fuse.h>
+#ifdef linux
+/* For pread()/pwrite() */
+#define _XOPEN_SOURCE 500
+#endif
 
+#include <fuse.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <errno.h>
 #include <signal.h>
+#include <utime.h>
+#include <fcntl.h>
 
 static struct fuse *pro_fuse;
 
@@ -53,7 +59,7 @@ static int pro_getdir(const char *path, struct fuse_dh *h, dirfiller_t filler)
     return res;
 }
 
-static int pro_mknod(const char *path, int mode, int rdev)
+static int pro_mknod(const char *path, mode_t mode, dev_t rdev)
 {
     int res;
 
@@ -64,44 +70,44 @@ static int pro_mknod(const char *path, int mode, int rdev)
     return 0;
 }
 
-static int pro_symlink(const char *from, const char *to)
+static int pro_mkdir(const char *path, mode_t mode)
 {
     int res;
 
-    res = symlink(from, to);
+    res = mkdir(path, mode);
     if(res == -1)
         return -errno;
 
     return 0;
 }
 
-static int pro_mkdir(const char *path, int mode)
+static int pro_unlink(const char *path)
 {
     int res;
 
-    res = mkdir(path, mode);
+    res = unlink(path);
     if(res == -1)
         return -errno;
 
     return 0;
 }
 
-static int pro_unlink(const char *path)
+static int pro_rmdir(const char *path)
 {
     int res;
 
-    res = unlink(path);
+    res = rmdir(path);
     if(res == -1)
         return -errno;
 
     return 0;
 }
 
-static int pro_rmdir(const char *path)
+static int pro_symlink(const char *from, const char *to)
 {
     int res;
 
-    res = rmdir(path);
+    res = symlink(from, to);
     if(res == -1)
         return -errno;
 
@@ -130,6 +136,80 @@ static int pro_link(const char *from, const char *to)
     return 0;
 }
 
+static int pro_chmod(const char *path, mode_t mode)
+{
+    int res;
+
+    res = chmod(path, mode);
+    if(res == -1)
+        return -errno;
+    
+    return 0;
+}
+
+static int pro_chown(const char *path, uid_t uid, gid_t gid)
+{
+    int res;
+
+    res = chown(path, uid, gid);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int pro_truncate(const char *path, off_t size)
+{
+    int res;
+    
+    res = truncate(path, size);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+static int pro_utime(const char *path, struct utimbuf *buf)
+{
+    int res;
+    
+    res = utime(path, buf);
+    if(res == -1)
+        return -errno;
+
+    return 0;
+}
+
+
+static int pro_open(const char *path, int flags)
+{
+    int res;
+
+    res = open(path, flags);
+    if(res == -1) 
+        return -errno;
+
+    close(res);
+    return 0;
+}
+
+static int pro_pread(const char *path, char *buf, size_t size, off_t offset)
+{
+    int fd;
+    int res;
+
+    fd = open(path, 0);
+    if(fd == -1)
+        return -errno;
+
+    res = pread(fd, buf, size, offset);
+    if(res == -1)
+        res = -errno;
+    
+    close(fd);
+    return res;
+}
+
 static void exit_handler()
 {
     exit(0);
@@ -176,10 +256,17 @@ static struct fuse_operations pro_oper = {
     rmdir:     pro_rmdir,
     rename:     pro_rename,
     link:      pro_link,
+    chmod:     pro_chmod,
+    chown:     pro_chown,
+    truncate:  pro_truncate,
+    utime:     pro_utime,
+    open:      pro_open,
+    pread:     pro_pread,
 };
 
 int main(int argc, char *argv[])
 {
+    int res;
     if(argc != 2) {
         fprintf(stderr, "usage: %s mount_dir\n", argv[0]);
         exit(1);
@@ -189,7 +276,10 @@ int main(int argc, char *argv[])
     atexit(cleanup);
 
     pro_fuse = fuse_new();
-    fuse_mount(pro_fuse, argv[1]);
+    res = fuse_mount(pro_fuse, argv[1]);
+    if(res == -1)
+        exit(1);
+        
     fuse_set_operations(pro_fuse, &pro_oper);
     fuse_loop(pro_fuse);
 
index e18f606164d067eb9e42aea60b1deba6f8874a5a..bdc96a631b0c47d56aedebda521199a1832a16c8 100644 (file)
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <utime.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 (*getattr)  (const char *path, struct stat *stbuf);
     int (*readlink) (const char *path, char *buf, size_t size);
-    int (*getdir) (const char *path, struct fuse_dh *h, dirfiller_t filler);
-    int (*mknod) (const char *path, int mode, int rdev);
-    int (*mkdir) (const char *path, int mode);
-    int (*unlink) (const char *path);
-    int (*rmdir) (const char *path);
-    int (*rename) (const char *from, const char *to);
-    int (*symlink) (const char *from, const char *to);
-    int (*link) (const char *from, const char *to);
+    int (*getdir)   (const char *path, struct fuse_dh *h, dirfiller_t filler);
+    int (*mknod)    (const char *path, mode_t mode, dev_t rdev);
+    int (*mkdir)    (const char *path, mode_t mode);
+    int (*unlink)   (const char *path);
+    int (*rmdir)    (const char *path);
+    int (*symlink)  (const char *from, const char *to);
+    int (*rename)   (const char *from, const char *to);
+    int (*link)     (const char *from, const char *to);
+    int (*chmod)    (const char *path, mode_t mode);
+    int (*chown)    (const char *path, uid_t uid, gid_t gid);
+    int (*truncate) (const char *path, off_t size);
+    int (*utime)    (const char *path, struct utimbuf *buf);
+    int (*open)     (const char *path, int flags);
+    int (*pread)    (const char *path, char *buf, size_t size, off_t offset);
 };
 
 struct fuse *fuse_new();
index 64a4af371f42bb792ea748005c78438d9d2e3f4a..5fe008ca2c11ad7532c5f57c4f55879d1666fd09 100644 (file)
@@ -19,11 +19,11 @@ struct fuse_mount_data {
 #define FUSE_ROOT_INO 1
 
 struct fuse_attr {
-       unsigned short      mode;
-       unsigned short      nlink;
-       unsigned short      uid;
-       unsigned short      gid;
-       unsigned short      rdev;
+       unsigned int        mode;
+       unsigned int        nlink;
+       unsigned int        uid;
+       unsigned int        gid;
+       unsigned int        rdev;
        unsigned long long  size;
        unsigned long       blksize;
        unsigned long       blocks;
@@ -32,19 +32,28 @@ struct fuse_attr {
        unsigned long       ctime;
 };
 
+#define FATTR_MODE     (1 << 0)
+#define FATTR_UID      (1 << 1)
+#define FATTR_GID      (1 << 2)
+#define FATTR_SIZE     (1 << 3)
+#define FATTR_UTIME    (1 << 4)
+
 enum fuse_opcode {
        FUSE_LOOKUP     = 1,
        FUSE_FORGET,
        FUSE_GETATTR,
+       FUSE_SETATTR,
        FUSE_READLINK,
+       FUSE_SYMLINK,
        FUSE_GETDIR,
        FUSE_MKNOD,
        FUSE_MKDIR,
-       FUSE_SYMLINK,
        FUSE_UNLINK,
        FUSE_RMDIR,
        FUSE_RENAME,
        FUSE_LINK,
+       FUSE_OPEN,
+       FUSE_READ,
 };
 
 /* Conservative buffer size for the client */
@@ -90,6 +99,20 @@ struct fuse_link_in {
        char name[1];
 };
 
+struct fuse_setattr_in {
+       struct fuse_attr attr;
+       unsigned int valid;
+};
+
+struct fuse_open_in {
+       unsigned int flags;
+};
+
+struct fuse_read_in {
+       unsigned long long offset;
+       unsigned int size;
+};
+
 struct fuse_in_header {
        int unique;
        enum fuse_opcode opcode;
index f7769d53f72bd7b145824c5443b238c74c11b3b3..46461623b6e67147ccbcf51808a75beeb39a3ac4 100644 (file)
@@ -5,7 +5,7 @@ CPPFLAGS = -I /lib/modules/`uname -r`/build/include/ -D__KERNEL__ -DMODULE -D_LO
 
 all: fuse.o
 
-fuse_objs = dev.o inode.o dir.o util.o
+fuse_objs = dev.o inode.o dir.o file.o util.o
 
 fuse.o: $(fuse_objs)
        ld -r -o fuse.o $(fuse_objs)
index d32589d2d21e5faa06e584d8fd554cc944136d19..6a8d3738110c12c91149389f4853b590ed2b23a3 100644 (file)
@@ -87,7 +87,7 @@ static struct fuse_req *request_new(struct fuse_conn *fc, struct fuse_in *inp,
 {
        struct fuse_req *req;
        
-       req = kmalloc(sizeof(*req), GFP_KERNEL);
+       req = kmalloc(sizeof(*req), GFP_NOFS);
        if(!req)
                return NULL;
 
@@ -98,7 +98,7 @@ static struct fuse_req *request_new(struct fuse_conn *fc, struct fuse_in *inp,
        req->out = NULL;
 
        req->insize = IHSIZE + inp->argsize;
-       req->in = kmalloc(req->insize, GFP_KERNEL);
+       req->in = kmalloc(req->insize, GFP_NOFS);
        if(!req->in) {
                request_free(req);
                return NULL;
@@ -188,7 +188,7 @@ 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_conn *fc = DEV_FC(file);
        struct fuse_req *req;
        char *tmpbuf;
        unsigned int size;
@@ -249,7 +249,7 @@ 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_conn *fc = DEV_FC(file);
        struct fuse_req *req;
        char *tmpbuf;
        struct fuse_out_header *oh;
@@ -302,7 +302,7 @@ static ssize_t fuse_dev_write(struct file *file, const char *buf,
 
 static unsigned int fuse_dev_poll(struct file *file, poll_table *wait)
 {
-       struct fuse_conn *fc = file->private_data;
+       struct fuse_conn *fc = DEV_FC(file);
        unsigned int mask = POLLOUT | POLLWRNORM;
 
        if(!fc->sb)
@@ -370,7 +370,7 @@ static void end_requests(struct list_head *head)
 
 static int fuse_dev_release(struct inode *inode, struct file *file)
 {
-       struct fuse_conn *fc = file->private_data;
+       struct fuse_conn *fc = DEV_FC(file);
 
        spin_lock(&fuse_lock);
        fc->file = NULL;
index b23def74f8ec46fed7b2f0bed23f727578dff343..1dac0c8127a114e707a7b5c1c5302b8c07d144f5 100644 (file)
@@ -10,9 +10,8 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/file.h>
 #include <linux/slab.h>
+#include <linux/file.h>
 
 static struct inode_operations fuse_dir_inode_operations;
 static struct inode_operations fuse_file_inode_operations;
@@ -20,13 +19,12 @@ static struct inode_operations fuse_symlink_inode_operations;
 static struct inode_operations fuse_special_inode_operations;
 
 static struct file_operations fuse_dir_operations;
-static struct file_operations fuse_file_operations;
 
 static struct dentry_operations fuse_dentry_opertations;
 
 static void change_attributes(struct inode *inode, struct fuse_attr *attr)
 {
-       inode->i_mode    = attr->mode;
+       inode->i_mode    = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
        inode->i_nlink   = attr->nlink;
        inode->i_uid     = attr->uid;
        inode->i_gid     = attr->gid;
@@ -38,29 +36,46 @@ static void change_attributes(struct inode *inode, struct fuse_attr *attr)
        inode->i_ctime   = attr->ctime;
 }
 
-void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
+static void fuse_init_inode(struct inode *inode, int mode, int rdev)
 {
-       change_attributes(inode, attr);
-       
+       inode->i_mode = mode & S_IFMT;
        if(S_ISREG(inode->i_mode)) {
                inode->i_op = &fuse_file_inode_operations;
-               inode->i_fop = &fuse_file_operations;
+               fuse_init_file_inode(inode);
        }
        else if(S_ISDIR(inode->i_mode)) {
                inode->i_op = &fuse_dir_inode_operations;
                inode->i_fop = &fuse_dir_operations;
        }
-       else if(S_ISLNK(inode->i_mode))
+       else if(S_ISLNK(inode->i_mode)) {
                inode->i_op = &fuse_symlink_inode_operations;
+       }
        else {
                inode->i_op = &fuse_special_inode_operations;
-               init_special_inode(inode, inode->i_mode, attr->rdev);
+               init_special_inode(inode, inode->i_mode, rdev);
        }
+       inode->u.generic_ip = inode;
+}
+
+struct inode *fuse_iget(struct super_block *sb, ino_t ino,
+                       struct fuse_attr *attr)
+{
+       struct inode *inode;
+
+       inode = iget(sb, ino);
+       if(inode) {
+               if(!inode->u.generic_ip)
+                       fuse_init_inode(inode, attr->mode, attr->rdev);
+               
+               change_attributes(inode, attr);
+       }
+
+       return inode;
 }
 
 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
 {
-       struct fuse_conn *fc = dir->i_sb->u.generic_sbp;
+       struct fuse_conn *fc = INO_FC(dir);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
        struct fuse_lookup_out arg;
@@ -76,11 +91,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
        
        inode = NULL;
        if(!out.h.error) {
-               inode = iget(dir->i_sb, arg.ino);
+               inode = fuse_iget(dir->i_sb, arg.ino, &arg.attr);
                if(!inode) 
                        return ERR_PTR(-ENOMEM);
-               
-               fuse_init_inode(inode, &arg.attr);
        }
        else if(out.h.error != -ENOENT)
                return ERR_PTR(out.h.error);
@@ -94,7 +107,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
 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_conn *fc = INO_FC(dir);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
        struct fuse_mknod_in *inarg;
@@ -123,11 +136,10 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
        if(out.h.error) 
                return out.h.error;
 
-       inode = iget(dir->i_sb, outarg.ino);
+       inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr);
        if(!inode) 
                return -ENOMEM;
-       
-       fuse_init_inode(inode, &outarg.attr);
+
        d_instantiate(entry, inode);
 
        return 0;
@@ -141,7 +153,7 @@ static int fuse_create(struct inode *dir, struct dentry *entry, int mode)
 
 static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
 {
-       struct fuse_conn *fc = dir->i_sb->u.generic_sbp;
+       struct fuse_conn *fc = INO_FC(dir);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
        struct fuse_mkdir_in *inarg;
@@ -168,7 +180,7 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
 static int fuse_symlink(struct inode *dir, struct dentry *entry,
                        const char *link)
 {
-       struct fuse_conn *fc = dir->i_sb->u.generic_sbp;
+       struct fuse_conn *fc = INO_FC(dir);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
        char *inarg;
@@ -195,7 +207,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
 static int fuse_remove(struct inode *dir, struct dentry *entry, 
                       enum fuse_opcode op)
 {
-       struct fuse_conn *fc = dir->i_sb->u.generic_sbp;
+       struct fuse_conn *fc = INO_FC(dir);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
 
@@ -220,7 +232,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
 static int fuse_rename(struct inode *olddir, struct dentry *oldent,
                       struct inode *newdir, struct dentry *newent)
 {
-       struct fuse_conn *fc = olddir->i_sb->u.generic_sbp;
+       struct fuse_conn *fc = INO_FC(olddir);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
        struct fuse_rename_in *inarg;
@@ -252,7 +264,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
                     struct dentry *newent)
 {
        struct inode *inode = entry->d_inode;
-       struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+       struct fuse_conn *fc = INO_FC(inode);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
        struct fuse_link_in *inarg;
@@ -286,7 +298,7 @@ static int fuse_permission(struct inode *inode, int mask)
 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_conn *fc = INO_FC(inode);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
        struct fuse_getattr_out arg;
@@ -357,7 +369,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
 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_conn *fc = INO_FC(inode);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
        unsigned long page;
@@ -417,7 +429,7 @@ static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
 
 static int fuse_dir_open(struct inode *inode, struct file *file)
 {
-       struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+       struct fuse_conn *fc = INO_FC(inode);
        struct fuse_in in = FUSE_IN_INIT;
        struct fuse_out out = FUSE_OUT_INIT;
        struct fuse_getdir_out outarg;
@@ -453,15 +465,56 @@ static int fuse_dir_open(struct inode *inode, struct file *file)
 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 unsigned int iattr_to_fattr(struct iattr *iattr,
+                                  struct fuse_attr *fattr)
+{
+       unsigned int ivalid = iattr->ia_valid;
+       unsigned int fvalid = 0;
+       
+       memset(fattr, 0, sizeof(*fattr));
+       
+       if(ivalid & ATTR_MODE)
+               fvalid |= FATTR_MODE,   fattr->mode = iattr->ia_mode;
+       if(ivalid & ATTR_UID)
+               fvalid |= FATTR_UID,    fattr->uid = iattr->ia_uid;
+       if(ivalid & ATTR_GID)
+               fvalid |= FATTR_GID,    fattr->gid = iattr->ia_gid;
+       if(ivalid & ATTR_SIZE)
+               fvalid |= FATTR_SIZE,   fattr->size = iattr->ia_size;
+       /* You can only _set_ these together (they may change by themselves) */
+       if((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
+               fvalid |= FATTR_UTIME;
+               fattr->atime = iattr->ia_atime;
+               fattr->mtime = iattr->ia_mtime;
+       }
+
+       return fvalid;
+}
+
+static int fuse_setattr(struct dentry *entry, struct iattr *attr)
+{
+       struct inode *inode = entry->d_inode;
+       struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_in in = FUSE_IN_INIT;
+       struct fuse_out out = FUSE_OUT_INIT;
+       struct fuse_setattr_in arg;
+
+       arg.valid = iattr_to_fattr(attr, &arg.attr);
+       
+       in.h.opcode = FUSE_SETATTR;
+       in.h.ino = inode->i_ino;
+       in.argsize = sizeof(arg);
+       in.arg = &arg;
+       request_send(fc, &in, &out);
+
+       return out.h.error;
+}
+
 static int fuse_dentry_revalidate(struct dentry *entry, int flags)
 {
        if(!entry->d_inode || !(flags & LOOKUP_CONTINUE))
@@ -481,9 +534,7 @@ static struct inode_operations fuse_dir_inode_operations =
        rmdir:          fuse_rmdir,
        rename:         fuse_rename,
        link:           fuse_link,
-#if 0
        setattr:        fuse_setattr,
-#endif
        permission:     fuse_permission,
        revalidate:     fuse_revalidate,
 };
@@ -496,20 +547,20 @@ static struct file_operations fuse_dir_operations = {
 };
 
 static struct inode_operations fuse_file_inode_operations = {
+       setattr:        fuse_setattr,
        permission:     fuse_permission,
        revalidate:     fuse_revalidate,
 };
 
 static struct inode_operations fuse_special_inode_operations = {
+       setattr:        fuse_setattr,
        permission:     fuse_permission,
        revalidate:     fuse_revalidate,
 };
 
-static struct file_operations fuse_file_operations = {
-};
-
 static struct inode_operations fuse_symlink_inode_operations =
 {
+       setattr:        fuse_setattr,
        readlink:       fuse_readlink,
        follow_link:    fuse_follow_link,
        revalidate:     fuse_revalidate,
diff --git a/kernel/file.c b/kernel/file.c
new file mode 100644 (file)
index 0000000..df3a863
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+    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/pagemap.h>
+
+
+static int fuse_open(struct inode *inode, struct file *file)
+{
+       struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_in in = FUSE_IN_INIT;
+       struct fuse_out out = FUSE_OUT_INIT;
+       struct fuse_open_in arg;
+
+       arg.flags = file->f_flags & ~O_EXCL;
+       in.h.opcode = FUSE_OPEN;
+       in.h.ino = inode->i_ino;
+       in.argsize = sizeof(arg);
+       in.arg = &arg;
+       request_send(fc, &in, &out);
+
+       return out.h.error;
+}
+
+static int fuse_readpage(struct file *file, struct page *page)
+{
+       struct inode *inode = page->mapping->host;
+       struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_in in = FUSE_IN_INIT;
+       struct fuse_out out = FUSE_OUT_INIT;
+       struct fuse_read_in arg;
+       char *buffer;
+
+       buffer = kmap(page);
+
+       arg.offset = page->index << PAGE_CACHE_SHIFT;
+       arg.size = PAGE_CACHE_SIZE;
+
+       in.h.opcode = FUSE_READ;
+       in.h.ino = inode->i_ino;
+       in.argsize = sizeof(arg);
+       in.arg = &arg;
+       out.argsize = PAGE_CACHE_SIZE;
+       out.argvar = 1;
+       out.arg = buffer;
+
+       request_send(fc, &in, &out);
+       if(!out.h.error) {
+               if(out.argsize < PAGE_CACHE_SIZE) 
+                       memset(buffer + out.argsize, 0,
+                              PAGE_CACHE_SIZE - out.argsize);
+               SetPageUptodate(page);
+       }
+
+       kunmap(page);
+       UnlockPage(page);
+
+       return out.h.error;
+}
+
+static struct file_operations fuse_file_operations = {
+       open:           fuse_open,
+       read:           generic_file_read,
+};
+
+static struct address_space_operations fuse_file_aops  = {
+       readpage:       fuse_readpage,
+};
+
+void fuse_init_file_inode(struct inode *inode)
+{
+       inode->i_fop = &fuse_file_operations;
+       inode->i_data.a_ops = &fuse_file_aops;
+}
+
+/* 
+ * Local Variables:
+ * indent-tabs-mode: t
+ * c-basic-offset: 8
+ * End:
+ */
index de0a9e65d8a31ec750432718363f3894e78b08e9..aaa395d0add592698a7c13c43da7ebc0ccde8bb1 100644 (file)
@@ -82,6 +82,9 @@ struct fuse_req {
 };
 
 
+#define INO_FC(inode) ((struct fuse_conn *) (inode)->i_sb->u.generic_sbp)
+#define DEV_FC(file) ((struct fuse_conn *) (file)->private_data)
+
 struct fuse_in {
        struct fuse_in_header h;
        unsigned int argsize;
@@ -111,9 +114,16 @@ extern spinlock_t fuse_lock;
 
 
 /**
- * Initialize inode
+ * Get a filled in inode
+ */
+struct inode *fuse_iget(struct super_block *sb, ino_t ino,
+                       struct fuse_attr *attr);
+
+
+/**
+ * Initialise operations on regular file
  */
-void fuse_init_inode(struct inode *inode, struct fuse_attr *attr);
+void fuse_init_file_inode(struct inode *inode);
 
 /**
  * Check if the connection can be released, and if yes, then free the
index 702ef5792e5ae01a3a3cbbbe0693f7c21fcb82aa..ed4f760735e72b45810ebb43c4678a3de5220f5b 100644 (file)
@@ -39,7 +39,7 @@ static int alloc_cleared(struct fuse_conn *fc)
        unsigned long *tmp;
        
        spin_unlock(&fuse_lock);
-       tmp = kmalloc(sizeof(unsigned long) * MAX_CLEARED, GFP_KERNEL);
+       tmp = kmalloc(sizeof(unsigned long) * MAX_CLEARED, GFP_NOFS);
        spin_lock(&fuse_lock);
 
        if(!fc->file || fc->cleared != NULL)
@@ -72,7 +72,7 @@ static unsigned long *add_cleared(struct fuse_conn *fc, unsigned long ino)
 
 static void fuse_clear_inode(struct inode *inode)
 {
-       struct fuse_conn *fc = inode->i_sb->u.generic_sbp;
+       struct fuse_conn *fc = INO_FC(inode);
        unsigned long *forget;
 
        spin_lock(&fuse_lock);
@@ -139,17 +139,11 @@ static struct fuse_conn *get_conn(struct fuse_mount_data *d)
 
 static struct inode *get_root_inode(struct super_block *sb)
 {
-       struct inode *root;
-
-       root = iget(sb, 1);
-       if(root) {
-               struct fuse_attr attr;
-               memset(&attr, 0, sizeof(attr));
-               attr.mode = S_IFDIR;
-               fuse_init_inode(root, &attr);
-       }
+       struct fuse_attr attr;
+       memset(&attr, 0, sizeof(attr));
 
-       return root;
+       attr.mode = S_IFDIR;
+       return fuse_iget(sb, 1, &attr);
 }
 
 static struct super_block *fuse_read_super(struct super_block *sb, 
index f033e0406b5b33b31804a369d5a1123d46f3be97..cd919ed4cc8c820a55f031840829fdbb6a6e86d3 100644 (file)
@@ -27,11 +27,12 @@ static gint name_compare(const struct node *node1, const struct node *node2)
         strcmp(node1->name, node2->name) == 0;
 }
 
-static struct node *new_node(fino_t parent, const char *name)
+static struct node *new_node(fino_t parent, const char *name, int mode)
 {
     struct node *node = g_new0(struct node, 1);
     node->name = g_strdup(name);
     node->parent = parent;
+    node->mode = mode;
     return node;
 }
 
@@ -63,22 +64,43 @@ static struct node *lookup_node(struct fuse *f, fino_t parent,
     return g_hash_table_lookup(f->nametab, &tmp);
 }
 
-static fino_t find_node(struct fuse *f, fino_t parent, char *name, int create)
+static void unhash_node(struct fuse *f, struct node *node)
+{
+    g_hash_table_remove(f->nametab, node);
+    g_free(node->name);
+    node->parent = 0;
+    node->name = NULL;
+}
+
+static fino_t find_node(struct fuse *f, fino_t parent, char *name, int mode)
 {
     struct node *node;
+    mode &= S_IFMT;
 
     node = lookup_node(f, parent, name);
-    if(node != NULL)
-        return get_ino(node);
+    if(node != NULL) {
+        if(node->mode == mode)
+            return get_ino(node);
 
-    if(!create)
-        return (fino_t) -1;
+        unhash_node(f, node);
+    }
 
-    node = new_node(parent, name);
+    node = new_node(parent, name, mode);
     g_hash_table_insert(f->nametab, node, node);
     return get_ino(node);
 }
 
+static fino_t find_node_dir(struct fuse *f, fino_t parent, char *name)
+{
+    struct node *node;
+
+    node = lookup_node(f, parent, name);
+    if(node != NULL)
+        return get_ino(node);
+    else
+        return (fino_t) -1;
+}
+
 static char *get_path(fino_t ino)
 {
     GString *s;
@@ -91,6 +113,10 @@ static char *get_path(fino_t ino)
         struct node *node;
         for(; ino != FUSE_ROOT_INO; ino = node->parent) {
             node = get_node(ino);
+            if(node->name == NULL) {
+                g_string_free(s, TRUE);
+                return NULL;
+            }
             g_string_prepend(s, node->name);
             g_string_prepend_c(s, '/');
         }
@@ -104,32 +130,42 @@ static char *get_path(fino_t ino)
 
 static char *get_path_name(fino_t ino, const char *name)
 {
-    char *path = get_path(ino);
-    char *path2 = g_strconcat(path, "/", name, NULL);
+    char *path;
+    char *path2;
+    
+    path = get_path(ino);
+    if(path == NULL)
+        return NULL;
+
+    path2 = g_strconcat(path, "/", name, NULL);
     g_free(path);
     return path2;
 }
 
-static void remove_node(struct fuse *f, fino_t ino)
+static void destroy_node(struct fuse *f, fino_t ino)
 {
     struct node *node = get_node(ino);
-    g_hash_table_remove(f->nametab, node);
+    unhash_node(f, node);
     free_node(node);
 }
 
+static void remove_node(struct fuse *f, fino_t dir, const char *name)
+{
+    struct node *node = lookup_node(f, dir, name);
+    assert(node != NULL);
+    unhash_node(f, node);
+}
+
 static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
                         fino_t newdir, const char *newname)
 {
     struct node *node = lookup_node(f, olddir, oldname);
     struct node *newnode = lookup_node(f, newdir, newname);
-        
     assert(node != NULL);
 
-    /* The overwritten node is left to dangle until deleted */
     if(newnode != NULL)
-        g_hash_table_remove(f->nametab, newnode);
+        unhash_node(f, newnode);
         
-    /* The renamed node is not freed, since it's pointer is the key */
     g_hash_table_remove(f->nametab, node);
     g_free(node->name);
     node->name = g_strdup(newname);
@@ -159,7 +195,7 @@ static int fill_dir(struct fuse_dh *dh, char *name, int type)
     size_t reclen;
     size_t res;
 
-    dirent.ino = find_node(dh->fuse, dh->dir, name, 0);
+    dirent.ino = find_node_dir(dh->fuse, dh->dir, name);
     dirent.namelen = strlen(name);
     strncpy(dirent.name, name, sizeof(dirent.name));
     dirent.type = type;
@@ -213,14 +249,17 @@ static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
     struct stat buf;
     struct fuse_lookup_out arg;
 
+    res = -ENOENT;
     path = get_path_name(in->ino, name);
-    res = -ENOSYS;
-    if(f->op.getattr)
-        res = f->op.getattr(path, &buf);
-    g_free(path);
+    if(path != NULL) {
+        res = -ENOSYS;
+        if(f->op.getattr)
+            res = f->op.getattr(path, &buf);
+        g_free(path);
+    }
     if(res == 0) {
         convert_stat(&buf, &arg.attr);
-        arg.ino = find_node(f, in->ino, name, 1);
+        arg.ino = find_node(f, in->ino, name, arg.attr.mode);
     }
     send_reply(f, in, res, &arg, sizeof(arg));
 }
@@ -230,7 +269,7 @@ 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]);
+        destroy_node(f, inos[i]);
 }
 
 static void do_getattr(struct fuse *f, struct fuse_in_header *in)
@@ -240,30 +279,78 @@ static void do_getattr(struct fuse *f, struct fuse_in_header *in)
     struct stat buf;
     struct fuse_getattr_out arg;
 
+    res = -ENOENT;
     path = get_path(in->ino);
-    res = -ENOSYS;
-    if(f->op.getattr)
-        res = f->op.getattr(path, &buf);
-    g_free(path);
+    if(path != NULL) {
+        res = -ENOSYS;
+        if(f->op.getattr)
+            res = f->op.getattr(path, &buf);
+        g_free(path);
+    }
     if(res == 0) 
         convert_stat(&buf, &arg.attr);
 
     send_reply(f, in, res, &arg, sizeof(arg));
 }
 
+static void do_setattr(struct fuse *f, struct fuse_in_header *in,
+                       struct fuse_setattr_in *arg)
+{
+    int res;
+    char *path;
+    int valid = arg->valid;
+    struct fuse_attr *attr = &arg->attr;
+
+    res = -ENOENT;
+    path = get_path(in->ino);
+    if(path != NULL) {
+        res = 0;
+        if(!res && (valid & FATTR_MODE)) {
+            res = -ENOSYS;
+            if(f->op.chmod)
+                res = f->op.chmod(path, attr->mode);
+        }        
+        if(!res && (valid & (FATTR_UID | FATTR_GID))) {
+            uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
+            gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
+            
+            res = -ENOSYS;
+            if(f->op.chown)
+                res = f->op.chown(path, uid, gid);
+        }
+        if(!res && (valid & FATTR_SIZE)) {
+            res = -ENOSYS;
+            if(f->op.truncate)
+                res = f->op.truncate(path, attr->size);
+        }
+        if(!res && (valid & FATTR_UTIME)) {
+            struct utimbuf buf;
+            buf.actime = attr->atime;
+            buf.modtime = attr->mtime;
+            res = -ENOSYS;
+            if(f->op.utime)
+                res = f->op.utime(path, &buf);
+        }
+        g_free(path);
+    }
+    send_reply(f, in, res, NULL, 0);
+}
+
 static void do_readlink(struct fuse *f, struct fuse_in_header *in)
 {
     int res;
     char link[PATH_MAX + 1];
     char *path;
 
-    path = get_path(in->ino);    
-    res = -ENOSYS;
-    if(f->op.readlink)
-        res = f->op.readlink(path, link, sizeof(link));
-    g_free(path);
-
-    send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
+    res = -ENOENT;
+    path = get_path(in->ino);
+    if(path != NULL) {
+        res = -ENOSYS;
+        if(f->op.readlink)
+            res = f->op.readlink(path, link, sizeof(link));
+        g_free(path);
+    }
+    send_reply(f, in, res, link, !res ? strlen(link) : 0);
 }
 
 static void do_getdir(struct fuse *f, struct fuse_in_header *in)
@@ -277,12 +364,14 @@ static void do_getdir(struct fuse *f, struct fuse_in_header *in)
     dh.fp = tmpfile();
     dh.dir = in->ino;
 
+    res = -ENOENT;
     path = get_path(in->ino);
-    res = -ENOSYS;
-    if(f->op.getdir)
-        res = f->op.getdir(path, &dh, (dirfiller_t) fill_dir);
-    g_free(path);
-
+    if(path != NULL) {
+        res = -ENOSYS;
+        if(f->op.getdir)
+            res = f->op.getdir(path, &dh, (dirfiller_t) fill_dir);
+        g_free(path);
+    }
     fflush(dh.fp);
     arg.fd = fileno(dh.fp);
     send_reply(f, in, res, &arg, sizeof(arg));
@@ -297,17 +386,20 @@ static void do_mknod(struct fuse *f, struct fuse_in_header *in,
     struct fuse_mknod_out outarg;
     struct stat buf;
 
+    res = -ENOENT;
     path = get_path_name(in->ino, inarg->name);
-    res = -ENOSYS;
-    if(f->op.mknod && f->op.getattr) {
-        res = f->op.mknod(path, inarg->mode, inarg->rdev);
-        if(res == 0)
-            res = f->op.getattr(path, &buf);
+    if(path != NULL) {
+        res = -ENOSYS;
+        if(f->op.mknod && f->op.getattr) {
+            res = f->op.mknod(path, inarg->mode, inarg->rdev);
+            if(res == 0)
+                res = f->op.getattr(path, &buf);
+        }
+        g_free(path);
     }
-    g_free(path);
     if(res == 0) {
         convert_stat(&buf, &outarg.attr);
-        outarg.ino = find_node(f, in->ino, inarg->name, 1);
+        outarg.ino = find_node(f, in->ino, inarg->name, outarg.attr.mode);
     }
 
     send_reply(f, in, res, &outarg, sizeof(outarg));
@@ -319,11 +411,14 @@ static void do_mkdir(struct fuse *f, struct fuse_in_header *in,
     int res;
     char *path;
 
+    res = -ENOENT;
     path = get_path_name(in->ino, inarg->name);
-    res = -ENOSYS;
-    if(f->op.mkdir)
-        res = f->op.mkdir(path, inarg->mode);
-    g_free(path);
+    if(path != NULL) {
+        res = -ENOSYS;
+        if(f->op.mkdir)
+            res = f->op.mkdir(path, inarg->mode);
+        g_free(path);
+    }
     send_reply(f, in, res, NULL, 0);
 }
 
@@ -332,17 +427,22 @@ static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name)
     int res;
     char *path;
 
+    res = -ENOENT;
     path = get_path_name(in->ino, name);
-    res = -ENOSYS;
-    if(in->opcode == FUSE_UNLINK) {
-        if(f->op.unlink)
-            res = f->op.unlink(path);
-    }
-    else {
-        if(f->op.rmdir)
-            res = f->op.rmdir(path);
+    if(path != NULL) {
+        res = -ENOSYS;
+        if(in->opcode == FUSE_UNLINK) {
+            if(f->op.unlink)
+                res = f->op.unlink(path);
+        }
+        else {
+            if(f->op.rmdir)
+                res = f->op.rmdir(path);
+        }
+        g_free(path);
     }
-    g_free(path);
+    if(res == 0)
+        remove_node(f, in->ino, name);
     send_reply(f, in, res, NULL, 0);
 }
 
@@ -352,11 +452,14 @@ static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name,
     int res;
     char *path;
 
+    res = -ENOENT;
     path = get_path_name(in->ino, name);
-    res = -ENOSYS;
-    if(f->op.symlink)
-        res = f->op.symlink(link, path);
-    g_free(path);
+    if(path != NULL) {
+        res = -ENOSYS;
+        if(f->op.symlink)
+            res = f->op.symlink(link, path);
+        g_free(path);
+    }
     send_reply(f, in, res, NULL, 0);
 }
 
@@ -368,31 +471,90 @@ static void do_rename(struct fuse *f, struct fuse_in_header *in,
     fino_t newdir = inarg->newdir;
     char *oldname = inarg->names;
     char *newname = inarg->names + strlen(oldname) + 1;
-    char *oldpath = get_path_name(olddir, oldname);
-    char *newpath = get_path_name(newdir, newname);
-
-    res = -ENOSYS;
-    if(f->op.rename)
-        res = f->op.rename(oldpath, newpath);
-    if(res == 0)
-        rename_node(f, olddir, oldname, newdir, newname);
+    char *oldpath;
+    char *newpath;
+
+    res = -ENOENT;
+    oldpath = get_path_name(olddir, oldname);
+    if(oldpath != NULL) {
+        newpath = get_path_name(newdir, newname);
+        if(newpath != NULL) {
+            res = -ENOSYS;
+            if(f->op.rename)
+                res = f->op.rename(oldpath, newpath);
+            if(res == 0)
+                rename_node(f, olddir, oldname, newdir, newname);
+            g_free(newpath);
+        }
+        g_free(oldpath);
+    }
     send_reply(f, in, res, NULL, 0);   
 }
 
 static void do_link(struct fuse *f, struct fuse_in_header *in,
-                    struct fuse_link_in *inarg)
+                    struct fuse_link_in *arg)
 {
     int res;
-    char *oldpath = get_path(in->ino);
-    char *newpath = get_path_name(inarg->newdir, inarg->name);
+    char *oldpath;
+    char *newpath;
+
+    res = -ENOENT;
+    oldpath = get_path(in->ino);
+    if(oldpath != NULL) {
+        newpath =  get_path_name(arg->newdir, arg->name);
+        if(newpath != NULL) {
+            res = -ENOSYS;
+            if(f->op.link)
+                res = f->op.link(oldpath, newpath);
+            g_free(newpath);
+        }
+        g_free(oldpath);
+    }
+    send_reply(f, in, res, NULL, 0);   
+}
 
-    res = -ENOSYS;
-    if(f->op.link)
-        res = f->op.link(oldpath, newpath);
+static void do_open(struct fuse *f, struct fuse_in_header *in,
+                    struct fuse_open_in *arg)
+{
+    int res;
+    char *path;
 
-    send_reply(f, in, res, NULL, 0);   
+    res = -ENOENT;
+    path = get_path(in->ino);
+    if(path != NULL) {
+        res = -ENOSYS;
+        if(f->op.open)
+            res = f->op.open(path, arg->flags);
+        g_free(path);
+    }
+    send_reply(f, in, res, NULL, 0);
 }
 
+static void do_read(struct fuse *f, struct fuse_in_header *in,
+                    struct fuse_read_in *arg)
+{
+    int res;
+    char *path;
+    char *buf = g_malloc(arg->size);
+    size_t size;
+
+    path = get_path(in->ino);
+    if(path != NULL) {
+        res = -ENOSYS;
+        if(f->op.pread)
+            res = f->op.pread(path, buf, arg->size, arg->offset);
+        g_free(path);
+    }
+    
+    size = 0;
+    if(res > 0) {
+        size = res;
+        res = 0;
+    }
+
+    send_reply(f, in, res, buf, size);
+    g_free(buf);
+}
 
 void fuse_loop(struct fuse *f)
 {
@@ -435,6 +597,10 @@ void fuse_loop(struct fuse *f)
             do_getattr(f, in);
             break;
 
+        case FUSE_SETATTR:
+            do_setattr(f, in, (struct fuse_setattr_in *) inarg);
+            break;
+
         case FUSE_READLINK:
             do_readlink(f, in);
             break;
@@ -469,6 +635,14 @@ void fuse_loop(struct fuse *f)
             do_link(f, in, (struct fuse_link_in *) inarg);
             break;
 
+        case FUSE_OPEN:
+            do_open(f, in, (struct fuse_open_in *) inarg);
+            break;
+
+        case FUSE_READ:
+            do_read(f, in, (struct fuse_read_in *) inarg);
+            break;
+
         default:
             fprintf(stderr, "Operation %i not implemented\n", in->opcode);
             /* No need to send reply to async requests */
index b3b907bf4186d9709aa44c221a255d4279a86239..2d030ae7c26312e0c4148b94b48afc43d24ae18f 100644 (file)
@@ -17,6 +17,7 @@ typedef unsigned long fino_t;
 struct node {
     char *name;
     fino_t parent;
+    int mode;
 };
 
 struct fuse {
index ace3c6552a40c1cd12a4935577c52954de1f77a5..48d9d45423f3d6eea38c7ecf07249cdc264e1d0d 100644 (file)
@@ -103,7 +103,6 @@ int fuse_mount(struct fuse *f, const char *dir)
     if(f->dir != NULL)
         return 0;
 
-    f->dir = g_strdup(dir);
     f->fd = open(dev, O_RDWR);
     if(f->fd == -1) {
         perror(dev);
@@ -115,6 +114,7 @@ int fuse_mount(struct fuse *f, const char *dir)
         return -1;
 
     add_mntent(dev, dir, type);
+    f->dir = g_strdup(dir);
     
     return 0;
 }