Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hfsplus: implement POSIX ACLs support

Implement POSIX ACLs support in hfsplus driver.

Signed-off-by: Vyacheslav Dubeyko <slava@dubeyko.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Hin-Tak Leung <htl10@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Vyacheslav Dubeyko and committed by
Linus Torvalds
eef80d4a 2c92057e

+274
+274
fs/hfsplus/posix_acl.c
··· 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 + 13 + struct 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 + acl = get_cached_acl(inode, type); 21 + if (acl != ACL_NOT_CACHED) 22 + return acl; 23 + 24 + switch (type) { 25 + case ACL_TYPE_ACCESS: 26 + xattr_name = POSIX_ACL_XATTR_ACCESS; 27 + break; 28 + case ACL_TYPE_DEFAULT: 29 + xattr_name = POSIX_ACL_XATTR_DEFAULT; 30 + break; 31 + default: 32 + return ERR_PTR(-EINVAL); 33 + } 34 + 35 + size = __hfsplus_getxattr(inode, xattr_name, NULL, 0); 36 + 37 + if (size > 0) { 38 + value = (char *)hfsplus_alloc_attr_entry(); 39 + if (unlikely(!value)) 40 + return ERR_PTR(-ENOMEM); 41 + size = __hfsplus_getxattr(inode, xattr_name, value, size); 42 + } 43 + 44 + if (size > 0) 45 + acl = posix_acl_from_xattr(&init_user_ns, value, size); 46 + else if (size == -ENODATA) 47 + acl = NULL; 48 + else 49 + acl = ERR_PTR(size); 50 + 51 + hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value); 52 + 53 + if (!IS_ERR(acl)) 54 + set_cached_acl(inode, type, acl); 55 + 56 + return acl; 57 + } 58 + 59 + static int hfsplus_set_posix_acl(struct inode *inode, 60 + int type, 61 + struct posix_acl *acl) 62 + { 63 + int err; 64 + char *xattr_name; 65 + size_t size = 0; 66 + char *value = NULL; 67 + 68 + if (S_ISLNK(inode->i_mode)) 69 + return -EOPNOTSUPP; 70 + 71 + switch (type) { 72 + case ACL_TYPE_ACCESS: 73 + xattr_name = POSIX_ACL_XATTR_ACCESS; 74 + if (acl) { 75 + err = posix_acl_equiv_mode(acl, &inode->i_mode); 76 + if (err < 0) 77 + return err; 78 + } 79 + err = 0; 80 + break; 81 + 82 + case ACL_TYPE_DEFAULT: 83 + xattr_name = POSIX_ACL_XATTR_DEFAULT; 84 + if (!S_ISDIR(inode->i_mode)) 85 + return acl ? -EACCES : 0; 86 + break; 87 + 88 + default: 89 + return -EINVAL; 90 + } 91 + 92 + if (acl) { 93 + size = posix_acl_xattr_size(acl->a_count); 94 + if (unlikely(size > HFSPLUS_MAX_INLINE_DATA_SIZE)) 95 + return -ENOMEM; 96 + value = (char *)hfsplus_alloc_attr_entry(); 97 + if (unlikely(!value)) 98 + return -ENOMEM; 99 + err = posix_acl_to_xattr(&init_user_ns, acl, value, size); 100 + if (unlikely(err < 0)) 101 + goto end_set_acl; 102 + } 103 + 104 + err = __hfsplus_setxattr(inode, xattr_name, value, size, 0); 105 + 106 + end_set_acl: 107 + hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value); 108 + 109 + if (!err) 110 + set_cached_acl(inode, type, acl); 111 + 112 + return err; 113 + } 114 + 115 + int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir) 116 + { 117 + int err = 0; 118 + struct posix_acl *acl = NULL; 119 + 120 + hfs_dbg(ACL_MOD, 121 + "[%s]: ino %lu, dir->ino %lu\n", 122 + __func__, inode->i_ino, dir->i_ino); 123 + 124 + if (S_ISLNK(inode->i_mode)) 125 + return 0; 126 + 127 + acl = hfsplus_get_posix_acl(dir, ACL_TYPE_DEFAULT); 128 + if (IS_ERR(acl)) 129 + return PTR_ERR(acl); 130 + 131 + if (acl) { 132 + if (S_ISDIR(inode->i_mode)) { 133 + err = hfsplus_set_posix_acl(inode, 134 + ACL_TYPE_DEFAULT, 135 + acl); 136 + if (unlikely(err)) 137 + goto init_acl_cleanup; 138 + } 139 + 140 + err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); 141 + if (unlikely(err < 0)) 142 + return err; 143 + 144 + if (err > 0) 145 + err = hfsplus_set_posix_acl(inode, 146 + ACL_TYPE_ACCESS, 147 + acl); 148 + } else 149 + inode->i_mode &= ~current_umask(); 150 + 151 + init_acl_cleanup: 152 + posix_acl_release(acl); 153 + return err; 154 + } 155 + 156 + int hfsplus_posix_acl_chmod(struct inode *inode) 157 + { 158 + int err; 159 + struct posix_acl *acl; 160 + 161 + hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino); 162 + 163 + if (S_ISLNK(inode->i_mode)) 164 + return -EOPNOTSUPP; 165 + 166 + acl = hfsplus_get_posix_acl(inode, ACL_TYPE_ACCESS); 167 + if (IS_ERR(acl) || !acl) 168 + return PTR_ERR(acl); 169 + 170 + err = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); 171 + if (unlikely(err)) 172 + return err; 173 + 174 + err = hfsplus_set_posix_acl(inode, ACL_TYPE_ACCESS, acl); 175 + posix_acl_release(acl); 176 + return err; 177 + } 178 + 179 + static int hfsplus_xattr_get_posix_acl(struct dentry *dentry, 180 + const char *name, 181 + void *buffer, 182 + size_t size, 183 + int type) 184 + { 185 + int err = 0; 186 + struct posix_acl *acl; 187 + 188 + hfs_dbg(ACL_MOD, 189 + "[%s]: ino %lu, buffer %p, size %zu, type %#x\n", 190 + __func__, dentry->d_inode->i_ino, buffer, size, type); 191 + 192 + if (strcmp(name, "") != 0) 193 + return -EINVAL; 194 + 195 + acl = hfsplus_get_posix_acl(dentry->d_inode, type); 196 + if (IS_ERR(acl)) 197 + return PTR_ERR(acl); 198 + if (acl == NULL) 199 + return -ENODATA; 200 + 201 + err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); 202 + posix_acl_release(acl); 203 + 204 + return err; 205 + } 206 + 207 + static int hfsplus_xattr_set_posix_acl(struct dentry *dentry, 208 + const char *name, 209 + const void *value, 210 + size_t size, 211 + int flags, 212 + int type) 213 + { 214 + int err = 0; 215 + struct inode *inode = dentry->d_inode; 216 + struct posix_acl *acl = NULL; 217 + 218 + hfs_dbg(ACL_MOD, 219 + "[%s]: ino %lu, value %p, size %zu, flags %#x, type %#x\n", 220 + __func__, inode->i_ino, value, size, flags, type); 221 + 222 + if (strcmp(name, "") != 0) 223 + return -EINVAL; 224 + 225 + if (!inode_owner_or_capable(inode)) 226 + return -EPERM; 227 + 228 + if (value) { 229 + acl = posix_acl_from_xattr(&init_user_ns, value, size); 230 + if (IS_ERR(acl)) 231 + return PTR_ERR(acl); 232 + else if (acl) { 233 + err = posix_acl_valid(acl); 234 + if (err) 235 + goto end_xattr_set_acl; 236 + } 237 + } 238 + 239 + err = hfsplus_set_posix_acl(inode, type, acl); 240 + 241 + end_xattr_set_acl: 242 + posix_acl_release(acl); 243 + return err; 244 + } 245 + 246 + static size_t hfsplus_xattr_list_posix_acl(struct dentry *dentry, 247 + char *list, 248 + size_t list_size, 249 + const char *name, 250 + size_t name_len, 251 + int type) 252 + { 253 + /* 254 + * This method is not used. 255 + * It is used hfsplus_listxattr() instead of generic_listxattr(). 256 + */ 257 + return -EOPNOTSUPP; 258 + } 259 + 260 + const struct xattr_handler hfsplus_xattr_acl_access_handler = { 261 + .prefix = POSIX_ACL_XATTR_ACCESS, 262 + .flags = ACL_TYPE_ACCESS, 263 + .list = hfsplus_xattr_list_posix_acl, 264 + .get = hfsplus_xattr_get_posix_acl, 265 + .set = hfsplus_xattr_set_posix_acl, 266 + }; 267 + 268 + const struct xattr_handler hfsplus_xattr_acl_default_handler = { 269 + .prefix = POSIX_ACL_XATTR_DEFAULT, 270 + .flags = ACL_TYPE_DEFAULT, 271 + .list = hfsplus_xattr_list_posix_acl, 272 + .get = hfsplus_xattr_get_posix_acl, 273 + .set = hfsplus_xattr_set_posix_acl, 274 + };