1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2007 Red Hat. All rights reserved. 4 */ 5 6 #include <linux/fs.h> 7 #include <linux/string.h> 8 #include <linux/xattr.h> 9 #include <linux/posix_acl_xattr.h> 10 #include <linux/posix_acl.h> 11 #include <linux/sched.h> 12 #include <linux/slab.h> 13 14 #include "ctree.h" 15 #include "btrfs_inode.h" 16 #include "xattr.h" 17 18 struct posix_acl *btrfs_get_acl(struct inode *inode, int type) 19 { 20 int size; 21 const char *name; 22 char *value = NULL; 23 struct posix_acl *acl; 24 25 switch (type) { 26 case ACL_TYPE_ACCESS: 27 name = XATTR_NAME_POSIX_ACL_ACCESS; 28 break; 29 case ACL_TYPE_DEFAULT: 30 name = XATTR_NAME_POSIX_ACL_DEFAULT; 31 break; 32 default: 33 BUG(); 34 } 35 36 size = btrfs_getxattr(inode, name, "", 0); 37 if (size > 0) { 38 value = kzalloc(size, GFP_KERNEL); 39 if (!value) 40 return ERR_PTR(-ENOMEM); 41 size = btrfs_getxattr(inode, name, value, size); 42 } 43 if (size > 0) { 44 acl = posix_acl_from_xattr(&init_user_ns, value, size); 45 } else if (size == -ERANGE || size == -ENODATA || size == 0) { 46 acl = NULL; 47 } else { 48 acl = ERR_PTR(-EIO); 49 } 50 kfree(value); 51 52 return acl; 53 } 54 55 static int __btrfs_set_acl(struct btrfs_trans_handle *trans, 56 struct inode *inode, struct posix_acl *acl, int type) 57 { 58 int ret, size = 0; 59 const char *name; 60 char *value = NULL; 61 62 switch (type) { 63 case ACL_TYPE_ACCESS: 64 name = XATTR_NAME_POSIX_ACL_ACCESS; 65 break; 66 case ACL_TYPE_DEFAULT: 67 if (!S_ISDIR(inode->i_mode)) 68 return acl ? -EINVAL : 0; 69 name = XATTR_NAME_POSIX_ACL_DEFAULT; 70 break; 71 default: 72 return -EINVAL; 73 } 74 75 if (acl) { 76 size = posix_acl_xattr_size(acl->a_count); 77 value = kmalloc(size, GFP_KERNEL); 78 if (!value) { 79 ret = -ENOMEM; 80 goto out; 81 } 82 83 ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 84 if (ret < 0) 85 goto out; 86 } 87 88 ret = btrfs_setxattr(trans, inode, name, value, size, 0); 89 out: 90 kfree(value); 91 92 if (!ret) 93 set_cached_acl(inode, type, acl); 94 95 return ret; 96 } 97 98 int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) 99 { 100 int ret; 101 umode_t old_mode = inode->i_mode; 102 103 if (type == ACL_TYPE_ACCESS && acl) { 104 ret = posix_acl_update_mode(inode, &inode->i_mode, &acl); 105 if (ret) 106 return ret; 107 } 108 ret = __btrfs_set_acl(NULL, inode, acl, type); 109 if (ret) 110 inode->i_mode = old_mode; 111 return ret; 112 } 113 114 int btrfs_init_acl(struct btrfs_trans_handle *trans, 115 struct inode *inode, struct inode *dir) 116 { 117 struct posix_acl *default_acl, *acl; 118 int ret = 0; 119 120 /* this happens with subvols */ 121 if (!dir) 122 return 0; 123 124 ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); 125 if (ret) 126 return ret; 127 128 if (default_acl) { 129 ret = __btrfs_set_acl(trans, inode, default_acl, 130 ACL_TYPE_DEFAULT); 131 posix_acl_release(default_acl); 132 } 133 134 if (acl) { 135 if (!ret) 136 ret = __btrfs_set_acl(trans, inode, acl, 137 ACL_TYPE_ACCESS); 138 posix_acl_release(acl); 139 } 140 141 if (!default_acl && !acl) 142 cache_no_acl(inode); 143 return ret; 144 } 145