summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2009-11-03 16:44:44 +0100
committerAl Viro <viro@zeniv.linux.org.uk>2009-12-16 12:16:49 -0500
commit1c7c474c31aea6d5cb2fb35f31d9e9e91ae466b1 (patch)
tree89a5fd1146be1744ce3ac94789542841512315b8 /fs
parent431547b3c4533b8c7fd150ab36980b9a3147797b (diff)
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 <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/generic_acl.c158
1 files changed, 89 insertions, 69 deletions
diff --git a/fs/generic_acl.c b/fs/generic_acl.c
index e0b53aa7bbec..55458031e501 100644
--- a/fs/generic_acl.c
+++ b/fs/generic_acl.c
@@ -1,62 +1,58 @@
/*
- * fs/generic_acl.c
- *
* (C) 2005 Andreas Gruenbacher <agruen@suse.de>
*
* This file is released under the GPL.
+ *
+ * Generic ACL support for in-memory filesystems.
*/
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/generic_acl.h>
+#include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
-/**
- * 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,
+};