1 /* 2 * Copyright (C) 2007 Red Hat. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public 6 * License v2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public 14 * License along with this program; if not, write to the 15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 16 * Boston, MA 021110-1307, USA. 17 */ 18 19 #include <linux/fs.h> 20 #include <linux/string.h> 21 #include <linux/xattr.h> 22 #include <linux/posix_acl_xattr.h> 23 #include <linux/posix_acl.h> 24 #include <linux/sched.h> 25 #include <linux/slab.h> 26 27 #include "ctree.h" 28 #include "btrfs_inode.h" 29 #include "xattr.h" 30 31 struct posix_acl *btrfs_get_acl(struct inode *inode, int type) 32 { 33 int size; 34 const char *name; 35 char *value = NULL; 36 struct posix_acl *acl; 37 38 if (!IS_POSIXACL(inode)) 39 return NULL; 40 41 acl = get_cached_acl(inode, type); 42 if (acl != ACL_NOT_CACHED) 43 return acl; 44 45 switch (type) { 46 case ACL_TYPE_ACCESS: 47 name = POSIX_ACL_XATTR_ACCESS; 48 break; 49 case ACL_TYPE_DEFAULT: 50 name = POSIX_ACL_XATTR_DEFAULT; 51 break; 52 default: 53 BUG(); 54 } 55 56 size = __btrfs_getxattr(inode, name, "", 0); 57 if (size > 0) { 58 value = kzalloc(size, GFP_NOFS); 59 if (!value) 60 return ERR_PTR(-ENOMEM); 61 size = __btrfs_getxattr(inode, name, value, size); 62 } 63 if (size > 0) { 64 acl = posix_acl_from_xattr(value, size); 65 } else if (size == -ENOENT || size == -ENODATA || size == 0) { 66 /* FIXME, who returns -ENOENT? I think nobody */ 67 acl = NULL; 68 } else { 69 acl = ERR_PTR(-EIO); 70 } 71 kfree(value); 72 73 if (!IS_ERR(acl)) 74 set_cached_acl(inode, type, acl); 75 76 return acl; 77 } 78 79 static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name, 80 void *value, size_t size, int type) 81 { 82 struct posix_acl *acl; 83 int ret = 0; 84 85 if (!IS_POSIXACL(dentry->d_inode)) 86 return -EOPNOTSUPP; 87 88 acl = btrfs_get_acl(dentry->d_inode, type); 89 90 if (IS_ERR(acl)) 91 return PTR_ERR(acl); 92 if (acl == NULL) 93 return -ENODATA; 94 ret = posix_acl_to_xattr(acl, value, size); 95 posix_acl_release(acl); 96 97 return ret; 98 } 99 100 /* 101 * Needs to be called with fs_mutex held 102 */ 103 static int btrfs_set_acl(struct btrfs_trans_handle *trans, 104 struct inode *inode, struct posix_acl *acl, int type) 105 { 106 int ret, size = 0; 107 const char *name; 108 char *value = NULL; 109 110 if (acl) { 111 ret = posix_acl_valid(acl); 112 if (ret < 0) 113 return ret; 114 ret = 0; 115 } 116 117 switch (type) { 118 case ACL_TYPE_ACCESS: 119 name = POSIX_ACL_XATTR_ACCESS; 120 if (acl) { 121 ret = posix_acl_equiv_mode(acl, &inode->i_mode); 122 if (ret < 0) 123 return ret; 124 } 125 ret = 0; 126 break; 127 case ACL_TYPE_DEFAULT: 128 if (!S_ISDIR(inode->i_mode)) 129 return acl ? -EINVAL : 0; 130 name = POSIX_ACL_XATTR_DEFAULT; 131 break; 132 default: 133 return -EINVAL; 134 } 135 136 if (acl) { 137 size = posix_acl_xattr_size(acl->a_count); 138 value = kmalloc(size, GFP_NOFS); 139 if (!value) { 140 ret = -ENOMEM; 141 goto out; 142 } 143 144 ret = posix_acl_to_xattr(acl, value, size); 145 if (ret < 0) 146 goto out; 147 } 148 149 ret = __btrfs_setxattr(trans, inode, name, value, size, 0); 150 out: 151 kfree(value); 152 153 if (!ret) 154 set_cached_acl(inode, type, acl); 155 156 return ret; 157 } 158 159 static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, 160 const void *value, size_t size, int flags, int type) 161 { 162 int ret; 163 struct posix_acl *acl = NULL; 164 165 if (!inode_owner_or_capable(dentry->d_inode)) 166 return -EPERM; 167 168 if (!IS_POSIXACL(dentry->d_inode)) 169 return -EOPNOTSUPP; 170 171 if (value) { 172 acl = posix_acl_from_xattr(value, size); 173 if (IS_ERR(acl)) 174 return PTR_ERR(acl); 175 176 if (acl) { 177 ret = posix_acl_valid(acl); 178 if (ret) 179 goto out; 180 } 181 } 182 183 ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type); 184 out: 185 posix_acl_release(acl); 186 187 return ret; 188 } 189 190 /* 191 * btrfs_init_acl is already generally called under fs_mutex, so the locking 192 * stuff has been fixed to work with that. If the locking stuff changes, we 193 * need to re-evaluate the acl locking stuff. 194 */ 195 int btrfs_init_acl(struct btrfs_trans_handle *trans, 196 struct inode *inode, struct inode *dir) 197 { 198 struct posix_acl *acl = NULL; 199 int ret = 0; 200 201 /* this happens with subvols */ 202 if (!dir) 203 return 0; 204 205 if (!S_ISLNK(inode->i_mode)) { 206 if (IS_POSIXACL(dir)) { 207 acl = btrfs_get_acl(dir, ACL_TYPE_DEFAULT); 208 if (IS_ERR(acl)) 209 return PTR_ERR(acl); 210 } 211 212 if (!acl) 213 inode->i_mode &= ~current_umask(); 214 } 215 216 if (IS_POSIXACL(dir) && acl) { 217 if (S_ISDIR(inode->i_mode)) { 218 ret = btrfs_set_acl(trans, inode, acl, 219 ACL_TYPE_DEFAULT); 220 if (ret) 221 goto failed; 222 } 223 ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); 224 if (ret < 0) 225 return ret; 226 227 if (ret > 0) { 228 /* we need an acl */ 229 ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS); 230 } else { 231 cache_no_acl(inode); 232 } 233 } else { 234 cache_no_acl(inode); 235 } 236 failed: 237 posix_acl_release(acl); 238 239 return ret; 240 } 241 242 int btrfs_acl_chmod(struct inode *inode) 243 { 244 struct posix_acl *acl; 245 int ret = 0; 246 247 if (S_ISLNK(inode->i_mode)) 248 return -EOPNOTSUPP; 249 250 if (!IS_POSIXACL(inode)) 251 return 0; 252 253 acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); 254 if (IS_ERR_OR_NULL(acl)) 255 return PTR_ERR(acl); 256 257 ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); 258 if (ret) 259 return ret; 260 ret = btrfs_set_acl(NULL, inode, acl, ACL_TYPE_ACCESS); 261 posix_acl_release(acl); 262 return ret; 263 } 264 265 const struct xattr_handler btrfs_xattr_acl_default_handler = { 266 .prefix = POSIX_ACL_XATTR_DEFAULT, 267 .flags = ACL_TYPE_DEFAULT, 268 .get = btrfs_xattr_acl_get, 269 .set = btrfs_xattr_acl_set, 270 }; 271 272 const struct xattr_handler btrfs_xattr_acl_access_handler = { 273 .prefix = POSIX_ACL_XATTR_ACCESS, 274 .flags = ACL_TYPE_ACCESS, 275 .get = btrfs_xattr_acl_get, 276 .set = btrfs_xattr_acl_set, 277 }; 278