diff options
-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) | |||
461 | return fuse_do_getattr(inode); | 461 | return fuse_do_getattr(inode); |
462 | } | 462 | } |
463 | 463 | ||
464 | static int fuse_access(struct inode *inode, int mask) | ||
465 | { | ||
466 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
467 | struct fuse_req *req; | ||
468 | struct fuse_access_in inarg; | ||
469 | int err; | ||
470 | |||
471 | if (fc->no_access) | ||
472 | return 0; | ||
473 | |||
474 | req = fuse_get_request(fc); | ||
475 | if (!req) | ||
476 | return -EINTR; | ||
477 | |||
478 | memset(&inarg, 0, sizeof(inarg)); | ||
479 | inarg.mask = mask; | ||
480 | req->in.h.opcode = FUSE_ACCESS; | ||
481 | req->in.h.nodeid = get_node_id(inode); | ||
482 | req->inode = inode; | ||
483 | req->in.numargs = 1; | ||
484 | req->in.args[0].size = sizeof(inarg); | ||
485 | req->in.args[0].value = &inarg; | ||
486 | request_send(fc, req); | ||
487 | err = req->out.h.error; | ||
488 | fuse_put_request(fc, req); | ||
489 | if (err == -ENOSYS) { | ||
490 | fc->no_access = 1; | ||
491 | err = 0; | ||
492 | } | ||
493 | return err; | ||
494 | } | ||
495 | |||
464 | static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | 496 | static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) |
465 | { | 497 | { |
466 | struct fuse_conn *fc = get_fuse_conn(inode); | 498 | struct fuse_conn *fc = get_fuse_conn(inode); |
@@ -493,6 +525,9 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
493 | int mode = inode->i_mode; | 525 | int mode = inode->i_mode; |
494 | if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) | 526 | if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) |
495 | return -EACCES; | 527 | return -EACCES; |
528 | |||
529 | if (nd && (nd->flags & LOOKUP_ACCESS)) | ||
530 | return fuse_access(inode, mask); | ||
496 | return 0; | 531 | return 0; |
497 | } | 532 | } |
498 | } | 533 | } |
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 { | |||
266 | /** Is removexattr not implemented by fs? */ | 266 | /** Is removexattr not implemented by fs? */ |
267 | unsigned no_removexattr : 1; | 267 | unsigned no_removexattr : 1; |
268 | 268 | ||
269 | /** Is access not implemented by fs? */ | ||
270 | unsigned no_access : 1; | ||
271 | |||
269 | /** Backing dev info */ | 272 | /** Backing dev info */ |
270 | struct backing_dev_info bdi; | 273 | struct backing_dev_info bdi; |
271 | }; | 274 | }; |
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 { | |||
99 | FUSE_OPENDIR = 27, | 99 | FUSE_OPENDIR = 27, |
100 | FUSE_READDIR = 28, | 100 | FUSE_READDIR = 28, |
101 | FUSE_RELEASEDIR = 29, | 101 | FUSE_RELEASEDIR = 29, |
102 | FUSE_FSYNCDIR = 30 | 102 | FUSE_FSYNCDIR = 30, |
103 | FUSE_ACCESS = 34 | ||
103 | }; | 104 | }; |
104 | 105 | ||
105 | /* Conservative buffer size for the client */ | 106 | /* Conservative buffer size for the client */ |
@@ -222,6 +223,11 @@ struct fuse_getxattr_out { | |||
222 | __u32 padding; | 223 | __u32 padding; |
223 | }; | 224 | }; |
224 | 225 | ||
226 | struct fuse_access_in { | ||
227 | __u32 mask; | ||
228 | __u32 padding; | ||
229 | }; | ||
230 | |||
225 | struct fuse_init_in_out { | 231 | struct fuse_init_in_out { |
226 | __u32 major; | 232 | __u32 major; |
227 | __u32 minor; | 233 | __u32 minor; |