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