diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2005-11-07 00:59:50 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 07:53:42 -0800 |
commit | 31d40d74b402a6fa18a006fb3745f64609f35b77 (patch) | |
tree | ee8c61e814fcae687e3ba3f8ed4828d6d34f8ff2 | |
parent | 5b62073d502a88fedc5c369f8a004bda7c9d1999 (diff) | |
download | lwn-31d40d74b402a6fa18a006fb3745f64609f35b77.tar.gz lwn-31d40d74b402a6fa18a006fb3745f64609f35b77.zip |
[PATCH] FUSE: add access call
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>
-rw-r--r-- | fs/fuse/dir.c | 35 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 3 | ||||
-rw-r--r-- | include/linux/fuse.h | 8 |
3 files changed, 45 insertions, 1 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 61b58fdd973e..4bc1afcc476d 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -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; } } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 5cb456f572c1..c4e8c3b47982 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -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; }; diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 6e91c9a3a0b6..507913b65af0 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -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; |