]> Pileus Git - ~andy/linux/blobdiff - fs/fuse/dir.c
Merge branch 'master'
[~andy/linux] / fs / fuse / dir.c
index f156392d019e5b19ecec16223fe5fc4a0455dd8b..21fd59c7bc24d5d25728114ed4c4d0824ea6fb61 100644 (file)
@@ -23,8 +23,7 @@
 /*
  * Calculate the time in jiffies until a dentry/attributes are valid
  */
-static inline unsigned long time_to_jiffies(unsigned long sec,
-                                           unsigned long nsec)
+static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec)
 {
        struct timespec ts = {sec, nsec};
        return jiffies + timespec_to_jiffies(&ts);
@@ -157,7 +156,7 @@ static int dir_alias(struct inode *inode)
        return 0;
 }
 
-static inline int invalid_nodeid(u64 nodeid)
+static int invalid_nodeid(u64 nodeid)
 {
        return !nodeid || nodeid == FUSE_ROOT_ID;
 }
@@ -166,6 +165,12 @@ static struct dentry_operations fuse_dentry_operations = {
        .d_revalidate   = fuse_dentry_revalidate,
 };
 
+static int valid_mode(int m)
+{
+       return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
+               S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
+}
+
 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
                                  struct nameidata *nd)
 {
@@ -185,7 +190,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
        fuse_lookup_init(req, dir, entry, &outarg);
        request_send(fc, req);
        err = req->out.h.error;
-       if (!err && outarg.nodeid && invalid_nodeid(outarg.nodeid))
+       if (!err && ((outarg.nodeid && invalid_nodeid(outarg.nodeid)) ||
+                    !valid_mode(outarg.attr.mode)))
                err = -EIO;
        if (!err && outarg.nodeid) {
                inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
@@ -328,10 +334,13 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
                fuse_put_request(fc, req);
                return err;
        }
-       if (invalid_nodeid(outarg.nodeid)) {
-               fuse_put_request(fc, req);
-               return -EIO;
-       }
+       err = -EIO;
+       if (invalid_nodeid(outarg.nodeid))
+               goto out_put_request;
+
+       if ((outarg.attr.mode ^ mode) & S_IFMT)
+               goto out_put_request;
+
        inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
                          &outarg.attr);
        if (!inode) {
@@ -340,8 +349,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
        }
        fuse_put_request(fc, req);
 
-       /* Don't allow userspace to do really stupid things... */
-       if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) {
+       if (dir_alias(inode)) {
                iput(inode);
                return -EIO;
        }
@@ -350,6 +358,10 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
        fuse_change_timeout(entry, &outarg);
        fuse_invalidate_attr(dir);
        return 0;
+
+ out_put_request:
+       fuse_put_request(fc, req);
+       return err;
 }
 
 static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
@@ -750,13 +762,6 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
        return 0;
 }
 
-static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
-                                      struct inode *inode, loff_t pos,
-                                      size_t count)
-{
-       return fuse_send_read_common(req, file, inode, pos, count, 1);
-}
-
 static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
 {
        int err;
@@ -780,7 +785,9 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
        }
        req->num_pages = 1;
        req->pages[0] = page;
-       nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
+       fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
+       request_send(fc, req);
+       nbytes = req->out.args[0].size;
        err = req->out.h.error;
        fuse_put_request(fc, req);
        if (!err)