linux/fs/generic_acl.c
<<
>>
Prefs
   1/*
   2 * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
   3 *
   4 * This file is released under the GPL.
   5 *
   6 * Generic ACL support for in-memory filesystems.
   7 */
   8
   9#include <linux/sched.h>
  10#include <linux/gfp.h>
  11#include <linux/fs.h>
  12#include <linux/generic_acl.h>
  13#include <linux/posix_acl.h>
  14#include <linux/posix_acl_xattr.h>
  15
  16
  17static size_t
  18generic_acl_list(struct dentry *dentry, char *list, size_t list_size,
  19                const char *name, size_t name_len, int type)
  20{
  21        struct posix_acl *acl;
  22        const char *xname;
  23        size_t size;
  24
  25        acl = get_cached_acl(dentry->d_inode, type);
  26        if (!acl)
  27                return 0;
  28        posix_acl_release(acl);
  29
  30        switch (type) {
  31        case ACL_TYPE_ACCESS:
  32                xname = POSIX_ACL_XATTR_ACCESS;
  33                break;
  34        case ACL_TYPE_DEFAULT:
  35                xname = POSIX_ACL_XATTR_DEFAULT;
  36                break;
  37        default:
  38                return 0;
  39        }
  40        size = strlen(xname) + 1;
  41        if (list && size <= list_size)
  42                memcpy(list, xname, size);
  43        return size;
  44}
  45
  46static int
  47generic_acl_get(struct dentry *dentry, const char *name, void *buffer,
  48                     size_t size, int type)
  49{
  50        struct posix_acl *acl;
  51        int error;
  52
  53        if (strcmp(name, "") != 0)
  54                return -EINVAL;
  55
  56        acl = get_cached_acl(dentry->d_inode, type);
  57        if (!acl)
  58                return -ENODATA;
  59        error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
  60        posix_acl_release(acl);
  61
  62        return error;
  63}
  64
  65static int
  66generic_acl_set(struct dentry *dentry, const char *name, const void *value,
  67                     size_t size, int flags, int type)
  68{
  69        struct inode *inode = dentry->d_inode;
  70        struct posix_acl *acl = NULL;
  71        int error;
  72
  73        if (strcmp(name, "") != 0)
  74                return -EINVAL;
  75        if (S_ISLNK(inode->i_mode))
  76                return -EOPNOTSUPP;
  77        if (!inode_owner_or_capable(inode))
  78                return -EPERM;
  79        if (value) {
  80                acl = posix_acl_from_xattr(&init_user_ns, value, size);
  81                if (IS_ERR(acl))
  82                        return PTR_ERR(acl);
  83        }
  84        if (acl) {
  85                error = posix_acl_valid(acl);
  86                if (error)
  87                        goto failed;
  88                switch (type) {
  89                case ACL_TYPE_ACCESS:
  90                        error = posix_acl_equiv_mode(acl, &inode->i_mode);
  91                        if (error < 0)
  92                                goto failed;
  93                        inode->i_ctime = CURRENT_TIME;
  94                        if (error == 0) {
  95                                posix_acl_release(acl);
  96                                acl = NULL;
  97                        }
  98                        break;
  99                case ACL_TYPE_DEFAULT:
 100                        if (!S_ISDIR(inode->i_mode)) {
 101                                error = -EINVAL;
 102                                goto failed;
 103                        }
 104                        break;
 105                }
 106        }
 107        set_cached_acl(inode, type, acl);
 108        error = 0;
 109failed:
 110        posix_acl_release(acl);
 111        return error;
 112}
 113
 114/**
 115 * generic_acl_init  -  Take care of acl inheritance at @inode create time
 116 *
 117 * Files created inside a directory with a default ACL inherit the
 118 * directory's default ACL.
 119 */
 120int
 121generic_acl_init(struct inode *inode, struct inode *dir)
 122{
 123        struct posix_acl *acl = NULL;
 124        int error;
 125
 126        if (!S_ISLNK(inode->i_mode))
 127                acl = get_cached_acl(dir, ACL_TYPE_DEFAULT);
 128        if (acl) {
 129                if (S_ISDIR(inode->i_mode))
 130                        set_cached_acl(inode, ACL_TYPE_DEFAULT, acl);
 131                error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
 132                if (error < 0)
 133                        return error;
 134                if (error > 0)
 135                        set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
 136        } else {
 137                inode->i_mode &= ~current_umask();
 138        }
 139        error = 0;
 140
 141        posix_acl_release(acl);
 142        return error;
 143}
 144
 145/**
 146 * generic_acl_chmod  -  change the access acl of @inode upon chmod()
 147 *
 148 * A chmod also changes the permissions of the owner, group/mask, and
 149 * other ACL entries.
 150 */
 151int
 152generic_acl_chmod(struct inode *inode)
 153{
 154        struct posix_acl *acl;
 155        int error = 0;
 156
 157        if (S_ISLNK(inode->i_mode))
 158                return -EOPNOTSUPP;
 159        acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
 160        if (acl) {
 161                error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
 162                if (error)
 163                        return error;
 164                set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
 165                posix_acl_release(acl);
 166        }
 167        return error;
 168}
 169
 170const struct xattr_handler generic_acl_access_handler = {
 171        .prefix = POSIX_ACL_XATTR_ACCESS,
 172        .flags  = ACL_TYPE_ACCESS,
 173        .list   = generic_acl_list,
 174        .get    = generic_acl_get,
 175        .set    = generic_acl_set,
 176};
 177
 178const struct xattr_handler generic_acl_default_handler = {
 179        .prefix = POSIX_ACL_XATTR_DEFAULT,
 180        .flags  = ACL_TYPE_DEFAULT,
 181        .list   = generic_acl_list,
 182        .get    = generic_acl_get,
 183        .set    = generic_acl_set,
 184};
 185