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