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        struct jfs_inode_info *ji = JFS_IP(inode);
  35        struct posix_acl **p_acl;
  36        int size;
  37        char *value = NULL;
  38
  39        switch(type) {
  40                case ACL_TYPE_ACCESS:
  41                        ea_name = POSIX_ACL_XATTR_ACCESS;
  42                        p_acl = &ji->i_acl;
  43                        break;
  44                case ACL_TYPE_DEFAULT:
  45                        ea_name = POSIX_ACL_XATTR_DEFAULT;
  46                        p_acl = &ji->i_default_acl;
  47                        break;
  48                default:
  49                        return ERR_PTR(-EINVAL);
  50        }
  51
  52        if (*p_acl != JFS_ACL_NOT_CACHED)
  53                return posix_acl_dup(*p_acl);
  54
  55        size = __jfs_getxattr(inode, ea_name, NULL, 0);
  56
  57        if (size > 0) {
  58                value = kmalloc(size, GFP_KERNEL);
  59                if (!value)
  60                        return ERR_PTR(-ENOMEM);
  61                size = __jfs_getxattr(inode, ea_name, value, size);
  62        }
  63
  64        if (size < 0) {
  65                if (size == -ENODATA) {
  66                        *p_acl = NULL;
  67                        acl = NULL;
  68                } else
  69                        acl = ERR_PTR(size);
  70        } else {
  71                acl = posix_acl_from_xattr(value, size);
  72                if (!IS_ERR(acl))
  73                        *p_acl = posix_acl_dup(acl);
  74        }
  75        kfree(value);
  76        return acl;
  77}
  78
  79static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
  80                       struct posix_acl *acl)
  81{
  82        char *ea_name;
  83        struct jfs_inode_info *ji = JFS_IP(inode);
  84        struct posix_acl **p_acl;
  85        int rc;
  86        int size = 0;
  87        char *value = NULL;
  88
  89        if (S_ISLNK(inode->i_mode))
  90                return -EOPNOTSUPP;
  91
  92        switch(type) {
  93                case ACL_TYPE_ACCESS:
  94                        ea_name = POSIX_ACL_XATTR_ACCESS;
  95                        p_acl = &ji->i_acl;
  96                        break;
  97                case ACL_TYPE_DEFAULT:
  98                        ea_name = POSIX_ACL_XATTR_DEFAULT;
  99                        p_acl = &ji->i_default_acl;
 100                        if (!S_ISDIR(inode->i_mode))
 101                                return acl ? -EACCES : 0;
 102                        break;
 103                default:
 104                        return -EINVAL;
 105        }
 106        if (acl) {
 107                size = posix_acl_xattr_size(acl->a_count);
 108                value = kmalloc(size, GFP_KERNEL);
 109                if (!value)
 110                        return -ENOMEM;
 111                rc = posix_acl_to_xattr(acl, value, size);
 112                if (rc < 0)
 113                        goto out;
 114        }
 115        rc = __jfs_setxattr(tid, inode, ea_name, value, size, 0);
 116out:
 117        kfree(value);
 118
 119        if (!rc) {
 120                if (*p_acl && (*p_acl != JFS_ACL_NOT_CACHED))
 121                        posix_acl_release(*p_acl);
 122                *p_acl = posix_acl_dup(acl);
 123        }
 124        return rc;
 125}
 126
 127static int jfs_check_acl(struct inode *inode, int mask)
 128{
 129        struct jfs_inode_info *ji = JFS_IP(inode);
 130
 131        if (ji->i_acl == JFS_ACL_NOT_CACHED) {
 132                struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
 133                if (IS_ERR(acl))
 134                        return PTR_ERR(acl);
 135                posix_acl_release(acl);
 136        }
 137
 138        if (ji->i_acl)
 139                return posix_acl_permission(inode, ji->i_acl, mask);
 140        return -EAGAIN;
 141}
 142
 143int jfs_permission(struct inode *inode, int mask, struct nameidata *nd)
 144{
 145        return generic_permission(inode, mask, jfs_check_acl);
 146}
 147
 148int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
 149{
 150        struct posix_acl *acl = NULL;
 151        struct posix_acl *clone;
 152        mode_t mode;
 153        int rc = 0;
 154
 155        if (S_ISLNK(inode->i_mode))
 156                return 0;
 157
 158        acl = jfs_get_acl(dir, ACL_TYPE_DEFAULT);
 159        if (IS_ERR(acl))
 160                return PTR_ERR(acl);
 161
 162        if (acl) {
 163                if (S_ISDIR(inode->i_mode)) {
 164                        rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl);
 165                        if (rc)
 166                                goto cleanup;
 167                }
 168                clone = posix_acl_clone(acl, GFP_KERNEL);
 169                if (!clone) {
 170                        rc = -ENOMEM;
 171                        goto cleanup;
 172                }
 173                mode = inode->i_mode;
 174                rc = posix_acl_create_masq(clone, &mode);
 175                if (rc >= 0) {
 176                        inode->i_mode = mode;
 177                        if (rc > 0)
 178                                rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS,
 179                                                 clone);
 180                }
 181                posix_acl_release(clone);
 182cleanup:
 183                posix_acl_release(acl);
 184        } else
 185                inode->i_mode &= ~current->fs->umask;
 186
 187        JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
 188                               inode->i_mode;
 189
 190        return rc;
 191}
 192
 193static int jfs_acl_chmod(struct inode *inode)
 194{
 195        struct posix_acl *acl, *clone;
 196        int rc;
 197
 198        if (S_ISLNK(inode->i_mode))
 199                return -EOPNOTSUPP;
 200
 201        acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
 202        if (IS_ERR(acl) || !acl)
 203                return PTR_ERR(acl);
 204
 205        clone = posix_acl_clone(acl, GFP_KERNEL);
 206        posix_acl_release(acl);
 207        if (!clone)
 208                return -ENOMEM;
 209
 210        rc = posix_acl_chmod_masq(clone, inode->i_mode);
 211        if (!rc) {
 212                tid_t tid = txBegin(inode->i_sb, 0);
 213                mutex_lock(&JFS_IP(inode)->commit_mutex);
 214                rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, clone);
 215                if (!rc)
 216                        rc = txCommit(tid, 1, &inode, 0);
 217                txEnd(tid);
 218                mutex_unlock(&JFS_IP(inode)->commit_mutex);
 219        }
 220
 221        posix_acl_release(clone);
 222        return rc;
 223}
 224
 225int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
 226{
 227        struct inode *inode = dentry->d_inode;
 228        int rc;
 229
 230        rc = inode_change_ok(inode, iattr);
 231        if (rc)
 232                return rc;
 233
 234        if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
 235            (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
 236                if (DQUOT_TRANSFER(inode, iattr))
 237                        return -EDQUOT;
 238        }
 239
 240        rc = inode_setattr(inode, iattr);
 241
 242        if (!rc && (iattr->ia_valid & ATTR_MODE))
 243                rc = jfs_acl_chmod(inode);
 244
 245        return rc;
 246}
 247