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(HFSPLUS_ATTR_TREE_I(sb), HFSPLUS_I_ATTR_DIRTY); 321 hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY); 322 323 sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID); 324 if (!sbi->attr_tree) 325 pr_err("failed to load attributes file\n"); 326 327 failed_header_node_init: 328 kfree(buf); 329 330 end_attr_file_creation: 331 iput(attr_file); 332 333 if (!err) 334 atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE); 335 else if (err == -ENOSPC) 336 atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE); 337 else 338 atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE); 339 340 return err; 341 } 342 343 static inline 344 bool is_xattr_operation_supported(struct inode *inode) 345 { 346 if (HFSPLUS_IS_RSRC(inode)) 347 return false; 348 349 return true; 350 } 351 352 int __hfsplus_setxattr(struct inode *inode, const char *name, 353 const void *value, size_t size, int flags) 354 { 355 int err; 356 struct hfs_find_data cat_fd; 357 hfsplus_cat_entry entry; 358 u16 cat_entry_flags, cat_entry_type; 359 u16 folder_finderinfo_len = sizeof(DInfo) + sizeof(DXInfo); 360 u16 file_finderinfo_len = sizeof(FInfo) + sizeof(FXInfo); 361 362 hfs_dbg("ino %llu, name %s, value %p, size %zu\n", 363 inode->i_ino, name ? name : NULL, 364 value, size); 365 366 if (!is_xattr_operation_supported(inode)) 367 return -EOPNOTSUPP; 368 369 if (value == NULL) 370 return hfsplus_removexattr(inode, name); 371 372 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); 373 if (err) { 374 pr_err("can't init xattr find struct\n"); 375 return err; 376 } 377 378 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); 379 if (err) { 380 pr_err("catalog searching failed\n"); 381 goto end_setxattr; 382 } 383 384 if (!strcmp_xattr_finder_info(name)) { 385 if (flags & XATTR_CREATE) { 386 pr_err("xattr exists yet\n"); 387 err = -EOPNOTSUPP; 388 goto end_setxattr; 389 } 390 hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset, 391 sizeof(hfsplus_cat_entry)); 392 if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) { 393 if (size == folder_finderinfo_len) { 394 memcpy(&entry.folder.info, value, 395 folder_finderinfo_len); 396 hfs_bnode_write(cat_fd.bnode, &entry, 397 cat_fd.entryoffset, 398 sizeof(struct hfsplus_cat_folder)); 399 hfsplus_mark_inode_dirty( 400 HFSPLUS_CAT_TREE_I(inode->i_sb), 401 HFSPLUS_I_CAT_DIRTY); 402 hfsplus_mark_inode_dirty(inode, 403 HFSPLUS_I_CAT_DIRTY); 404 } else { 405 err = -ERANGE; 406 goto end_setxattr; 407 } 408 } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) { 409 if (size == file_finderinfo_len) { 410 memcpy(&entry.file.info, value, 411 file_finderinfo_len); 412 hfs_bnode_write(cat_fd.bnode, &entry, 413 cat_fd.entryoffset, 414 sizeof(struct hfsplus_cat_file)); 415 hfsplus_mark_inode_dirty( 416 HFSPLUS_CAT_TREE_I(inode->i_sb), 417 HFSPLUS_I_CAT_DIRTY); 418 hfsplus_mark_inode_dirty(inode, 419 HFSPLUS_I_CAT_DIRTY); 420 } else { 421 err = -ERANGE; 422 goto end_setxattr; 423 } 424 } else { 425 err = -EOPNOTSUPP; 426 goto end_setxattr; 427 } 428 goto end_setxattr; 429 } 430 431 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) { 432 err = hfsplus_create_attributes_file(inode->i_sb); 433 if (unlikely(err)) 434 goto end_setxattr; 435 } 436 437 if (hfsplus_attr_exists(inode, name)) { 438 if (flags & XATTR_CREATE) { 439 pr_err("xattr exists yet\n"); 440 err = -EOPNOTSUPP; 441 goto end_setxattr; 442 } 443 err = hfsplus_replace_attr(inode, name, value, size); 444 if (err) { 445 hfs_dbg("unable to replace xattr: err %d\n", err); 446 goto end_setxattr; 447 } 448 } else { 449 if (flags & XATTR_REPLACE) { 450 pr_err("cannot replace xattr\n"); 451 err = -EOPNOTSUPP; 452 goto end_setxattr; 453 } 454 err = hfsplus_create_attr(inode, name, value, size); 455 if (err) { 456 hfs_dbg("unable to store value: err %d\n", err); 457 goto end_setxattr; 458 } 459 } 460 461 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); 462 if (cat_entry_type == HFSPLUS_FOLDER) { 463 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, 464 cat_fd.entryoffset + 465 offsetof(struct hfsplus_cat_folder, flags)); 466 cat_entry_flags |= HFSPLUS_XATTR_EXISTS; 467 if (!strcmp_xattr_acl(name)) 468 cat_entry_flags |= HFSPLUS_ACL_EXISTS; 469 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 470 offsetof(struct hfsplus_cat_folder, flags), 471 cat_entry_flags); 472 hfsplus_mark_inode_dirty(HFSPLUS_CAT_TREE_I(inode->i_sb), 473 HFSPLUS_I_CAT_DIRTY); 474 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 475 } else if (cat_entry_type == HFSPLUS_FILE) { 476 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, 477 cat_fd.entryoffset + 478 offsetof(struct hfsplus_cat_file, flags)); 479 cat_entry_flags |= HFSPLUS_XATTR_EXISTS; 480 if (!strcmp_xattr_acl(name)) 481 cat_entry_flags |= HFSPLUS_ACL_EXISTS; 482 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 483 offsetof(struct hfsplus_cat_file, flags), 484 cat_entry_flags); 485 hfsplus_mark_inode_dirty(HFSPLUS_CAT_TREE_I(inode->i_sb), 486 HFSPLUS_I_CAT_DIRTY); 487 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 488 } else { 489 pr_err("invalid catalog entry type\n"); 490 err = -EIO; 491 goto end_setxattr; 492 } 493 494 inode_set_ctime_current(inode); 495 496 end_setxattr: 497 hfs_find_exit(&cat_fd); 498 hfs_dbg("finished: res %d\n", err); 499 return err; 500 } 501 502 static size_t name_len(const char *xattr_name, size_t xattr_name_len) 503 { 504 size_t len = xattr_name_len + 1; 505 506 if (!is_known_namespace(xattr_name)) 507 len += XATTR_MAC_OSX_PREFIX_LEN; 508 509 return len; 510 } 511 512 static ssize_t copy_name(char *buffer, const char *xattr_name, size_t name_len) 513 { 514 ssize_t len; 515 516 memset(buffer, 0, name_len); 517 518 if (!is_known_namespace(xattr_name)) { 519 len = scnprintf(buffer, name_len + XATTR_MAC_OSX_PREFIX_LEN, 520 "%s%s", XATTR_MAC_OSX_PREFIX, xattr_name); 521 } else { 522 len = strscpy(buffer, xattr_name, name_len + 1); 523 if (len < 0) { 524 pr_err("fail to copy name: err %zd\n", len); 525 len = 0; 526 } 527 } 528 529 /* include NUL-byte in length for non-empty name */ 530 if (len >= 0) 531 len++; 532 return len; 533 } 534 535 int hfsplus_setxattr(struct inode *inode, const char *name, 536 const void *value, size_t size, int flags, 537 const char *prefix, size_t prefixlen) 538 { 539 char *xattr_name; 540 size_t xattr_name_len = 541 NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1; 542 int res; 543 544 hfs_dbg("ino %llu, name %s, prefix %s, prefixlen %zu, " 545 "value %p, size %zu\n", 546 inode->i_ino, name ? name : NULL, 547 prefix ? prefix : NULL, prefixlen, 548 value, size); 549 550 xattr_name = kmalloc(xattr_name_len, GFP_KERNEL); 551 if (!xattr_name) 552 return -ENOMEM; 553 strcpy(xattr_name, prefix); 554 strcpy(xattr_name + prefixlen, name); 555 res = __hfsplus_setxattr(inode, xattr_name, value, size, flags); 556 kfree(xattr_name); 557 558 hfs_dbg("finished: res %d\n", res); 559 560 return res; 561 } 562 563 static ssize_t hfsplus_getxattr_finder_info(struct inode *inode, 564 void *value, size_t size) 565 { 566 ssize_t res = 0; 567 struct hfs_find_data fd; 568 u16 entry_type; 569 u16 folder_rec_len = sizeof(DInfo) + sizeof(DXInfo); 570 u16 file_rec_len = sizeof(FInfo) + sizeof(FXInfo); 571 u16 record_len = max(folder_rec_len, file_rec_len); 572 u8 folder_finder_info[sizeof(DInfo) + sizeof(DXInfo)]; 573 u8 file_finder_info[sizeof(FInfo) + sizeof(FXInfo)]; 574 575 if (size >= record_len) { 576 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 577 if (res) { 578 pr_err("can't init xattr find struct\n"); 579 return res; 580 } 581 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 582 if (res) 583 goto end_getxattr_finder_info; 584 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 585 586 if (entry_type == HFSPLUS_FOLDER) { 587 hfs_bnode_read(fd.bnode, folder_finder_info, 588 fd.entryoffset + 589 offsetof(struct hfsplus_cat_folder, user_info), 590 folder_rec_len); 591 memcpy(value, folder_finder_info, folder_rec_len); 592 res = folder_rec_len; 593 } else if (entry_type == HFSPLUS_FILE) { 594 hfs_bnode_read(fd.bnode, file_finder_info, 595 fd.entryoffset + 596 offsetof(struct hfsplus_cat_file, user_info), 597 file_rec_len); 598 memcpy(value, file_finder_info, file_rec_len); 599 res = file_rec_len; 600 } else { 601 res = -EOPNOTSUPP; 602 goto end_getxattr_finder_info; 603 } 604 } else 605 res = size ? -ERANGE : record_len; 606 607 end_getxattr_finder_info: 608 if (size >= record_len) 609 hfs_find_exit(&fd); 610 return res; 611 } 612 613 ssize_t __hfsplus_getxattr(struct inode *inode, const char *name, 614 void *value, size_t size) 615 { 616 struct hfs_find_data fd; 617 hfsplus_attr_entry *entry; 618 __be32 xattr_record_type; 619 u32 record_type; 620 u16 record_length = 0; 621 ssize_t res; 622 623 if (!is_xattr_operation_supported(inode)) 624 return -EOPNOTSUPP; 625 626 if (!strcmp_xattr_finder_info(name)) 627 return hfsplus_getxattr_finder_info(inode, value, size); 628 629 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 630 return -EOPNOTSUPP; 631 632 entry = hfsplus_alloc_attr_entry(); 633 if (!entry) { 634 pr_err("can't allocate xattr entry\n"); 635 return -ENOMEM; 636 } 637 638 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); 639 if (res) { 640 pr_err("can't init xattr find struct\n"); 641 goto failed_getxattr_init; 642 } 643 644 res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd); 645 if (res) { 646 if (res == -ENOENT || res == -ENODATA) 647 res = -ENODATA; 648 else 649 pr_err("xattr search failed\n"); 650 goto out; 651 } 652 653 hfs_bnode_read(fd.bnode, &xattr_record_type, 654 fd.entryoffset, sizeof(xattr_record_type)); 655 record_type = be32_to_cpu(xattr_record_type); 656 if (record_type == HFSPLUS_ATTR_INLINE_DATA) { 657 record_length = hfs_bnode_read_u16(fd.bnode, 658 fd.entryoffset + 659 offsetof(struct hfsplus_attr_inline_data, 660 length)); 661 if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) { 662 pr_err("invalid xattr record size\n"); 663 res = -EIO; 664 goto out; 665 } 666 } else if (record_type == HFSPLUS_ATTR_FORK_DATA || 667 record_type == HFSPLUS_ATTR_EXTENTS) { 668 pr_err("only inline data xattr are supported\n"); 669 res = -EOPNOTSUPP; 670 goto out; 671 } else { 672 pr_err("invalid xattr record\n"); 673 res = -EIO; 674 goto out; 675 } 676 677 if (size) { 678 hfs_bnode_read(fd.bnode, entry, fd.entryoffset, 679 offsetof(struct hfsplus_attr_inline_data, 680 raw_bytes) + record_length); 681 } 682 683 if (size >= record_length) { 684 memcpy(value, entry->inline_data.raw_bytes, record_length); 685 res = record_length; 686 } else 687 res = size ? -ERANGE : record_length; 688 689 out: 690 hfs_find_exit(&fd); 691 692 failed_getxattr_init: 693 hfsplus_destroy_attr_entry(entry); 694 return res; 695 } 696 697 ssize_t hfsplus_getxattr(struct inode *inode, const char *name, 698 void *value, size_t size, 699 const char *prefix, size_t prefixlen) 700 { 701 int res; 702 char *xattr_name; 703 704 hfs_dbg("ino %llu, name %s, prefix %s\n", 705 inode->i_ino, name ? name : NULL, 706 prefix ? prefix : NULL); 707 708 xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, 709 GFP_KERNEL); 710 if (!xattr_name) 711 return -ENOMEM; 712 713 strcpy(xattr_name, prefix); 714 strcpy(xattr_name + prefixlen, name); 715 716 res = __hfsplus_getxattr(inode, xattr_name, value, size); 717 kfree(xattr_name); 718 719 hfs_dbg("finished: res %d\n", res); 720 721 return res; 722 723 } 724 725 static inline int can_list(const char *xattr_name) 726 { 727 if (!xattr_name) 728 return 0; 729 730 return strncmp(xattr_name, XATTR_TRUSTED_PREFIX, 731 XATTR_TRUSTED_PREFIX_LEN) || 732 capable(CAP_SYS_ADMIN); 733 } 734 735 static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry, 736 char *buffer, size_t size) 737 { 738 ssize_t res; 739 struct inode *inode = d_inode(dentry); 740 struct hfs_find_data fd; 741 u16 entry_type; 742 u8 folder_finder_info[sizeof(DInfo) + sizeof(DXInfo)]; 743 u8 file_finder_info[sizeof(FInfo) + sizeof(FXInfo)]; 744 unsigned long len, found_bit; 745 int xattr_name_len, symbols_count; 746 747 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 748 if (res) { 749 pr_err("can't init xattr find struct\n"); 750 return res; 751 } 752 753 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 754 if (res) 755 goto end_listxattr_finder_info; 756 757 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 758 if (entry_type == HFSPLUS_FOLDER) { 759 len = sizeof(DInfo) + sizeof(DXInfo); 760 hfs_bnode_read(fd.bnode, folder_finder_info, 761 fd.entryoffset + 762 offsetof(struct hfsplus_cat_folder, user_info), 763 len); 764 found_bit = find_first_bit((void *)folder_finder_info, len*8); 765 } else if (entry_type == HFSPLUS_FILE) { 766 len = sizeof(FInfo) + sizeof(FXInfo); 767 hfs_bnode_read(fd.bnode, file_finder_info, 768 fd.entryoffset + 769 offsetof(struct hfsplus_cat_file, user_info), 770 len); 771 found_bit = find_first_bit((void *)file_finder_info, len*8); 772 } else { 773 res = -EOPNOTSUPP; 774 goto end_listxattr_finder_info; 775 } 776 777 if (found_bit >= (len*8)) 778 res = 0; 779 else { 780 symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1; 781 xattr_name_len = 782 name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count); 783 if (!buffer || !size) { 784 if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) 785 res = xattr_name_len; 786 } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) { 787 if (size < xattr_name_len) 788 res = -ERANGE; 789 else { 790 res = copy_name(buffer, 791 HFSPLUS_XATTR_FINDER_INFO_NAME, 792 symbols_count); 793 } 794 } 795 } 796 797 end_listxattr_finder_info: 798 hfs_find_exit(&fd); 799 800 return res; 801 } 802 803 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) 804 { 805 ssize_t err; 806 ssize_t res; 807 struct inode *inode = d_inode(dentry); 808 struct hfs_find_data fd; 809 struct hfsplus_attr_key attr_key; 810 char *strbuf; 811 size_t strbuf_size; 812 int xattr_name_len; 813 814 hfs_dbg("ino %llu\n", inode->i_ino); 815 816 if (!is_xattr_operation_supported(inode)) 817 return -EOPNOTSUPP; 818 819 res = hfsplus_listxattr_finder_info(dentry, buffer, size); 820 if (res < 0) 821 return res; 822 else if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 823 return (res == 0) ? -EOPNOTSUPP : res; 824 825 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); 826 if (err) { 827 pr_err("can't init xattr find struct\n"); 828 return err; 829 } 830 831 strbuf_size = NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 832 XATTR_MAC_OSX_PREFIX_LEN + 1; 833 strbuf = kzalloc(strbuf_size, GFP_KERNEL); 834 if (!strbuf) { 835 res = -ENOMEM; 836 goto out; 837 } 838 839 err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd); 840 if (err) { 841 if (err == -ENOENT || err == -ENODATA) { 842 res = 0; 843 goto end_listxattr; 844 } else { 845 res = err; 846 goto end_listxattr; 847 } 848 } 849 850 for (;;) { 851 u16 key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset); 852 853 if (key_len == 0 || key_len > fd.tree->max_key_len) { 854 pr_err("invalid xattr key length: %d\n", key_len); 855 res = -EIO; 856 goto end_listxattr; 857 } 858 859 hfs_bnode_read(fd.bnode, &attr_key, 860 fd.keyoffset, key_len + sizeof(key_len)); 861 862 if (be32_to_cpu(attr_key.cnid) != inode->i_ino) 863 goto end_listxattr; 864 865 xattr_name_len = NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN; 866 if (hfsplus_uni2asc_xattr_str(inode->i_sb, 867 &fd.key->attr.key_name, strbuf, 868 &xattr_name_len)) { 869 pr_err("unicode conversion failed\n"); 870 res = -EIO; 871 goto end_listxattr; 872 } 873 874 if (!buffer || !size) { 875 if (can_list(strbuf)) 876 res += name_len(strbuf, xattr_name_len); 877 } else if (can_list(strbuf)) { 878 if (size < (res + name_len(strbuf, xattr_name_len))) { 879 pr_err("size %zu, res %zd, name_len %zu\n", 880 size, res, 881 name_len(strbuf, xattr_name_len)); 882 res = -ERANGE; 883 goto end_listxattr; 884 } else 885 res += copy_name(buffer + res, 886 strbuf, xattr_name_len); 887 } 888 889 memset(fd.key->attr.key_name.unicode, 0, 890 sizeof(fd.key->attr.key_name.unicode)); 891 memset(strbuf, 0, strbuf_size); 892 893 if (hfs_brec_goto(&fd, 1)) 894 goto end_listxattr; 895 } 896 897 end_listxattr: 898 kfree(strbuf); 899 out: 900 hfs_find_exit(&fd); 901 902 hfs_dbg("finished: res %zd\n", res); 903 904 return res; 905 } 906 907 static int hfsplus_removexattr(struct inode *inode, const char *name) 908 { 909 int err; 910 struct hfs_find_data cat_fd; 911 u16 flags; 912 u16 cat_entry_type; 913 int is_xattr_acl_deleted; 914 int is_all_xattrs_deleted; 915 916 hfs_dbg("ino %llu, name %s\n", 917 inode->i_ino, name ? name : NULL); 918 919 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 920 return -EOPNOTSUPP; 921 922 if (!strcmp_xattr_finder_info(name)) 923 return -EOPNOTSUPP; 924 925 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); 926 if (err) { 927 pr_err("can't init xattr find struct\n"); 928 return err; 929 } 930 931 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); 932 if (err) { 933 pr_err("catalog searching failed\n"); 934 goto end_removexattr; 935 } 936 937 err = hfsplus_delete_attr(inode, name); 938 if (err) 939 goto end_removexattr; 940 941 is_xattr_acl_deleted = !strcmp_xattr_acl(name); 942 is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL); 943 944 if (!is_xattr_acl_deleted && !is_all_xattrs_deleted) 945 goto end_removexattr; 946 947 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); 948 949 if (cat_entry_type == HFSPLUS_FOLDER) { 950 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + 951 offsetof(struct hfsplus_cat_folder, flags)); 952 if (is_xattr_acl_deleted) 953 flags &= ~HFSPLUS_ACL_EXISTS; 954 if (is_all_xattrs_deleted) 955 flags &= ~HFSPLUS_XATTR_EXISTS; 956 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 957 offsetof(struct hfsplus_cat_folder, flags), 958 flags); 959 hfsplus_mark_inode_dirty(HFSPLUS_CAT_TREE_I(inode->i_sb), 960 HFSPLUS_I_CAT_DIRTY); 961 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 962 } else if (cat_entry_type == HFSPLUS_FILE) { 963 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + 964 offsetof(struct hfsplus_cat_file, flags)); 965 if (is_xattr_acl_deleted) 966 flags &= ~HFSPLUS_ACL_EXISTS; 967 if (is_all_xattrs_deleted) 968 flags &= ~HFSPLUS_XATTR_EXISTS; 969 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 970 offsetof(struct hfsplus_cat_file, flags), 971 flags); 972 hfsplus_mark_inode_dirty(HFSPLUS_CAT_TREE_I(inode->i_sb), 973 HFSPLUS_I_CAT_DIRTY); 974 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 975 } else { 976 pr_err("invalid catalog entry type\n"); 977 err = -EIO; 978 goto end_removexattr; 979 } 980 981 inode_set_ctime_current(inode); 982 983 end_removexattr: 984 hfs_find_exit(&cat_fd); 985 986 hfs_dbg("finished: err %d\n", err); 987 988 return err; 989 } 990 991 static int hfsplus_osx_getxattr(const struct xattr_handler *handler, 992 struct dentry *unused, struct inode *inode, 993 const char *name, void *buffer, size_t size) 994 { 995 /* 996 * Don't allow retrieving properly prefixed attributes 997 * by prepending them with "osx." 998 */ 999 if (is_known_namespace(name)) 1000 return -EOPNOTSUPP; 1001 1002 /* 1003 * osx is the namespace we use to indicate an unprefixed 1004 * attribute on the filesystem (like the ones that OS X 1005 * creates), so we pass the name through unmodified (after 1006 * ensuring it doesn't conflict with another namespace). 1007 */ 1008 return __hfsplus_getxattr(inode, name, buffer, size); 1009 } 1010 1011 static int hfsplus_osx_setxattr(const struct xattr_handler *handler, 1012 struct mnt_idmap *idmap, 1013 struct dentry *unused, struct inode *inode, 1014 const char *name, const void *buffer, 1015 size_t size, int flags) 1016 { 1017 /* 1018 * Don't allow setting properly prefixed attributes 1019 * by prepending them with "osx." 1020 */ 1021 if (is_known_namespace(name)) 1022 return -EOPNOTSUPP; 1023 1024 /* 1025 * osx is the namespace we use to indicate an unprefixed 1026 * attribute on the filesystem (like the ones that OS X 1027 * creates), so we pass the name through unmodified (after 1028 * ensuring it doesn't conflict with another namespace). 1029 */ 1030 return __hfsplus_setxattr(inode, name, buffer, size, flags); 1031 } 1032 1033 const struct xattr_handler hfsplus_xattr_osx_handler = { 1034 .prefix = XATTR_MAC_OSX_PREFIX, 1035 .get = hfsplus_osx_getxattr, 1036 .set = hfsplus_osx_setxattr, 1037 }; 1038