[PATCH] FUSE: add access call
authorMiklos Szeredi <miklos@szeredi.hu>
Mon, 7 Nov 2005 08:59:50 +0000 (00:59 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 7 Nov 2005 15:53:42 +0000 (07:53 -0800)
Add a new access call, which will only be called if ->permission is invoked
from sys_access().  In all other cases permission checking is delayed until
the actual filesystem operation.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/fuse/dir.c
fs/fuse/fuse_i.h
include/linux/fuse.h

index 61b58fdd973e353c584cc0db7bf76763977ab5a4..4bc1afcc476da7f6b7d61099be0d38e373050088 100644 (file)
@@ -461,6 +461,38 @@ static int fuse_revalidate(struct dentry *entry)
        return fuse_do_getattr(inode);
 }
 
+static int fuse_access(struct inode *inode, int mask)
+{
+       struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_req *req;
+       struct fuse_access_in inarg;
+       int err;
+
+       if (fc->no_access)
+               return 0;
+
+       req = fuse_get_request(fc);
+       if (!req)
+               return -EINTR;
+
+       memset(&inarg, 0, sizeof(inarg));
+       inarg.mask = mask;
+       req->in.h.opcode = FUSE_ACCESS;
+       req->in.h.nodeid = get_node_id(inode);
+       req->inode = inode;
+       req->in.numargs = 1;
+       req->in.args[0].size = sizeof(inarg);
+       req->in.args[0].value = &inarg;
+       request_send(fc, req);
+       err = req->out.h.error;
+       fuse_put_request(fc, req);
+       if (err == -ENOSYS) {
+               fc->no_access = 1;
+               err = 0;
+       }
+       return err;
+}
+
 static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
@@ -493,6 +525,9 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
                int mode = inode->i_mode;
                if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
                        return -EACCES;
+
+               if (nd && (nd->flags & LOOKUP_ACCESS))
+                       return fuse_access(inode, mask);
                return 0;
        }
 }
index 5cb456f572c1c97d7bf016b1ac0493dedccbde35..c4e8c3b479821428607d7c91a4df6a03ce56d947 100644 (file)
@@ -266,6 +266,9 @@ struct fuse_conn {
        /** Is removexattr not implemented by fs? */
        unsigned no_removexattr : 1;
 
+       /** Is access not implemented by fs? */
+       unsigned no_access : 1;
+
        /** Backing dev info */
        struct backing_dev_info bdi;
 };
index 6e91c9a3a0b6de5858e3d18f879ee8d62a6141c3..507913b65af02e61e59a551eba68818a4bc66cc3 100644 (file)
@@ -99,7 +99,8 @@ enum fuse_opcode {
        FUSE_OPENDIR       = 27,
        FUSE_READDIR       = 28,
        FUSE_RELEASEDIR    = 29,
-       FUSE_FSYNCDIR      = 30
+       FUSE_FSYNCDIR      = 30,
+       FUSE_ACCESS        = 34
 };
 
 /* Conservative buffer size for the client */
@@ -222,6 +223,11 @@ struct fuse_getxattr_out {
        __u32   padding;
 };
 
+struct fuse_access_in {
+       __u32   mask;
+       __u32   padding;
+};
+
 struct fuse_init_in_out {
        __u32   major;
        __u32   minor;