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