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 switch (type) { 39 case ACL_TYPE_ACCESS: 40 name = XATTR_NAME_POSIX_ACL_ACCESS; 41 break; 42 case ACL_TYPE_DEFAULT: 43 name = XATTR_NAME_POSIX_ACL_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_KERNEL); 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 == -ERANGE || size == -ENODATA || size == 0) { 59 acl = NULL; 60 } else { 61 acl = ERR_PTR(-EIO); 62 } 63 kfree(value); 64 65 return acl; 66 } 67 68 static int __btrfs_set_acl(struct btrfs_trans_handle *trans, 69 struct inode *inode, struct posix_acl *acl, int type) 70 { 71 int ret, size = 0; 72 const char *name; 73 char *value = NULL; 74 75 switch (type) { 76 case ACL_TYPE_ACCESS: 77 name = XATTR_NAME_POSIX_ACL_ACCESS; 78 break; 79 case ACL_TYPE_DEFAULT: 80 if (!S_ISDIR(inode->i_mode)) 81 return acl ? -EINVAL : 0; 82 name = XATTR_NAME_POSIX_ACL_DEFAULT; 83 break; 84 default: 85 return -EINVAL; 86 } 87 88 if (acl) { 89 size = posix_acl_xattr_size(acl->a_count); 90 value = kmalloc(size, GFP_KERNEL); 91 if (!value) { 92 ret = -ENOMEM; 93 goto out; 94 } 95 96 ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 97 if (ret < 0) 98 goto out; 99 } 100 101 ret = btrfs_setxattr(trans, inode, name, value, size, 0); 102 out: 103 kfree(value); 104 105 if (!ret) 106 set_cached_acl(inode, type, acl); 107 108 return ret; 109 } 110 111 int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) 112 { 113 int ret; 114 umode_t old_mode = inode->i_mode; 115 116 if (type == ACL_TYPE_ACCESS && acl) { 117 ret = posix_acl_update_mode(inode, &inode->i_mode, &acl); 118 if (ret) 119 return ret; 120 } 121 ret = __btrfs_set_acl(NULL, inode, acl, type); 122 if (ret) 123 inode->i_mode = old_mode; 124 return ret; 125 } 126 127 int btrfs_init_acl(struct btrfs_trans_handle *trans, 128 struct inode *inode, struct inode *dir) 129 { 130 struct posix_acl *default_acl, *acl; 131 int ret = 0; 132 133 /* this happens with subvols */ 134 if (!dir) 135 return 0; 136 137 ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); 138 if (ret) 139 return ret; 140 141 if (default_acl) { 142 ret = __btrfs_set_acl(trans, inode, default_acl, 143 ACL_TYPE_DEFAULT); 144 posix_acl_release(default_acl); 145 } 146 147 if (acl) { 148 if (!ret) 149 ret = __btrfs_set_acl(trans, inode, acl, 150 ACL_TYPE_ACCESS); 151 posix_acl_release(acl); 152 } 153 154 if (!default_acl && !acl) 155 cache_no_acl(inode); 156 return ret; 157 } 158