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