netns xfrm: fix "ip xfrm state|policy count" misreport
[safe/jmp/linux-2.6] / fs / generic_acl.c
index 995d63b..5545803 100644 (file)
@@ -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,22 +115,20 @@ 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;
        int error;
 
-       inode->i_mode = mode & ~current->fs->umask;
+       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,
+};