From 1c7c474c31aea6d5cb2fb35f31d9e9e91ae466b1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 3 Nov 2009 16:44:44 +0100 Subject: make generic_acl slightly more generic Now that we cache the ACL pointers in the generic inode all the generic_acl cruft can go away and generic_acl.c can directly implement xattr handlers dealing with the full Posix ACL semantics for in-memory filesystems. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/generic_acl.c | 158 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 89 insertions(+), 69 deletions(-) (limited to 'fs/generic_acl.c') diff --git a/fs/generic_acl.c b/fs/generic_acl.c index e0b53aa..5545803 100644 --- a/fs/generic_acl.c +++ b/fs/generic_acl.c @@ -1,62 +1,58 @@ /* - * fs/generic_acl.c - * * (C) 2005 Andreas Gruenbacher * * This file is released under the GPL. + * + * Generic ACL support for in-memory filesystems. */ #include #include #include +#include +#include -/** - * generic_acl_list - Generic xattr_handler->list() operation - * @ops: Filesystem specific getacl and setacl callbacks - */ -size_t -generic_acl_list(struct inode *inode, struct generic_acl_operations *ops, - int type, char *list, size_t list_size) + +static size_t +generic_acl_list(struct dentry *dentry, char *list, size_t list_size, + const char *name, size_t name_len, int type) { struct posix_acl *acl; - const char *name; + const char *xname; size_t size; - acl = ops->getacl(inode, type); + acl = get_cached_acl(dentry->d_inode, type); if (!acl) return 0; posix_acl_release(acl); - switch(type) { - case ACL_TYPE_ACCESS: - name = POSIX_ACL_XATTR_ACCESS; - break; - - case ACL_TYPE_DEFAULT: - name = POSIX_ACL_XATTR_DEFAULT; - break; - - default: - return 0; + switch (type) { + case ACL_TYPE_ACCESS: + xname = POSIX_ACL_XATTR_ACCESS; + break; + case ACL_TYPE_DEFAULT: + xname = POSIX_ACL_XATTR_DEFAULT; + break; + default: + return 0; } - size = strlen(name) + 1; + size = strlen(xname) + 1; if (list && size <= list_size) - memcpy(list, name, size); + memcpy(list, xname, size); return size; } -/** - * generic_acl_get - Generic xattr_handler->get() operation - * @ops: Filesystem specific getacl and setacl callbacks - */ -int -generic_acl_get(struct inode *inode, struct generic_acl_operations *ops, - int type, void *buffer, size_t size) +static int +generic_acl_get(struct dentry *dentry, const char *name, void *buffer, + size_t size, int type) { struct posix_acl *acl; int error; - acl = ops->getacl(inode, type); + if (strcmp(name, "") != 0) + return -EINVAL; + + acl = get_cached_acl(dentry->d_inode, type); if (!acl) return -ENODATA; error = posix_acl_to_xattr(acl, buffer, size); @@ -65,17 +61,16 @@ generic_acl_get(struct inode *inode, struct generic_acl_operations *ops, return error; } -/** - * generic_acl_set - Generic xattr_handler->set() operation - * @ops: Filesystem specific getacl and setacl callbacks - */ -int -generic_acl_set(struct inode *inode, struct generic_acl_operations *ops, - int type, const void *value, size_t size) +static int +generic_acl_set(struct dentry *dentry, const char *name, const void *value, + size_t size, int flags, int type) { + struct inode *inode = dentry->d_inode; struct posix_acl *acl = NULL; int error; + if (strcmp(name, "") != 0) + return -EINVAL; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; if (!is_owner_or_cap(inode)) @@ -91,28 +86,27 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops, error = posix_acl_valid(acl); if (error) goto failed; - switch(type) { - case ACL_TYPE_ACCESS: - mode = inode->i_mode; - error = posix_acl_equiv_mode(acl, &mode); - if (error < 0) - goto failed; - inode->i_mode = mode; - if (error == 0) { - posix_acl_release(acl); - acl = NULL; - } - break; - - case ACL_TYPE_DEFAULT: - if (!S_ISDIR(inode->i_mode)) { - error = -EINVAL; - goto failed; - } - break; + switch (type) { + case ACL_TYPE_ACCESS: + mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); + if (error < 0) + goto failed; + inode->i_mode = mode; + if (error == 0) { + posix_acl_release(acl); + acl = NULL; + } + break; + case ACL_TYPE_DEFAULT: + if (!S_ISDIR(inode->i_mode)) { + error = -EINVAL; + goto failed; + } + break; } } - ops->setacl(inode, type, acl); + set_cached_acl(inode, type, acl); error = 0; failed: posix_acl_release(acl); @@ -121,14 +115,12 @@ failed: /** * generic_acl_init - Take care of acl inheritance at @inode create time - * @ops: Filesystem specific getacl and setacl callbacks * * Files created inside a directory with a default ACL inherit the * directory's default ACL. */ int -generic_acl_init(struct inode *inode, struct inode *dir, - struct generic_acl_operations *ops) +generic_acl_init(struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; mode_t mode = inode->i_mode; @@ -136,7 +128,7 @@ generic_acl_init(struct inode *inode, struct inode *dir, inode->i_mode = mode & ~current_umask(); if (!S_ISLNK(inode->i_mode)) - acl = ops->getacl(dir, ACL_TYPE_DEFAULT); + acl = get_cached_acl(dir, ACL_TYPE_DEFAULT); if (acl) { struct posix_acl *clone; @@ -145,7 +137,7 @@ generic_acl_init(struct inode *inode, struct inode *dir, error = -ENOMEM; if (!clone) goto cleanup; - ops->setacl(inode, ACL_TYPE_DEFAULT, clone); + set_cached_acl(inode, ACL_TYPE_DEFAULT, clone); posix_acl_release(clone); } clone = posix_acl_clone(acl, GFP_KERNEL); @@ -156,7 +148,7 @@ generic_acl_init(struct inode *inode, struct inode *dir, if (error >= 0) { inode->i_mode = mode; if (error > 0) - ops->setacl(inode, ACL_TYPE_ACCESS, clone); + set_cached_acl(inode, ACL_TYPE_ACCESS, clone); } posix_acl_release(clone); } @@ -169,20 +161,19 @@ cleanup: /** * generic_acl_chmod - change the access acl of @inode upon chmod() - * @ops: FIlesystem specific getacl and setacl callbacks * * A chmod also changes the permissions of the owner, group/mask, and * other ACL entries. */ int -generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops) +generic_acl_chmod(struct inode *inode) { struct posix_acl *acl, *clone; int error = 0; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; - acl = ops->getacl(inode, ACL_TYPE_ACCESS); + acl = get_cached_acl(inode, ACL_TYPE_ACCESS); if (acl) { clone = posix_acl_clone(acl, GFP_KERNEL); posix_acl_release(acl); @@ -190,8 +181,37 @@ generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops) return -ENOMEM; error = posix_acl_chmod_masq(clone, inode->i_mode); if (!error) - ops->setacl(inode, ACL_TYPE_ACCESS, clone); + set_cached_acl(inode, ACL_TYPE_ACCESS, clone); posix_acl_release(clone); } return error; } + +int +generic_check_acl(struct inode *inode, int mask) +{ + struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS); + + if (acl) { + int error = posix_acl_permission(inode, acl, mask); + posix_acl_release(acl); + return error; + } + return -EAGAIN; +} + +struct xattr_handler generic_acl_access_handler = { + .prefix = POSIX_ACL_XATTR_ACCESS, + .flags = ACL_TYPE_ACCESS, + .list = generic_acl_list, + .get = generic_acl_get, + .set = generic_acl_set, +}; + +struct xattr_handler generic_acl_default_handler = { + .prefix = POSIX_ACL_XATTR_DEFAULT, + .flags = ACL_TYPE_DEFAULT, + .list = generic_acl_list, + .get = generic_acl_get, + .set = generic_acl_set, +}; -- cgit v1.1