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(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 (!is_owner_or_cap(inode))
  78                return -EPERM;
  79        if (value) {
  80                acl = posix_acl_from_xattr(value, size);
  81                if (IS_ERR(acl))
  82                        return PTR_ERR(acl);
  83        }
  84        if (acl) {
  85                mode_t mode;
  86
  87                error = posix_acl_valid(acl);
  88                if (error)
  89                        goto failed;
  90                switch (type) {
  91                case ACL_TYPE_ACCESS:
  92                        mode = inode->i_mode;
  93                        error = posix_acl_equiv_mode(acl, &mode);
  94                        if (error < 0)
  95                                goto failed;
  96                        inode->i_mode = mode;
  97                        if (error == 0) {
  98                                posix_acl_release(acl);
  99                                acl = NULL;
 100                        }
 101                        break;
 102                case ACL_TYPE_DEFAULT:
 103                        if (!S_ISDIR(inode->i_mode)) {
 104                                error = -EINVAL;
 105                                goto failed;
 106                        }
 107                        break;
 108                }
 109        }
 110        set_cached_acl(inode, type, acl);
 111        error = 0;
 112failed:
 113        posix_acl_release(acl);
 114        return error;
 115}
 116
 117/**
 118 * generic_acl_init  -  Take care of acl inheritance at @inode create time
 119 *
 120 * Files created inside a directory with a default ACL inherit the
 121 * directory's default ACL.
 122 */
 123int
 124generic_acl_init(struct inode *inode, struct inode *dir)
 125{
 126        struct posix_acl *acl = NULL;
 127        mode_t mode = inode->i_mode;
 128        int error;
 129
 130        inode->i_mode = mode & ~current_umask();
 131        if (!S_ISLNK(inode->i_mode))
 132                acl = get_cached_acl(dir, ACL_TYPE_DEFAULT);
 133        if (acl) {
 134                struct posix_acl *clone;
 135
 136                if (S_ISDIR(inode->i_mode)) {
 137                        clone = posix_acl_clone(acl, GFP_KERNEL);
 138                        error = -ENOMEM;
 139                        if (!clone)
 140                                goto cleanup;
 141                        set_cached_acl(inode, ACL_TYPE_DEFAULT, clone);
 142                        posix_acl_release(clone);
 143                }
 144                clone = posix_acl_clone(acl, GFP_KERNEL);
 145                error = -ENOMEM;
 146                if (!clone)
 147                        goto cleanup;
 148                error = posix_acl_create_masq(clone, &mode);
 149                if (error >= 0) {
 150                        inode->i_mode = mode;
 151                        if (error > 0)
 152                                set_cached_acl(inode, ACL_TYPE_ACCESS, clone);
 153                }
 154                posix_acl_release(clone);
 155        }
 156        error = 0;
 157
 158cleanup:
 159        posix_acl_release(acl);
 160        return error;
 161}
 162
 163/**
 164 * generic_acl_chmod  -  change the access acl of @inode upon chmod()
 165 *
 166 * A chmod also changes the permissions of the owner, group/mask, and
 167 * other ACL entries.
 168 */
 169int
 170generic_acl_chmod(struct inode *inode)
 171{
 172        struct posix_acl *acl, *clone;
 173        int error = 0;
 174
 175        if (S_ISLNK(inode->i_mode))
 176                return -EOPNOTSUPP;
 177        acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
 178        if (acl) {
 179                clone = posix_acl_clone(acl, GFP_KERNEL);
 180                posix_acl_release(acl);
 181                if (!clone)
 182                        return -ENOMEM;
 183                error = posix_acl_chmod_masq(clone, inode->i_mode);
 184                if (!error)
 185                        set_cached_acl(inode, ACL_TYPE_ACCESS, clone);
 186                posix_acl_release(clone);
 187        }
 188        return error;
 189}
 190
 191int
 192generic_check_acl(struct inode *inode, int mask)
 193{
 194        struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
 195
 196        if (acl) {
 197                int error = posix_acl_permission(inode, acl, mask);
 198                posix_acl_release(acl);
 199                return error;
 200        }
 201        return -EAGAIN;
 202}
 203
 204const struct xattr_handler generic_acl_access_handler = {
 205        .prefix = POSIX_ACL_XATTR_ACCESS,
 206        .flags  = ACL_TYPE_ACCESS,
 207        .list   = generic_acl_list,
 208        .get    = generic_acl_get,
 209        .set    = generic_acl_set,
 210};
 211
 212const struct xattr_handler generic_acl_default_handler = {
 213        .prefix = POSIX_ACL_XATTR_DEFAULT,
 214        .flags  = ACL_TYPE_DEFAULT,
 215        .list   = generic_acl_list,
 216        .get    = generic_acl_get,
 217        .set    = generic_acl_set,
 218};
 219
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.