1/* 2 * linux/fs/hfsplus/posix_acl.c 3 * 4 * Vyacheslav Dubeyko <slava@dubeyko.com> 5 * 6 * Handler for Posix Access Control Lists (ACLs) support. 7 */ 8 9#include "hfsplus_fs.h" 10#include "xattr.h" 11#include "acl.h" 12 13struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type) 14{ 15 struct posix_acl *acl; 16 char *xattr_name; 17 char *value = NULL; 18 ssize_t size; 19 20 hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino); 21 22 switch (type) { 23 case ACL_TYPE_ACCESS: 24 xattr_name = POSIX_ACL_XATTR_ACCESS; 25 break; 26 case ACL_TYPE_DEFAULT: 27 xattr_name = POSIX_ACL_XATTR_DEFAULT; 28 break; 29 default: 30 return ERR_PTR(-EINVAL); 31 } 32 33 size = __hfsplus_getxattr(inode, xattr_name, NULL, 0); 34 35 if (size > 0) { 36 value = (char *)hfsplus_alloc_attr_entry(); 37 if (unlikely(!value)) 38 return ERR_PTR(-ENOMEM); 39 size = __hfsplus_getxattr(inode, xattr_name, value, size); 40 } 41 42 if (size > 0) 43 acl = posix_acl_from_xattr(&init_user_ns, value, size); 44 else if (size == -ENODATA) 45 acl = NULL; 46 else 47 acl = ERR_PTR(size); 48 49 hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value); 50 51 if (!IS_ERR(acl)) 52 set_cached_acl(inode, type, acl); 53 54 return acl; 55} 56 57int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl, 58 int type) 59{ 60 int err; 61 char *xattr_name; 62 size_t size = 0; 63 char *value = NULL; 64 65 hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino); 66 67 switch (type) { 68 case ACL_TYPE_ACCESS: 69 xattr_name = POSIX_ACL_XATTR_ACCESS; 70 if (acl) { 71 err = posix_acl_equiv_mode(acl, &inode->i_mode); 72 if (err < 0) 73 return err; 74 } 75 err = 0; 76 break; 77 78 case ACL_TYPE_DEFAULT: 79 xattr_name = POSIX_ACL_XATTR_DEFAULT; 80 if (!S_ISDIR(inode->i_mode)) 81 return acl ? -EACCES : 0; 82 break; 83 84 default: 85 return -EINVAL; 86 } 87 88 if (acl) { 89 size = posix_acl_xattr_size(acl->a_count); 90 if (unlikely(size > HFSPLUS_MAX_INLINE_DATA_SIZE)) 91 return -ENOMEM; 92 value = (char *)hfsplus_alloc_attr_entry(); 93 if (unlikely(!value)) 94 return -ENOMEM; 95 err = posix_acl_to_xattr(&init_user_ns, acl, value, size); 96 if (unlikely(err < 0)) 97 goto end_set_acl; 98 } 99 100 err = __hfsplus_setxattr(inode, xattr_name, value, size, 0); 101 102end_set_acl: 103 hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value); 104 105 if (!err) 106 set_cached_acl(inode, type, acl); 107 108 return err; 109} 110 111int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir) 112{ 113 int err = 0; 114 struct posix_acl *default_acl, *acl; 115 116 hfs_dbg(ACL_MOD, 117 "[%s]: ino %lu, dir->ino %lu\n", 118 __func__, inode->i_ino, dir->i_ino); 119 120 if (S_ISLNK(inode->i_mode)) 121 return 0; 122 123 err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); 124 if (err) 125 return err; 126 127 if (default_acl) { 128 err = hfsplus_set_posix_acl(inode, default_acl, 129 ACL_TYPE_DEFAULT); 130 posix_acl_release(default_acl); 131 } 132 133 if (acl) { 134 if (!err) 135 err = hfsplus_set_posix_acl(inode, acl, 136 ACL_TYPE_ACCESS); 137 posix_acl_release(acl); 138 } 139 return err; 140} 141