1 /* 2 * linux/fs/hfsplus/xattr.c 3 * 4 * Vyacheslav Dubeyko <slava@dubeyko.com> 5 * 6 * Logic of processing extended attributes 7 */ 8 9 #include "hfsplus_fs.h" 10 #include "xattr.h" 11 #include "acl.h" 12 13 const struct xattr_handler *hfsplus_xattr_handlers[] = { 14 &hfsplus_xattr_osx_handler, 15 &hfsplus_xattr_user_handler, 16 &hfsplus_xattr_trusted_handler, 17 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL 18 &hfsplus_xattr_acl_access_handler, 19 &hfsplus_xattr_acl_default_handler, 20 #endif 21 &hfsplus_xattr_security_handler, 22 NULL 23 }; 24 25 static int strcmp_xattr_finder_info(const char *name) 26 { 27 if (name) { 28 return strncmp(name, HFSPLUS_XATTR_FINDER_INFO_NAME, 29 sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME)); 30 } 31 return -1; 32 } 33 34 static int strcmp_xattr_acl(const char *name) 35 { 36 if (name) { 37 return strncmp(name, HFSPLUS_XATTR_ACL_NAME, 38 sizeof(HFSPLUS_XATTR_ACL_NAME)); 39 } 40 return -1; 41 } 42 43 static inline int is_known_namespace(const char *name) 44 { 45 if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) && 46 strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && 47 strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && 48 strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) 49 return false; 50 51 return true; 52 } 53 54 static int can_set_system_xattr(struct inode *inode, const char *name, 55 const void *value, size_t size) 56 { 57 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL 58 struct posix_acl *acl; 59 int err; 60 61 if (!inode_owner_or_capable(inode)) 62 return -EPERM; 63 64 /* 65 * POSIX_ACL_XATTR_ACCESS is tied to i_mode 66 */ 67 if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) { 68 acl = posix_acl_from_xattr(&init_user_ns, value, size); 69 if (IS_ERR(acl)) 70 return PTR_ERR(acl); 71 if (acl) { 72 err = posix_acl_equiv_mode(acl, &inode->i_mode); 73 posix_acl_release(acl); 74 if (err < 0) 75 return err; 76 mark_inode_dirty(inode); 77 } 78 /* 79 * We're changing the ACL. Get rid of the cached one 80 */ 81 forget_cached_acl(inode, ACL_TYPE_ACCESS); 82 83 return 0; 84 } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { 85 acl = posix_acl_from_xattr(&init_user_ns, value, size); 86 if (IS_ERR(acl)) 87 return PTR_ERR(acl); 88 posix_acl_release(acl); 89 90 /* 91 * We're changing the default ACL. Get rid of the cached one 92 */ 93 forget_cached_acl(inode, ACL_TYPE_DEFAULT); 94 95 return 0; 96 } 97 #endif /* CONFIG_HFSPLUS_FS_POSIX_ACL */ 98 return -EOPNOTSUPP; 99 } 100 101 static int can_set_xattr(struct inode *inode, const char *name, 102 const void *value, size_t value_len) 103 { 104 if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) 105 return can_set_system_xattr(inode, name, value, value_len); 106 107 if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) { 108 /* 109 * This makes sure that we aren't trying to set an 110 * attribute in a different namespace by prefixing it 111 * with "osx." 112 */ 113 if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN)) 114 return -EOPNOTSUPP; 115 116 return 0; 117 } 118 119 /* 120 * Don't allow setting an attribute in an unknown namespace. 121 */ 122 if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && 123 strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && 124 strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) 125 return -EOPNOTSUPP; 126 127 return 0; 128 } 129 130 static void hfsplus_init_header_node(struct inode *attr_file, 131 u32 clump_size, 132 char *buf, u16 node_size) 133 { 134 struct hfs_bnode_desc *desc; 135 struct hfs_btree_header_rec *head; 136 u16 offset; 137 __be16 *rec_offsets; 138 u32 hdr_node_map_rec_bits; 139 char *bmp; 140 u32 used_nodes; 141 u32 used_bmp_bytes; 142 loff_t tmp; 143 144 hfs_dbg(ATTR_MOD, "init_hdr_attr_file: clump %u, node_size %u\n", 145 clump_size, node_size); 146 147 /* The end of the node contains list of record offsets */ 148 rec_offsets = (__be16 *)(buf + node_size); 149 150 desc = (struct hfs_bnode_desc *)buf; 151 desc->type = HFS_NODE_HEADER; 152 desc->num_recs = cpu_to_be16(HFSPLUS_BTREE_HDR_NODE_RECS_COUNT); 153 offset = sizeof(struct hfs_bnode_desc); 154 *--rec_offsets = cpu_to_be16(offset); 155 156 head = (struct hfs_btree_header_rec *)(buf + offset); 157 head->node_size = cpu_to_be16(node_size); 158 tmp = i_size_read(attr_file); 159 do_div(tmp, node_size); 160 head->node_count = cpu_to_be32(tmp); 161 head->free_nodes = cpu_to_be32(be32_to_cpu(head->node_count) - 1); 162 head->clump_size = cpu_to_be32(clump_size); 163 head->attributes |= cpu_to_be32(HFS_TREE_BIGKEYS | HFS_TREE_VARIDXKEYS); 164 head->max_key_len = cpu_to_be16(HFSPLUS_ATTR_KEYLEN - sizeof(u16)); 165 offset += sizeof(struct hfs_btree_header_rec); 166 *--rec_offsets = cpu_to_be16(offset); 167 offset += HFSPLUS_BTREE_HDR_USER_BYTES; 168 *--rec_offsets = cpu_to_be16(offset); 169 170 hdr_node_map_rec_bits = 8 * (node_size - offset - (4 * sizeof(u16))); 171 if (be32_to_cpu(head->node_count) > hdr_node_map_rec_bits) { 172 u32 map_node_bits; 173 u32 map_nodes; 174 175 desc->next = cpu_to_be32(be32_to_cpu(head->leaf_tail) + 1); 176 map_node_bits = 8 * (node_size - sizeof(struct hfs_bnode_desc) - 177 (2 * sizeof(u16)) - 2); 178 map_nodes = (be32_to_cpu(head->node_count) - 179 hdr_node_map_rec_bits + 180 (map_node_bits - 1)) / map_node_bits; 181 be32_add_cpu(&head->free_nodes, 0 - map_nodes); 182 } 183 184 bmp = buf + offset; 185 used_nodes = 186 be32_to_cpu(head->node_count) - be32_to_cpu(head->free_nodes); 187 used_bmp_bytes = used_nodes / 8; 188 if (used_bmp_bytes) { 189 memset(bmp, 0xFF, used_bmp_bytes); 190 bmp += used_bmp_bytes; 191 used_nodes %= 8; 192 } 193 *bmp = ~(0xFF >> used_nodes); 194 offset += hdr_node_map_rec_bits / 8; 195 *--rec_offsets = cpu_to_be16(offset); 196 } 197 198 static int hfsplus_create_attributes_file(struct super_block *sb) 199 { 200 int err = 0; 201 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 202 struct inode *attr_file; 203 struct hfsplus_inode_info *hip; 204 u32 clump_size; 205 u16 node_size = HFSPLUS_ATTR_TREE_NODE_SIZE; 206 char *buf; 207 int index, written; 208 struct address_space *mapping; 209 struct page *page; 210 int old_state = HFSPLUS_EMPTY_ATTR_TREE; 211 212 hfs_dbg(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID); 213 214 check_attr_tree_state_again: 215 switch (atomic_read(&sbi->attr_tree_state)) { 216 case HFSPLUS_EMPTY_ATTR_TREE: 217 if (old_state != atomic_cmpxchg(&sbi->attr_tree_state, 218 old_state, 219 HFSPLUS_CREATING_ATTR_TREE)) 220 goto check_attr_tree_state_again; 221 break; 222 case HFSPLUS_CREATING_ATTR_TREE: 223 /* 224 * This state means that another thread is in process 225 * of AttributesFile creation. Theoretically, it is 226 * possible to be here. But really __setxattr() method 227 * first of all calls hfs_find_init() for lookup in 228 * B-tree of CatalogFile. This method locks mutex of 229 * CatalogFile's B-tree. As a result, if some thread 230 * is inside AttributedFile creation operation then 231 * another threads will be waiting unlocking of 232 * CatalogFile's B-tree's mutex. However, if code will 233 * change then we will return error code (-EAGAIN) from 234 * here. Really, it means that first try to set of xattr 235 * fails with error but second attempt will have success. 236 */ 237 return -EAGAIN; 238 case HFSPLUS_VALID_ATTR_TREE: 239 return 0; 240 case HFSPLUS_FAILED_ATTR_TREE: 241 return -EOPNOTSUPP; 242 default: 243 BUG(); 244 } 245 246 attr_file = hfsplus_iget(sb, HFSPLUS_ATTR_CNID); 247 if (IS_ERR(attr_file)) { 248 pr_err("failed to load attributes file\n"); 249 return PTR_ERR(attr_file); 250 } 251 252 BUG_ON(i_size_read(attr_file) != 0); 253 254 hip = HFSPLUS_I(attr_file); 255 256 clump_size = hfsplus_calc_btree_clump_size(sb->s_blocksize, 257 node_size, 258 sbi->sect_count, 259 HFSPLUS_ATTR_CNID); 260 261 mutex_lock(&hip->extents_lock); 262 hip->clump_blocks = clump_size >> sbi->alloc_blksz_shift; 263 mutex_unlock(&hip->extents_lock); 264 265 if (sbi->free_blocks <= (hip->clump_blocks << 1)) { 266 err = -ENOSPC; 267 goto end_attr_file_creation; 268 } 269 270 while (hip->alloc_blocks < hip->clump_blocks) { 271 err = hfsplus_file_extend(attr_file); 272 if (unlikely(err)) { 273 pr_err("failed to extend attributes file\n"); 274 goto end_attr_file_creation; 275 } 276 hip->phys_size = attr_file->i_size = 277 (loff_t)hip->alloc_blocks << sbi->alloc_blksz_shift; 278 hip->fs_blocks = hip->alloc_blocks << sbi->fs_shift; 279 inode_set_bytes(attr_file, attr_file->i_size); 280 } 281 282 buf = kzalloc(node_size, GFP_NOFS); 283 if (!buf) { 284 pr_err("failed to allocate memory for header node\n"); 285 err = -ENOMEM; 286 goto end_attr_file_creation; 287 } 288 289 hfsplus_init_header_node(attr_file, clump_size, buf, node_size); 290 291 mapping = attr_file->i_mapping; 292 293 index = 0; 294 written = 0; 295 for (; written < node_size; index++, written += PAGE_CACHE_SIZE) { 296 void *kaddr; 297 298 page = read_mapping_page(mapping, index, NULL); 299 if (IS_ERR(page)) { 300 err = PTR_ERR(page); 301 goto failed_header_node_init; 302 } 303 304 kaddr = kmap_atomic(page); 305 memcpy(kaddr, buf + written, 306 min_t(size_t, PAGE_CACHE_SIZE, node_size - written)); 307 kunmap_atomic(kaddr); 308 309 set_page_dirty(page); 310 page_cache_release(page); 311 } 312 313 hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY); 314 315 sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID); 316 if (!sbi->attr_tree) 317 pr_err("failed to load attributes file\n"); 318 319 failed_header_node_init: 320 kfree(buf); 321 322 end_attr_file_creation: 323 iput(attr_file); 324 325 if (!err) 326 atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE); 327 else if (err == -ENOSPC) 328 atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE); 329 else 330 atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE); 331 332 return err; 333 } 334 335 int __hfsplus_setxattr(struct inode *inode, const char *name, 336 const void *value, size_t size, int flags) 337 { 338 int err = 0; 339 struct hfs_find_data cat_fd; 340 hfsplus_cat_entry entry; 341 u16 cat_entry_flags, cat_entry_type; 342 u16 folder_finderinfo_len = sizeof(struct DInfo) + 343 sizeof(struct DXInfo); 344 u16 file_finderinfo_len = sizeof(struct FInfo) + 345 sizeof(struct FXInfo); 346 347 if ((!S_ISREG(inode->i_mode) && 348 !S_ISDIR(inode->i_mode)) || 349 HFSPLUS_IS_RSRC(inode)) 350 return -EOPNOTSUPP; 351 352 err = can_set_xattr(inode, name, value, size); 353 if (err) 354 return err; 355 356 if (strncmp(name, XATTR_MAC_OSX_PREFIX, 357 XATTR_MAC_OSX_PREFIX_LEN) == 0) 358 name += XATTR_MAC_OSX_PREFIX_LEN; 359 360 if (value == NULL) { 361 value = ""; 362 size = 0; 363 } 364 365 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); 366 if (err) { 367 pr_err("can't init xattr find struct\n"); 368 return err; 369 } 370 371 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); 372 if (err) { 373 pr_err("catalog searching failed\n"); 374 goto end_setxattr; 375 } 376 377 if (!strcmp_xattr_finder_info(name)) { 378 if (flags & XATTR_CREATE) { 379 pr_err("xattr exists yet\n"); 380 err = -EOPNOTSUPP; 381 goto end_setxattr; 382 } 383 hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset, 384 sizeof(hfsplus_cat_entry)); 385 if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) { 386 if (size == folder_finderinfo_len) { 387 memcpy(&entry.folder.user_info, value, 388 folder_finderinfo_len); 389 hfs_bnode_write(cat_fd.bnode, &entry, 390 cat_fd.entryoffset, 391 sizeof(struct hfsplus_cat_folder)); 392 hfsplus_mark_inode_dirty(inode, 393 HFSPLUS_I_CAT_DIRTY); 394 } else { 395 err = -ERANGE; 396 goto end_setxattr; 397 } 398 } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) { 399 if (size == file_finderinfo_len) { 400 memcpy(&entry.file.user_info, value, 401 file_finderinfo_len); 402 hfs_bnode_write(cat_fd.bnode, &entry, 403 cat_fd.entryoffset, 404 sizeof(struct hfsplus_cat_file)); 405 hfsplus_mark_inode_dirty(inode, 406 HFSPLUS_I_CAT_DIRTY); 407 } else { 408 err = -ERANGE; 409 goto end_setxattr; 410 } 411 } else { 412 err = -EOPNOTSUPP; 413 goto end_setxattr; 414 } 415 goto end_setxattr; 416 } 417 418 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) { 419 err = hfsplus_create_attributes_file(inode->i_sb); 420 if (unlikely(err)) 421 goto end_setxattr; 422 } 423 424 if (hfsplus_attr_exists(inode, name)) { 425 if (flags & XATTR_CREATE) { 426 pr_err("xattr exists yet\n"); 427 err = -EOPNOTSUPP; 428 goto end_setxattr; 429 } 430 err = hfsplus_delete_attr(inode, name); 431 if (err) 432 goto end_setxattr; 433 err = hfsplus_create_attr(inode, name, value, size); 434 if (err) 435 goto end_setxattr; 436 } else { 437 if (flags & XATTR_REPLACE) { 438 pr_err("cannot replace xattr\n"); 439 err = -EOPNOTSUPP; 440 goto end_setxattr; 441 } 442 err = hfsplus_create_attr(inode, name, value, size); 443 if (err) 444 goto end_setxattr; 445 } 446 447 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); 448 if (cat_entry_type == HFSPLUS_FOLDER) { 449 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, 450 cat_fd.entryoffset + 451 offsetof(struct hfsplus_cat_folder, flags)); 452 cat_entry_flags |= HFSPLUS_XATTR_EXISTS; 453 if (!strcmp_xattr_acl(name)) 454 cat_entry_flags |= HFSPLUS_ACL_EXISTS; 455 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 456 offsetof(struct hfsplus_cat_folder, flags), 457 cat_entry_flags); 458 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 459 } else if (cat_entry_type == HFSPLUS_FILE) { 460 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, 461 cat_fd.entryoffset + 462 offsetof(struct hfsplus_cat_file, flags)); 463 cat_entry_flags |= HFSPLUS_XATTR_EXISTS; 464 if (!strcmp_xattr_acl(name)) 465 cat_entry_flags |= HFSPLUS_ACL_EXISTS; 466 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 467 offsetof(struct hfsplus_cat_file, flags), 468 cat_entry_flags); 469 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 470 } else { 471 pr_err("invalid catalog entry type\n"); 472 err = -EIO; 473 goto end_setxattr; 474 } 475 476 end_setxattr: 477 hfs_find_exit(&cat_fd); 478 return err; 479 } 480 481 static inline int is_osx_xattr(const char *xattr_name) 482 { 483 return !is_known_namespace(xattr_name); 484 } 485 486 static int name_len(const char *xattr_name, int xattr_name_len) 487 { 488 int len = xattr_name_len + 1; 489 490 if (is_osx_xattr(xattr_name)) 491 len += XATTR_MAC_OSX_PREFIX_LEN; 492 493 return len; 494 } 495 496 static int copy_name(char *buffer, const char *xattr_name, int name_len) 497 { 498 int len = name_len; 499 int offset = 0; 500 501 if (is_osx_xattr(xattr_name)) { 502 strncpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN); 503 offset += XATTR_MAC_OSX_PREFIX_LEN; 504 len += XATTR_MAC_OSX_PREFIX_LEN; 505 } 506 507 strncpy(buffer + offset, xattr_name, name_len); 508 memset(buffer + offset + name_len, 0, 1); 509 len += 1; 510 511 return len; 512 } 513 514 static ssize_t hfsplus_getxattr_finder_info(struct inode *inode, 515 void *value, size_t size) 516 { 517 ssize_t res = 0; 518 struct hfs_find_data fd; 519 u16 entry_type; 520 u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo); 521 u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo); 522 u16 record_len = max(folder_rec_len, file_rec_len); 523 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; 524 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; 525 526 if (size >= record_len) { 527 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 528 if (res) { 529 pr_err("can't init xattr find struct\n"); 530 return res; 531 } 532 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 533 if (res) 534 goto end_getxattr_finder_info; 535 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 536 537 if (entry_type == HFSPLUS_FOLDER) { 538 hfs_bnode_read(fd.bnode, folder_finder_info, 539 fd.entryoffset + 540 offsetof(struct hfsplus_cat_folder, user_info), 541 folder_rec_len); 542 memcpy(value, folder_finder_info, folder_rec_len); 543 res = folder_rec_len; 544 } else if (entry_type == HFSPLUS_FILE) { 545 hfs_bnode_read(fd.bnode, file_finder_info, 546 fd.entryoffset + 547 offsetof(struct hfsplus_cat_file, user_info), 548 file_rec_len); 549 memcpy(value, file_finder_info, file_rec_len); 550 res = file_rec_len; 551 } else { 552 res = -EOPNOTSUPP; 553 goto end_getxattr_finder_info; 554 } 555 } else 556 res = size ? -ERANGE : record_len; 557 558 end_getxattr_finder_info: 559 if (size >= record_len) 560 hfs_find_exit(&fd); 561 return res; 562 } 563 564 ssize_t __hfsplus_getxattr(struct inode *inode, const char *name, 565 void *value, size_t size) 566 { 567 struct hfs_find_data fd; 568 hfsplus_attr_entry *entry; 569 __be32 xattr_record_type; 570 u32 record_type; 571 u16 record_length = 0; 572 ssize_t res = 0; 573 574 if ((!S_ISREG(inode->i_mode) && 575 !S_ISDIR(inode->i_mode)) || 576 HFSPLUS_IS_RSRC(inode)) 577 return -EOPNOTSUPP; 578 579 if (strncmp(name, XATTR_MAC_OSX_PREFIX, 580 XATTR_MAC_OSX_PREFIX_LEN) == 0) { 581 /* skip "osx." prefix */ 582 name += XATTR_MAC_OSX_PREFIX_LEN; 583 /* 584 * Don't allow retrieving properly prefixed attributes 585 * by prepending them with "osx." 586 */ 587 if (is_known_namespace(name)) 588 return -EOPNOTSUPP; 589 } 590 591 if (!strcmp_xattr_finder_info(name)) 592 return hfsplus_getxattr_finder_info(inode, value, size); 593 594 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 595 return -EOPNOTSUPP; 596 597 entry = hfsplus_alloc_attr_entry(); 598 if (!entry) { 599 pr_err("can't allocate xattr entry\n"); 600 return -ENOMEM; 601 } 602 603 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); 604 if (res) { 605 pr_err("can't init xattr find struct\n"); 606 goto failed_getxattr_init; 607 } 608 609 res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd); 610 if (res) { 611 if (res == -ENOENT) 612 res = -ENODATA; 613 else 614 pr_err("xattr searching failed\n"); 615 goto out; 616 } 617 618 hfs_bnode_read(fd.bnode, &xattr_record_type, 619 fd.entryoffset, sizeof(xattr_record_type)); 620 record_type = be32_to_cpu(xattr_record_type); 621 if (record_type == HFSPLUS_ATTR_INLINE_DATA) { 622 record_length = hfs_bnode_read_u16(fd.bnode, 623 fd.entryoffset + 624 offsetof(struct hfsplus_attr_inline_data, 625 length)); 626 if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) { 627 pr_err("invalid xattr record size\n"); 628 res = -EIO; 629 goto out; 630 } 631 } else if (record_type == HFSPLUS_ATTR_FORK_DATA || 632 record_type == HFSPLUS_ATTR_EXTENTS) { 633 pr_err("only inline data xattr are supported\n"); 634 res = -EOPNOTSUPP; 635 goto out; 636 } else { 637 pr_err("invalid xattr record\n"); 638 res = -EIO; 639 goto out; 640 } 641 642 if (size) { 643 hfs_bnode_read(fd.bnode, entry, fd.entryoffset, 644 offsetof(struct hfsplus_attr_inline_data, 645 raw_bytes) + record_length); 646 } 647 648 if (size >= record_length) { 649 memcpy(value, entry->inline_data.raw_bytes, record_length); 650 res = record_length; 651 } else 652 res = size ? -ERANGE : record_length; 653 654 out: 655 hfs_find_exit(&fd); 656 657 failed_getxattr_init: 658 hfsplus_destroy_attr_entry(entry); 659 return res; 660 } 661 662 static inline int can_list(const char *xattr_name) 663 { 664 if (!xattr_name) 665 return 0; 666 667 return strncmp(xattr_name, XATTR_TRUSTED_PREFIX, 668 XATTR_TRUSTED_PREFIX_LEN) || 669 capable(CAP_SYS_ADMIN); 670 } 671 672 static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry, 673 char *buffer, size_t size) 674 { 675 ssize_t res = 0; 676 struct inode *inode = dentry->d_inode; 677 struct hfs_find_data fd; 678 u16 entry_type; 679 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; 680 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; 681 unsigned long len, found_bit; 682 int xattr_name_len, symbols_count; 683 684 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 685 if (res) { 686 pr_err("can't init xattr find struct\n"); 687 return res; 688 } 689 690 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 691 if (res) 692 goto end_listxattr_finder_info; 693 694 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 695 if (entry_type == HFSPLUS_FOLDER) { 696 len = sizeof(struct DInfo) + sizeof(struct DXInfo); 697 hfs_bnode_read(fd.bnode, folder_finder_info, 698 fd.entryoffset + 699 offsetof(struct hfsplus_cat_folder, user_info), 700 len); 701 found_bit = find_first_bit((void *)folder_finder_info, len*8); 702 } else if (entry_type == HFSPLUS_FILE) { 703 len = sizeof(struct FInfo) + sizeof(struct FXInfo); 704 hfs_bnode_read(fd.bnode, file_finder_info, 705 fd.entryoffset + 706 offsetof(struct hfsplus_cat_file, user_info), 707 len); 708 found_bit = find_first_bit((void *)file_finder_info, len*8); 709 } else { 710 res = -EOPNOTSUPP; 711 goto end_listxattr_finder_info; 712 } 713 714 if (found_bit >= (len*8)) 715 res = 0; 716 else { 717 symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1; 718 xattr_name_len = 719 name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count); 720 if (!buffer || !size) { 721 if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) 722 res = xattr_name_len; 723 } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) { 724 if (size < xattr_name_len) 725 res = -ERANGE; 726 else { 727 res = copy_name(buffer, 728 HFSPLUS_XATTR_FINDER_INFO_NAME, 729 symbols_count); 730 } 731 } 732 } 733 734 end_listxattr_finder_info: 735 hfs_find_exit(&fd); 736 737 return res; 738 } 739 740 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) 741 { 742 ssize_t err; 743 ssize_t res = 0; 744 struct inode *inode = dentry->d_inode; 745 struct hfs_find_data fd; 746 u16 key_len = 0; 747 struct hfsplus_attr_key attr_key; 748 char strbuf[HFSPLUS_ATTR_MAX_STRLEN + 749 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; 750 int xattr_name_len; 751 752 if ((!S_ISREG(inode->i_mode) && 753 !S_ISDIR(inode->i_mode)) || 754 HFSPLUS_IS_RSRC(inode)) 755 return -EOPNOTSUPP; 756 757 res = hfsplus_listxattr_finder_info(dentry, buffer, size); 758 if (res < 0) 759 return res; 760 else if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 761 return (res == 0) ? -EOPNOTSUPP : res; 762 763 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); 764 if (err) { 765 pr_err("can't init xattr find struct\n"); 766 return err; 767 } 768 769 err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd); 770 if (err) { 771 if (err == -ENOENT) { 772 if (res == 0) 773 res = -ENODATA; 774 goto end_listxattr; 775 } else { 776 res = err; 777 goto end_listxattr; 778 } 779 } 780 781 for (;;) { 782 key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset); 783 if (key_len == 0 || key_len > fd.tree->max_key_len) { 784 pr_err("invalid xattr key length: %d\n", key_len); 785 res = -EIO; 786 goto end_listxattr; 787 } 788 789 hfs_bnode_read(fd.bnode, &attr_key, 790 fd.keyoffset, key_len + sizeof(key_len)); 791 792 if (be32_to_cpu(attr_key.cnid) != inode->i_ino) 793 goto end_listxattr; 794 795 xattr_name_len = HFSPLUS_ATTR_MAX_STRLEN; 796 if (hfsplus_uni2asc(inode->i_sb, 797 (const struct hfsplus_unistr *)&fd.key->attr.key_name, 798 strbuf, &xattr_name_len)) { 799 pr_err("unicode conversion failed\n"); 800 res = -EIO; 801 goto end_listxattr; 802 } 803 804 if (!buffer || !size) { 805 if (can_list(strbuf)) 806 res += name_len(strbuf, xattr_name_len); 807 } else if (can_list(strbuf)) { 808 if (size < (res + name_len(strbuf, xattr_name_len))) { 809 res = -ERANGE; 810 goto end_listxattr; 811 } else 812 res += copy_name(buffer + res, 813 strbuf, xattr_name_len); 814 } 815 816 if (hfs_brec_goto(&fd, 1)) 817 goto end_listxattr; 818 } 819 820 end_listxattr: 821 hfs_find_exit(&fd); 822 return res; 823 } 824 825 int hfsplus_removexattr(struct dentry *dentry, const char *name) 826 { 827 int err = 0; 828 struct inode *inode = dentry->d_inode; 829 struct hfs_find_data cat_fd; 830 u16 flags; 831 u16 cat_entry_type; 832 int is_xattr_acl_deleted = 0; 833 int is_all_xattrs_deleted = 0; 834 835 if ((!S_ISREG(inode->i_mode) && 836 !S_ISDIR(inode->i_mode)) || 837 HFSPLUS_IS_RSRC(inode)) 838 return -EOPNOTSUPP; 839 840 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 841 return -EOPNOTSUPP; 842 843 err = can_set_xattr(inode, name, NULL, 0); 844 if (err) 845 return err; 846 847 if (strncmp(name, XATTR_MAC_OSX_PREFIX, 848 XATTR_MAC_OSX_PREFIX_LEN) == 0) 849 name += XATTR_MAC_OSX_PREFIX_LEN; 850 851 if (!strcmp_xattr_finder_info(name)) 852 return -EOPNOTSUPP; 853 854 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); 855 if (err) { 856 pr_err("can't init xattr find struct\n"); 857 return err; 858 } 859 860 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); 861 if (err) { 862 pr_err("catalog searching failed\n"); 863 goto end_removexattr; 864 } 865 866 err = hfsplus_delete_attr(inode, name); 867 if (err) 868 goto end_removexattr; 869 870 is_xattr_acl_deleted = !strcmp_xattr_acl(name); 871 is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL); 872 873 if (!is_xattr_acl_deleted && !is_all_xattrs_deleted) 874 goto end_removexattr; 875 876 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); 877 878 if (cat_entry_type == HFSPLUS_FOLDER) { 879 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + 880 offsetof(struct hfsplus_cat_folder, flags)); 881 if (is_xattr_acl_deleted) 882 flags &= ~HFSPLUS_ACL_EXISTS; 883 if (is_all_xattrs_deleted) 884 flags &= ~HFSPLUS_XATTR_EXISTS; 885 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 886 offsetof(struct hfsplus_cat_folder, flags), 887 flags); 888 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 889 } else if (cat_entry_type == HFSPLUS_FILE) { 890 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + 891 offsetof(struct hfsplus_cat_file, flags)); 892 if (is_xattr_acl_deleted) 893 flags &= ~HFSPLUS_ACL_EXISTS; 894 if (is_all_xattrs_deleted) 895 flags &= ~HFSPLUS_XATTR_EXISTS; 896 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 897 offsetof(struct hfsplus_cat_file, flags), 898 flags); 899 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 900 } else { 901 pr_err("invalid catalog entry type\n"); 902 err = -EIO; 903 goto end_removexattr; 904 } 905 906 end_removexattr: 907 hfs_find_exit(&cat_fd); 908 return err; 909 } 910 911 static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name, 912 void *buffer, size_t size, int type) 913 { 914 char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 915 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; 916 size_t len = strlen(name); 917 918 if (!strcmp(name, "")) 919 return -EINVAL; 920 921 if (len > HFSPLUS_ATTR_MAX_STRLEN) 922 return -EOPNOTSUPP; 923 924 strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); 925 strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); 926 927 return hfsplus_getxattr(dentry, xattr_name, buffer, size); 928 } 929 930 static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name, 931 const void *buffer, size_t size, int flags, int type) 932 { 933 char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 934 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; 935 size_t len = strlen(name); 936 937 if (!strcmp(name, "")) 938 return -EINVAL; 939 940 if (len > HFSPLUS_ATTR_MAX_STRLEN) 941 return -EOPNOTSUPP; 942 943 strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); 944 strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); 945 946 return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); 947 } 948 949 static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list, 950 size_t list_size, const char *name, size_t name_len, int type) 951 { 952 /* 953 * This method is not used. 954 * It is used hfsplus_listxattr() instead of generic_listxattr(). 955 */ 956 return -EOPNOTSUPP; 957 } 958 959 const struct xattr_handler hfsplus_xattr_osx_handler = { 960 .prefix = XATTR_MAC_OSX_PREFIX, 961 .list = hfsplus_osx_listxattr, 962 .get = hfsplus_osx_getxattr, 963 .set = hfsplus_osx_setxattr, 964 }; 965