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 31struct 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 switch (type) { 39 case ACL_TYPE_ACCESS: 40 name = POSIX_ACL_XATTR_ACCESS; 41 break; 42 case ACL_TYPE_DEFAULT: 43 name = POSIX_ACL_XATTR_DEFAULT; 44 break; 45 default: 46 BUG(); 47 } 48 49 size = __btrfs_getxattr(inode, name, "", 0); 50 if (size > 0) { 51 value = kzalloc(size, GFP_NOFS); 52 if (!value) 53 return ERR_PTR(-ENOMEM); 54 size = __btrfs_getxattr(inode, name, value, size); 55 } 56 if (size > 0) { 57 acl = posix_acl_from_xattr(&init_user_ns, value, size); 58 } else if (size == -ENOENT || size == -ENODATA || size == 0) { 59 /* FIXME, who returns -ENOENT? I think nobody */ 60 acl = NULL; 61 } else { 62 acl = ERR_PTR(-EIO); 63 } 64 kfree(value); 65 66 if (!IS_ERR(acl)) 67 set_cached_acl(inode, type, acl); 68 69 return acl; 70} 71 72/* 73 * Needs to be called with fs_mutex held 74 */ 75static int __btrfs_set_acl(struct btrfs_trans_handle *trans, 76 struct inode *inode, struct posix_acl *acl, int type) 77{ 78 int ret, size = 0; 79 const char *name; 80 char *value = NULL; 81 82 switch (type) { 83 case ACL_TYPE_ACCESS: 84 name = POSIX_ACL_XATTR_ACCESS; 85 if (acl) { 86 ret = posix_acl_equiv_mode(acl, &inode->i_mode); 87 if (ret < 0) 88 return ret; 89 if (ret == 0) 90 acl = NULL; 91 } 92 ret = 0; 93 break; 94 case ACL_TYPE_DEFAULT: 95 if (!S_ISDIR(inode->i_mode)) 96 return acl ? -EINVAL : 0; 97 name = POSIX_ACL_XATTR_DEFAULT; 98 break; 99 default: 100 return -EINVAL; 101 } 102 103 if (acl) { 104 size = posix_acl_xattr_size(acl->a_count); 105 value = kmalloc(size, GFP_NOFS); 106 if (!value) { 107 ret = -ENOMEM; 108 goto out; 109 } 110 111 ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 112 if (ret < 0) 113 goto out; 114 } 115 116 ret = __btrfs_setxattr(trans, inode, name, value, size, 0); 117out: 118 kfree(value); 119 120 if (!ret) 121 set_cached_acl(inode, type, acl); 122 123 return ret; 124} 125 126int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) 127{ 128 return __btrfs_set_acl(NULL, inode, acl, type); 129} 130 131/* 132 * btrfs_init_acl is already generally called under fs_mutex, so the locking 133 * stuff has been fixed to work with that. If the locking stuff changes, we 134 * need to re-evaluate the acl locking stuff. 135 */ 136int btrfs_init_acl(struct btrfs_trans_handle *trans, 137 struct inode *inode, struct inode *dir) 138{ 139 struct posix_acl *default_acl, *acl; 140 int ret = 0; 141 142 /* this happens with subvols */ 143 if (!dir) 144 return 0; 145 146 ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); 147 if (ret) 148 return ret; 149 150 if (default_acl) { 151 ret = __btrfs_set_acl(trans, inode, default_acl, 152 ACL_TYPE_DEFAULT); 153 posix_acl_release(default_acl); 154 } 155 156 if (acl) { 157 if (!ret) 158 ret = __btrfs_set_acl(trans, inode, acl, 159 ACL_TYPE_ACCESS); 160 posix_acl_release(acl); 161 } 162 163 if (!default_acl && !acl) 164 cache_no_acl(inode); 165 return ret; 166} 167