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 26 #include "ctree.h" 27 #include "btrfs_inode.h" 28 #include "xattr.h" 29 30 #ifdef CONFIG_FS_POSIX_ACL 31 32 static void btrfs_update_cached_acl(struct inode *inode, 33 struct posix_acl **p_acl, 34 struct posix_acl *acl) 35 { 36 spin_lock(&inode->i_lock); 37 if (*p_acl && *p_acl != BTRFS_ACL_NOT_CACHED) 38 posix_acl_release(*p_acl); 39 *p_acl = posix_acl_dup(acl); 40 spin_unlock(&inode->i_lock); 41 } 42 43 static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) 44 { 45 int size; 46 const char *name; 47 char *value = NULL; 48 struct posix_acl *acl = NULL, **p_acl; 49 50 switch (type) { 51 case ACL_TYPE_ACCESS: 52 name = POSIX_ACL_XATTR_ACCESS; 53 p_acl = &BTRFS_I(inode)->i_acl; 54 break; 55 case ACL_TYPE_DEFAULT: 56 name = POSIX_ACL_XATTR_DEFAULT; 57 p_acl = &BTRFS_I(inode)->i_default_acl; 58 break; 59 default: 60 return ERR_PTR(-EINVAL); 61 } 62 63 spin_lock(&inode->i_lock); 64 if (*p_acl != BTRFS_ACL_NOT_CACHED) 65 acl = posix_acl_dup(*p_acl); 66 spin_unlock(&inode->i_lock); 67 68 if (acl) 69 return acl; 70 71 72 size = __btrfs_getxattr(inode, name, "", 0); 73 if (size > 0) { 74 value = kzalloc(size, GFP_NOFS); 75 if (!value) 76 return ERR_PTR(-ENOMEM); 77 size = __btrfs_getxattr(inode, name, value, size); 78 if (size > 0) { 79 acl = posix_acl_from_xattr(value, size); 80 btrfs_update_cached_acl(inode, p_acl, acl); 81 } 82 kfree(value); 83 } else if (size == -ENOENT) { 84 acl = NULL; 85 btrfs_update_cached_acl(inode, p_acl, acl); 86 } 87 88 return acl; 89 } 90 91 static int btrfs_xattr_get_acl(struct inode *inode, int type, 92 void *value, size_t size) 93 { 94 struct posix_acl *acl; 95 int ret = 0; 96 97 acl = btrfs_get_acl(inode, type); 98 99 if (IS_ERR(acl)) 100 return PTR_ERR(acl); 101 if (acl == NULL) 102 return -ENODATA; 103 ret = posix_acl_to_xattr(acl, value, size); 104 posix_acl_release(acl); 105 106 return ret; 107 } 108 109 /* 110 * Needs to be called with fs_mutex held 111 */ 112 static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) 113 { 114 int ret, size = 0; 115 const char *name; 116 struct posix_acl **p_acl; 117 char *value = NULL; 118 mode_t mode; 119 120 if (acl) { 121 ret = posix_acl_valid(acl); 122 if (ret < 0) 123 return ret; 124 ret = 0; 125 } 126 127 switch (type) { 128 case ACL_TYPE_ACCESS: 129 mode = inode->i_mode; 130 ret = posix_acl_equiv_mode(acl, &mode); 131 if (ret < 0) 132 return ret; 133 ret = 0; 134 inode->i_mode = mode; 135 name = POSIX_ACL_XATTR_ACCESS; 136 p_acl = &BTRFS_I(inode)->i_acl; 137 break; 138 case ACL_TYPE_DEFAULT: 139 if (!S_ISDIR(inode->i_mode)) 140 return acl ? -EINVAL : 0; 141 name = POSIX_ACL_XATTR_DEFAULT; 142 p_acl = &BTRFS_I(inode)->i_default_acl; 143 break; 144 default: 145 return -EINVAL; 146 } 147 148 if (acl) { 149 size = posix_acl_xattr_size(acl->a_count); 150 value = kmalloc(size, GFP_NOFS); 151 if (!value) { 152 ret = -ENOMEM; 153 goto out; 154 } 155 156 ret = posix_acl_to_xattr(acl, value, size); 157 if (ret < 0) 158 goto out; 159 } 160 161 ret = __btrfs_setxattr(inode, name, value, size, 0); 162 163 out: 164 kfree(value); 165 166 if (!ret) 167 btrfs_update_cached_acl(inode, p_acl, acl); 168 169 return ret; 170 } 171 172 static int btrfs_xattr_set_acl(struct inode *inode, int type, 173 const void *value, size_t size) 174 { 175 int ret = 0; 176 struct posix_acl *acl = NULL; 177 178 if (value) { 179 acl = posix_acl_from_xattr(value, size); 180 if (acl == NULL) { 181 value = NULL; 182 size = 0; 183 } else if (IS_ERR(acl)) { 184 return PTR_ERR(acl); 185 } 186 } 187 188 ret = btrfs_set_acl(inode, acl, type); 189 190 posix_acl_release(acl); 191 192 return ret; 193 } 194 195 196 static int btrfs_xattr_acl_access_get(struct inode *inode, const char *name, 197 void *value, size_t size) 198 { 199 return btrfs_xattr_get_acl(inode, ACL_TYPE_ACCESS, value, size); 200 } 201 202 static int btrfs_xattr_acl_access_set(struct inode *inode, const char *name, 203 const void *value, size_t size, int flags) 204 { 205 return btrfs_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); 206 } 207 208 static int btrfs_xattr_acl_default_get(struct inode *inode, const char *name, 209 void *value, size_t size) 210 { 211 return btrfs_xattr_get_acl(inode, ACL_TYPE_DEFAULT, value, size); 212 } 213 214 static int btrfs_xattr_acl_default_set(struct inode *inode, const char *name, 215 const void *value, size_t size, int flags) 216 { 217 return btrfs_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); 218 } 219 220 int btrfs_check_acl(struct inode *inode, int mask) 221 { 222 struct posix_acl *acl; 223 int error = -EAGAIN; 224 225 acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); 226 227 if (IS_ERR(acl)) 228 return PTR_ERR(acl); 229 if (acl) { 230 error = posix_acl_permission(inode, acl, mask); 231 posix_acl_release(acl); 232 } 233 234 return error; 235 } 236 237 /* 238 * btrfs_init_acl is already generally called under fs_mutex, so the locking 239 * stuff has been fixed to work with that. If the locking stuff changes, we 240 * need to re-evaluate the acl locking stuff. 241 */ 242 int btrfs_init_acl(struct inode *inode, struct inode *dir) 243 { 244 struct posix_acl *acl = NULL; 245 int ret = 0; 246 247 /* this happens with subvols */ 248 if (!dir) 249 return 0; 250 251 if (!S_ISLNK(inode->i_mode)) { 252 if (IS_POSIXACL(dir)) { 253 acl = btrfs_get_acl(dir, ACL_TYPE_DEFAULT); 254 if (IS_ERR(acl)) 255 return PTR_ERR(acl); 256 } 257 258 if (!acl) 259 inode->i_mode &= ~current->fs->umask; 260 } 261 262 if (IS_POSIXACL(dir) && acl) { 263 struct posix_acl *clone; 264 mode_t mode; 265 266 if (S_ISDIR(inode->i_mode)) { 267 ret = btrfs_set_acl(inode, acl, ACL_TYPE_DEFAULT); 268 if (ret) 269 goto failed; 270 } 271 clone = posix_acl_clone(acl, GFP_NOFS); 272 ret = -ENOMEM; 273 if (!clone) 274 goto failed; 275 276 mode = inode->i_mode; 277 ret = posix_acl_create_masq(clone, &mode); 278 if (ret >= 0) { 279 inode->i_mode = mode; 280 if (ret > 0) { 281 /* we need an acl */ 282 ret = btrfs_set_acl(inode, clone, 283 ACL_TYPE_ACCESS); 284 } 285 } 286 } 287 failed: 288 posix_acl_release(acl); 289 290 return ret; 291 } 292 293 int btrfs_acl_chmod(struct inode *inode) 294 { 295 struct posix_acl *acl, *clone; 296 int ret = 0; 297 298 if (S_ISLNK(inode->i_mode)) 299 return -EOPNOTSUPP; 300 301 if (!IS_POSIXACL(inode)) 302 return 0; 303 304 acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); 305 if (IS_ERR(acl) || !acl) 306 return PTR_ERR(acl); 307 308 clone = posix_acl_clone(acl, GFP_KERNEL); 309 posix_acl_release(acl); 310 if (!clone) 311 return -ENOMEM; 312 313 ret = posix_acl_chmod_masq(clone, inode->i_mode); 314 if (!ret) 315 ret = btrfs_set_acl(inode, clone, ACL_TYPE_ACCESS); 316 317 posix_acl_release(clone); 318 319 return ret; 320 } 321 322 struct xattr_handler btrfs_xattr_acl_default_handler = { 323 .prefix = POSIX_ACL_XATTR_DEFAULT, 324 .get = btrfs_xattr_acl_default_get, 325 .set = btrfs_xattr_acl_default_set, 326 }; 327 328 struct xattr_handler btrfs_xattr_acl_access_handler = { 329 .prefix = POSIX_ACL_XATTR_ACCESS, 330 .get = btrfs_xattr_acl_access_get, 331 .set = btrfs_xattr_acl_access_set, 332 }; 333 334 #else /* CONFIG_FS_POSIX_ACL */ 335 336 int btrfs_acl_chmod(struct inode *inode) 337 { 338 return 0; 339 } 340 341 int btrfs_init_acl(struct inode *inode, struct inode *dir) 342 { 343 return 0; 344 } 345 346 int btrfs_check_acl(struct inode *inode, int mask) 347 { 348 return 0; 349 } 350 351 #endif /* CONFIG_FS_POSIX_ACL */ 352