linux/fs/jfs/acl.c
<<
>>
Prefs
   1/*
   2 *   Copyright (C) International Business Machines  Corp., 2002-2004
   3 *   Copyright (C) Andreas Gruenbacher, 2001
   4 *   Copyright (C) Linus Torvalds, 1991, 1992
   5 *
   6 *   This program is free software;  you can redistribute it and/or modify
   7 *   it under the terms of the GNU General Public License as published by
   8 *   the Free Software Foundation; either version 2 of the License, or
   9 *   (at your option) any later version.
  10 *
  11 *   This program is distributed in the hope that it will be useful,
  12 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
  13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  14 *   the GNU General Public License for more details.
  15 *
  16 *   You should have received a copy of the GNU General Public License
  17 *   along with this program;  if not, write to the Free Software
  18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 */
  20
  21#include <linux/sched.h>
  22#include <linux/fs.h>
  23#include <linux/quotaops.h>
  24#include <linux/posix_acl_xattr.h>
  25#include "jfs_incore.h"
  26#include "jfs_txnmgr.h"
  27#include "jfs_xattr.h"
  28#include "jfs_acl.h"
  29
  30static struct posix_acl *jfs_get_acl(struct inode *inode, int type)
  31{
  32        struct posix_acl *acl;
  33        char *ea_name;
  34        int size;
  35        char *value = NULL;
  36
  37        acl = get_cached_acl(inode, type);
  38        if (acl != ACL_NOT_CACHED)
  39                return acl;
  40
  41        switch(type) {
  42                case ACL_TYPE_ACCESS:
  43                        ea_name = POSIX_ACL_XATTR_ACCESS;
  44                        break;
  45                case ACL_TYPE_DEFAULT:
  46                        ea_name = POSIX_ACL_XATTR_DEFAULT;
  47                        break;
  48                default:
  49                        return ERR_PTR(-EINVAL);
  50        }
  51
  52        size = __jfs_getxattr(inode, ea_name, NULL, 0);
  53
  54        if (size > 0) {
  55                value = kmalloc(size, GFP_KERNEL);
  56                if (!value)
  57                        return ERR_PTR(-ENOMEM);
  58                size = __jfs_getxattr(inode, ea_name, value, size);
  59        }
  60
  61        if (size < 0) {
  62                if (size == -ENODATA)
  63                        acl = NULL;
  64                else
  65                        acl = ERR_PTR(size);
  66        } else {
  67                acl = posix_acl_from_xattr(value, size);
  68        }
  69        kfree(value);
  70        if (!IS_ERR(acl))
  71                set_cached_acl(inode, type, acl);
  72        return acl;
  73}
  74
  75static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
  76                       struct posix_acl *acl)
  77{
  78        char *ea_name;
  79        int rc;
  80        int size = 0;
  81        char *value = NULL;
  82
  83        if (S_ISLNK(inode->i_mode))
  84                return -EOPNOTSUPP;
  85
  86        switch(type) {
  87                case ACL_TYPE_ACCESS:
  88                        ea_name = POSIX_ACL_XATTR_ACCESS;
  89                        break;
  90                case ACL_TYPE_DEFAULT:
  91                        ea_name = POSIX_ACL_XATTR_DEFAULT;
  92                        if (!S_ISDIR(inode->i_mode))
  93                                return acl ? -EACCES : 0;
  94                        break;
  95                default:
  96                        return -EINVAL;
  97        }
  98        if (acl) {
  99                size = posix_acl_xattr_size(acl->a_count);
 100                value = kmalloc(size, GFP_KERNEL);
 101                if (!value)
 102                        return -ENOMEM;
 103                rc = posix_acl_to_xattr(acl, value, size);
 104                if (rc < 0)
 105                        goto out;
 106        }
 107        rc = __jfs_setxattr(tid, inode, ea_name, value, size, 0);
 108out:
 109        kfree(value);
 110
 111        if (!rc)
 112                set_cached_acl(inode, type, acl);
 113
 114        return rc;
 115}
 116
 117int jfs_check_acl(struct inode *inode, int mask)
 118{
 119        struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
 120
 121        if (IS_ERR(acl))
 122                return PTR_ERR(acl);
 123        if (acl) {
 124                int error = posix_acl_permission(inode, acl, mask);
 125                posix_acl_release(acl);
 126                return error;
 127        }
 128
 129        return -EAGAIN;
 130}
 131
 132int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
 133{
 134        struct posix_acl *acl = NULL;
 135        struct posix_acl *clone;
 136        mode_t mode;
 137        int rc = 0;
 138
 139        if (S_ISLNK(inode->i_mode))
 140                return 0;
 141
 142        acl = jfs_get_acl(dir, ACL_TYPE_DEFAULT);
 143        if (IS_ERR(acl))
 144                return PTR_ERR(acl);
 145
 146        if (acl) {
 147                if (S_ISDIR(inode->i_mode)) {
 148                        rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl);
 149                        if (rc)
 150                                goto cleanup;
 151                }
 152                clone = posix_acl_clone(acl, GFP_KERNEL);
 153                if (!clone) {
 154                        rc = -ENOMEM;
 155                        goto cleanup;
 156                }
 157                mode = inode->i_mode;
 158                rc = posix_acl_create_masq(clone, &mode);
 159                if (rc >= 0) {
 160                        inode->i_mode = mode;
 161                        if (rc > 0)
 162                                rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS,
 163                                                 clone);
 164                }
 165                posix_acl_release(clone);
 166cleanup:
 167                posix_acl_release(acl);
 168        } else
 169                inode->i_mode &= ~current_umask();
 170
 171        JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
 172                               inode->i_mode;
 173
 174        return rc;
 175}
 176
 177static int jfs_acl_chmod(struct inode *inode)
 178{
 179        struct posix_acl *acl, *clone;
 180        int rc;
 181
 182        if (S_ISLNK(inode->i_mode))
 183                return -EOPNOTSUPP;
 184
 185        acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
 186        if (IS_ERR(acl) || !acl)
 187                return PTR_ERR(acl);
 188
 189        clone = posix_acl_clone(acl, GFP_KERNEL);
 190        posix_acl_release(acl);
 191        if (!clone)
 192                return -ENOMEM;
 193
 194        rc = posix_acl_chmod_masq(clone, inode->i_mode);
 195        if (!rc) {
 196                tid_t tid = txBegin(inode->i_sb, 0);
 197                mutex_lock(&JFS_IP(inode)->commit_mutex);
 198                rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, clone);
 199                if (!rc)
 200                        rc = txCommit(tid, 1, &inode, 0);
 201                txEnd(tid);
 202                mutex_unlock(&JFS_IP(inode)->commit_mutex);
 203        }
 204
 205        posix_acl_release(clone);
 206        return rc;
 207}
 208
 209int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
 210{
 211        struct inode *inode = dentry->d_inode;
 212        int rc;
 213
 214        rc = inode_change_ok(inode, iattr);
 215        if (rc)
 216                return rc;
 217
 218        if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
 219            (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
 220                if (vfs_dq_transfer(inode, iattr))
 221                        return -EDQUOT;
 222        }
 223
 224        rc = inode_setattr(inode, iattr);
 225
 226        if (!rc && (iattr->ia_valid & ATTR_MODE))
 227                rc = jfs_acl_chmod(inode);
 228
 229        return rc;
 230}
 231