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(&init_user_ns, 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(&init_user_ns, 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 if (ret == 0) 125 acl = NULL; 126 } 127 ret = 0; 128 break; 129 case ACL_TYPE_DEFAULT: 130 if (!S_ISDIR(inode->i_mode)) 131 return acl ? -EINVAL : 0; 132 name = POSIX_ACL_XATTR_DEFAULT; 133 break; 134 default: 135 return -EINVAL; 136 } 137 138 if (acl) { 139 size = posix_acl_xattr_size(acl->a_count); 140 value = kmalloc(size, GFP_NOFS); 141 if (!value) { 142 ret = -ENOMEM; 143 goto out; 144 } 145 146 ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 147 if (ret < 0) 148 goto out; 149 } 150 151 ret = __btrfs_setxattr(trans, inode, name, value, size, 0); 152 out: 153 kfree(value); 154 155 if (!ret) 156 set_cached_acl(inode, type, acl); 157 158 return ret; 159 } 160 161 static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, 162 const void *value, size_t size, int flags, int type) 163 { 164 int ret; 165 struct posix_acl *acl = NULL; 166 167 if (!inode_owner_or_capable(dentry->d_inode)) 168 return -EPERM; 169 170 if (!IS_POSIXACL(dentry->d_inode)) 171 return -EOPNOTSUPP; 172 173 if (value) { 174 acl = posix_acl_from_xattr(&init_user_ns, value, size); 175 if (IS_ERR(acl)) 176 return PTR_ERR(acl); 177 178 if (acl) { 179 ret = posix_acl_valid(acl); 180 if (ret) 181 goto out; 182 } 183 } 184 185 ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type); 186 out: 187 posix_acl_release(acl); 188 189 return ret; 190 } 191 192 /* 193 * btrfs_init_acl is already generally called under fs_mutex, so the locking 194 * stuff has been fixed to work with that. If the locking stuff changes, we 195 * need to re-evaluate the acl locking stuff. 196 */ 197 int btrfs_init_acl(struct btrfs_trans_handle *trans, 198 struct inode *inode, struct inode *dir) 199 { 200 struct posix_acl *acl = NULL; 201 int ret = 0; 202 203 /* this happens with subvols */ 204 if (!dir) 205 return 0; 206 207 if (!S_ISLNK(inode->i_mode)) { 208 if (IS_POSIXACL(dir)) { 209 acl = btrfs_get_acl(dir, ACL_TYPE_DEFAULT); 210 if (IS_ERR(acl)) 211 return PTR_ERR(acl); 212 } 213 214 if (!acl) 215 inode->i_mode &= ~current_umask(); 216 } 217 218 if (IS_POSIXACL(dir) && acl) { 219 if (S_ISDIR(inode->i_mode)) { 220 ret = btrfs_set_acl(trans, inode, acl, 221 ACL_TYPE_DEFAULT); 222 if (ret) 223 goto failed; 224 } 225 ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); 226 if (ret < 0) 227 return ret; 228 229 if (ret > 0) { 230 /* we need an acl */ 231 ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS); 232 } else if (ret < 0) { 233 cache_no_acl(inode); 234 } 235 } else { 236 cache_no_acl(inode); 237 } 238 failed: 239 posix_acl_release(acl); 240 241 return ret; 242 } 243 244 int btrfs_acl_chmod(struct inode *inode) 245 { 246 struct posix_acl *acl; 247 int ret = 0; 248 249 if (S_ISLNK(inode->i_mode)) 250 return -EOPNOTSUPP; 251 252 if (!IS_POSIXACL(inode)) 253 return 0; 254 255 acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); 256 if (IS_ERR_OR_NULL(acl)) 257 return PTR_ERR(acl); 258 259 ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); 260 if (ret) 261 return ret; 262 ret = btrfs_set_acl(NULL, inode, acl, ACL_TYPE_ACCESS); 263 posix_acl_release(acl); 264 return ret; 265 } 266 267 const struct xattr_handler btrfs_xattr_acl_default_handler = { 268 .prefix = POSIX_ACL_XATTR_DEFAULT, 269 .flags = ACL_TYPE_DEFAULT, 270 .get = btrfs_xattr_acl_get, 271 .set = btrfs_xattr_acl_set, 272 }; 273 274 const struct xattr_handler btrfs_xattr_acl_access_handler = { 275 .prefix = POSIX_ACL_XATTR_ACCESS, 276 .flags = ACL_TYPE_ACCESS, 277 .get = btrfs_xattr_acl_get, 278 .set = btrfs_xattr_acl_set, 279 }; 280