xattr.c (23815B)
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 14static int hfsplus_removexattr(struct inode *inode, const char *name); 15 16const struct xattr_handler *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 24static 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 33static 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 42static 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 53static 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(ATTR_MOD, "init_hdr_attr_file: 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 121static 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(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID); 136 137check_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 BUG_ON(i_size_read(attr_file) != 0); 176 177 hip = HFSPLUS_I(attr_file); 178 179 clump_size = hfsplus_calc_btree_clump_size(sb->s_blocksize, 180 node_size, 181 sbi->sect_count, 182 HFSPLUS_ATTR_CNID); 183 184 mutex_lock(&hip->extents_lock); 185 hip->clump_blocks = clump_size >> sbi->alloc_blksz_shift; 186 mutex_unlock(&hip->extents_lock); 187 188 if (sbi->free_blocks <= (hip->clump_blocks << 1)) { 189 err = -ENOSPC; 190 goto end_attr_file_creation; 191 } 192 193 while (hip->alloc_blocks < hip->clump_blocks) { 194 err = hfsplus_file_extend(attr_file, false); 195 if (unlikely(err)) { 196 pr_err("failed to extend attributes file\n"); 197 goto end_attr_file_creation; 198 } 199 hip->phys_size = attr_file->i_size = 200 (loff_t)hip->alloc_blocks << sbi->alloc_blksz_shift; 201 hip->fs_blocks = hip->alloc_blocks << sbi->fs_shift; 202 inode_set_bytes(attr_file, attr_file->i_size); 203 } 204 205 buf = kzalloc(node_size, GFP_NOFS); 206 if (!buf) { 207 err = -ENOMEM; 208 goto end_attr_file_creation; 209 } 210 211 hfsplus_init_header_node(attr_file, clump_size, buf, node_size); 212 213 mapping = attr_file->i_mapping; 214 215 index = 0; 216 written = 0; 217 for (; written < node_size; index++, written += PAGE_SIZE) { 218 void *kaddr; 219 220 page = read_mapping_page(mapping, index, NULL); 221 if (IS_ERR(page)) { 222 err = PTR_ERR(page); 223 goto failed_header_node_init; 224 } 225 226 kaddr = kmap_atomic(page); 227 memcpy(kaddr, buf + written, 228 min_t(size_t, PAGE_SIZE, node_size - written)); 229 kunmap_atomic(kaddr); 230 231 set_page_dirty(page); 232 put_page(page); 233 } 234 235 hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY); 236 237 sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID); 238 if (!sbi->attr_tree) 239 pr_err("failed to load attributes file\n"); 240 241failed_header_node_init: 242 kfree(buf); 243 244end_attr_file_creation: 245 iput(attr_file); 246 247 if (!err) 248 atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE); 249 else if (err == -ENOSPC) 250 atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE); 251 else 252 atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE); 253 254 return err; 255} 256 257int __hfsplus_setxattr(struct inode *inode, const char *name, 258 const void *value, size_t size, int flags) 259{ 260 int err = 0; 261 struct hfs_find_data cat_fd; 262 hfsplus_cat_entry entry; 263 u16 cat_entry_flags, cat_entry_type; 264 u16 folder_finderinfo_len = sizeof(struct DInfo) + 265 sizeof(struct DXInfo); 266 u16 file_finderinfo_len = sizeof(struct FInfo) + 267 sizeof(struct FXInfo); 268 269 if ((!S_ISREG(inode->i_mode) && 270 !S_ISDIR(inode->i_mode)) || 271 HFSPLUS_IS_RSRC(inode)) 272 return -EOPNOTSUPP; 273 274 if (value == NULL) 275 return hfsplus_removexattr(inode, name); 276 277 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); 278 if (err) { 279 pr_err("can't init xattr find struct\n"); 280 return err; 281 } 282 283 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); 284 if (err) { 285 pr_err("catalog searching failed\n"); 286 goto end_setxattr; 287 } 288 289 if (!strcmp_xattr_finder_info(name)) { 290 if (flags & XATTR_CREATE) { 291 pr_err("xattr exists yet\n"); 292 err = -EOPNOTSUPP; 293 goto end_setxattr; 294 } 295 hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset, 296 sizeof(hfsplus_cat_entry)); 297 if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) { 298 if (size == folder_finderinfo_len) { 299 memcpy(&entry.folder.info, value, 300 folder_finderinfo_len); 301 hfs_bnode_write(cat_fd.bnode, &entry, 302 cat_fd.entryoffset, 303 sizeof(struct hfsplus_cat_folder)); 304 hfsplus_mark_inode_dirty(inode, 305 HFSPLUS_I_CAT_DIRTY); 306 } else { 307 err = -ERANGE; 308 goto end_setxattr; 309 } 310 } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) { 311 if (size == file_finderinfo_len) { 312 memcpy(&entry.file.info, value, 313 file_finderinfo_len); 314 hfs_bnode_write(cat_fd.bnode, &entry, 315 cat_fd.entryoffset, 316 sizeof(struct hfsplus_cat_file)); 317 hfsplus_mark_inode_dirty(inode, 318 HFSPLUS_I_CAT_DIRTY); 319 } else { 320 err = -ERANGE; 321 goto end_setxattr; 322 } 323 } else { 324 err = -EOPNOTSUPP; 325 goto end_setxattr; 326 } 327 goto end_setxattr; 328 } 329 330 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) { 331 err = hfsplus_create_attributes_file(inode->i_sb); 332 if (unlikely(err)) 333 goto end_setxattr; 334 } 335 336 if (hfsplus_attr_exists(inode, name)) { 337 if (flags & XATTR_CREATE) { 338 pr_err("xattr exists yet\n"); 339 err = -EOPNOTSUPP; 340 goto end_setxattr; 341 } 342 err = hfsplus_delete_attr(inode, name); 343 if (err) 344 goto end_setxattr; 345 err = hfsplus_create_attr(inode, name, value, size); 346 if (err) 347 goto end_setxattr; 348 } else { 349 if (flags & XATTR_REPLACE) { 350 pr_err("cannot replace xattr\n"); 351 err = -EOPNOTSUPP; 352 goto end_setxattr; 353 } 354 err = hfsplus_create_attr(inode, name, value, size); 355 if (err) 356 goto end_setxattr; 357 } 358 359 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); 360 if (cat_entry_type == HFSPLUS_FOLDER) { 361 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, 362 cat_fd.entryoffset + 363 offsetof(struct hfsplus_cat_folder, flags)); 364 cat_entry_flags |= HFSPLUS_XATTR_EXISTS; 365 if (!strcmp_xattr_acl(name)) 366 cat_entry_flags |= HFSPLUS_ACL_EXISTS; 367 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 368 offsetof(struct hfsplus_cat_folder, flags), 369 cat_entry_flags); 370 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 371 } else if (cat_entry_type == HFSPLUS_FILE) { 372 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, 373 cat_fd.entryoffset + 374 offsetof(struct hfsplus_cat_file, flags)); 375 cat_entry_flags |= HFSPLUS_XATTR_EXISTS; 376 if (!strcmp_xattr_acl(name)) 377 cat_entry_flags |= HFSPLUS_ACL_EXISTS; 378 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 379 offsetof(struct hfsplus_cat_file, flags), 380 cat_entry_flags); 381 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 382 } else { 383 pr_err("invalid catalog entry type\n"); 384 err = -EIO; 385 goto end_setxattr; 386 } 387 388end_setxattr: 389 hfs_find_exit(&cat_fd); 390 return err; 391} 392 393static int name_len(const char *xattr_name, int xattr_name_len) 394{ 395 int len = xattr_name_len + 1; 396 397 if (!is_known_namespace(xattr_name)) 398 len += XATTR_MAC_OSX_PREFIX_LEN; 399 400 return len; 401} 402 403static int copy_name(char *buffer, const char *xattr_name, int name_len) 404{ 405 int len = name_len; 406 int offset = 0; 407 408 if (!is_known_namespace(xattr_name)) { 409 memcpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN); 410 offset += XATTR_MAC_OSX_PREFIX_LEN; 411 len += XATTR_MAC_OSX_PREFIX_LEN; 412 } 413 414 strncpy(buffer + offset, xattr_name, name_len); 415 memset(buffer + offset + name_len, 0, 1); 416 len += 1; 417 418 return len; 419} 420 421int hfsplus_setxattr(struct inode *inode, const char *name, 422 const void *value, size_t size, int flags, 423 const char *prefix, size_t prefixlen) 424{ 425 char *xattr_name; 426 int res; 427 428 xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, 429 GFP_KERNEL); 430 if (!xattr_name) 431 return -ENOMEM; 432 strcpy(xattr_name, prefix); 433 strcpy(xattr_name + prefixlen, name); 434 res = __hfsplus_setxattr(inode, xattr_name, value, size, flags); 435 kfree(xattr_name); 436 return res; 437} 438 439static ssize_t hfsplus_getxattr_finder_info(struct inode *inode, 440 void *value, size_t size) 441{ 442 ssize_t res = 0; 443 struct hfs_find_data fd; 444 u16 entry_type; 445 u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo); 446 u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo); 447 u16 record_len = max(folder_rec_len, file_rec_len); 448 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; 449 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; 450 451 if (size >= record_len) { 452 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 453 if (res) { 454 pr_err("can't init xattr find struct\n"); 455 return res; 456 } 457 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 458 if (res) 459 goto end_getxattr_finder_info; 460 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 461 462 if (entry_type == HFSPLUS_FOLDER) { 463 hfs_bnode_read(fd.bnode, folder_finder_info, 464 fd.entryoffset + 465 offsetof(struct hfsplus_cat_folder, user_info), 466 folder_rec_len); 467 memcpy(value, folder_finder_info, folder_rec_len); 468 res = folder_rec_len; 469 } else if (entry_type == HFSPLUS_FILE) { 470 hfs_bnode_read(fd.bnode, file_finder_info, 471 fd.entryoffset + 472 offsetof(struct hfsplus_cat_file, user_info), 473 file_rec_len); 474 memcpy(value, file_finder_info, file_rec_len); 475 res = file_rec_len; 476 } else { 477 res = -EOPNOTSUPP; 478 goto end_getxattr_finder_info; 479 } 480 } else 481 res = size ? -ERANGE : record_len; 482 483end_getxattr_finder_info: 484 if (size >= record_len) 485 hfs_find_exit(&fd); 486 return res; 487} 488 489ssize_t __hfsplus_getxattr(struct inode *inode, const char *name, 490 void *value, size_t size) 491{ 492 struct hfs_find_data fd; 493 hfsplus_attr_entry *entry; 494 __be32 xattr_record_type; 495 u32 record_type; 496 u16 record_length = 0; 497 ssize_t res = 0; 498 499 if ((!S_ISREG(inode->i_mode) && 500 !S_ISDIR(inode->i_mode)) || 501 HFSPLUS_IS_RSRC(inode)) 502 return -EOPNOTSUPP; 503 504 if (!strcmp_xattr_finder_info(name)) 505 return hfsplus_getxattr_finder_info(inode, value, size); 506 507 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 508 return -EOPNOTSUPP; 509 510 entry = hfsplus_alloc_attr_entry(); 511 if (!entry) { 512 pr_err("can't allocate xattr entry\n"); 513 return -ENOMEM; 514 } 515 516 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); 517 if (res) { 518 pr_err("can't init xattr find struct\n"); 519 goto failed_getxattr_init; 520 } 521 522 res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd); 523 if (res) { 524 if (res == -ENOENT) 525 res = -ENODATA; 526 else 527 pr_err("xattr searching failed\n"); 528 goto out; 529 } 530 531 hfs_bnode_read(fd.bnode, &xattr_record_type, 532 fd.entryoffset, sizeof(xattr_record_type)); 533 record_type = be32_to_cpu(xattr_record_type); 534 if (record_type == HFSPLUS_ATTR_INLINE_DATA) { 535 record_length = hfs_bnode_read_u16(fd.bnode, 536 fd.entryoffset + 537 offsetof(struct hfsplus_attr_inline_data, 538 length)); 539 if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) { 540 pr_err("invalid xattr record size\n"); 541 res = -EIO; 542 goto out; 543 } 544 } else if (record_type == HFSPLUS_ATTR_FORK_DATA || 545 record_type == HFSPLUS_ATTR_EXTENTS) { 546 pr_err("only inline data xattr are supported\n"); 547 res = -EOPNOTSUPP; 548 goto out; 549 } else { 550 pr_err("invalid xattr record\n"); 551 res = -EIO; 552 goto out; 553 } 554 555 if (size) { 556 hfs_bnode_read(fd.bnode, entry, fd.entryoffset, 557 offsetof(struct hfsplus_attr_inline_data, 558 raw_bytes) + record_length); 559 } 560 561 if (size >= record_length) { 562 memcpy(value, entry->inline_data.raw_bytes, record_length); 563 res = record_length; 564 } else 565 res = size ? -ERANGE : record_length; 566 567out: 568 hfs_find_exit(&fd); 569 570failed_getxattr_init: 571 hfsplus_destroy_attr_entry(entry); 572 return res; 573} 574 575ssize_t hfsplus_getxattr(struct inode *inode, const char *name, 576 void *value, size_t size, 577 const char *prefix, size_t prefixlen) 578{ 579 int res; 580 char *xattr_name; 581 582 xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1, 583 GFP_KERNEL); 584 if (!xattr_name) 585 return -ENOMEM; 586 587 strcpy(xattr_name, prefix); 588 strcpy(xattr_name + prefixlen, name); 589 590 res = __hfsplus_getxattr(inode, xattr_name, value, size); 591 kfree(xattr_name); 592 return res; 593 594} 595 596static inline int can_list(const char *xattr_name) 597{ 598 if (!xattr_name) 599 return 0; 600 601 return strncmp(xattr_name, XATTR_TRUSTED_PREFIX, 602 XATTR_TRUSTED_PREFIX_LEN) || 603 capable(CAP_SYS_ADMIN); 604} 605 606static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry, 607 char *buffer, size_t size) 608{ 609 ssize_t res = 0; 610 struct inode *inode = d_inode(dentry); 611 struct hfs_find_data fd; 612 u16 entry_type; 613 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; 614 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; 615 unsigned long len, found_bit; 616 int xattr_name_len, symbols_count; 617 618 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 619 if (res) { 620 pr_err("can't init xattr find struct\n"); 621 return res; 622 } 623 624 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 625 if (res) 626 goto end_listxattr_finder_info; 627 628 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 629 if (entry_type == HFSPLUS_FOLDER) { 630 len = sizeof(struct DInfo) + sizeof(struct DXInfo); 631 hfs_bnode_read(fd.bnode, folder_finder_info, 632 fd.entryoffset + 633 offsetof(struct hfsplus_cat_folder, user_info), 634 len); 635 found_bit = find_first_bit((void *)folder_finder_info, len*8); 636 } else if (entry_type == HFSPLUS_FILE) { 637 len = sizeof(struct FInfo) + sizeof(struct FXInfo); 638 hfs_bnode_read(fd.bnode, file_finder_info, 639 fd.entryoffset + 640 offsetof(struct hfsplus_cat_file, user_info), 641 len); 642 found_bit = find_first_bit((void *)file_finder_info, len*8); 643 } else { 644 res = -EOPNOTSUPP; 645 goto end_listxattr_finder_info; 646 } 647 648 if (found_bit >= (len*8)) 649 res = 0; 650 else { 651 symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1; 652 xattr_name_len = 653 name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count); 654 if (!buffer || !size) { 655 if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) 656 res = xattr_name_len; 657 } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) { 658 if (size < xattr_name_len) 659 res = -ERANGE; 660 else { 661 res = copy_name(buffer, 662 HFSPLUS_XATTR_FINDER_INFO_NAME, 663 symbols_count); 664 } 665 } 666 } 667 668end_listxattr_finder_info: 669 hfs_find_exit(&fd); 670 671 return res; 672} 673 674ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) 675{ 676 ssize_t err; 677 ssize_t res = 0; 678 struct inode *inode = d_inode(dentry); 679 struct hfs_find_data fd; 680 u16 key_len = 0; 681 struct hfsplus_attr_key attr_key; 682 char *strbuf; 683 int xattr_name_len; 684 685 if ((!S_ISREG(inode->i_mode) && 686 !S_ISDIR(inode->i_mode)) || 687 HFSPLUS_IS_RSRC(inode)) 688 return -EOPNOTSUPP; 689 690 res = hfsplus_listxattr_finder_info(dentry, buffer, size); 691 if (res < 0) 692 return res; 693 else if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 694 return (res == 0) ? -EOPNOTSUPP : res; 695 696 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); 697 if (err) { 698 pr_err("can't init xattr find struct\n"); 699 return err; 700 } 701 702 strbuf = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 703 XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL); 704 if (!strbuf) { 705 res = -ENOMEM; 706 goto out; 707 } 708 709 err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd); 710 if (err) { 711 if (err == -ENOENT) { 712 if (res == 0) 713 res = -ENODATA; 714 goto end_listxattr; 715 } else { 716 res = err; 717 goto end_listxattr; 718 } 719 } 720 721 for (;;) { 722 key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset); 723 if (key_len == 0 || key_len > fd.tree->max_key_len) { 724 pr_err("invalid xattr key length: %d\n", key_len); 725 res = -EIO; 726 goto end_listxattr; 727 } 728 729 hfs_bnode_read(fd.bnode, &attr_key, 730 fd.keyoffset, key_len + sizeof(key_len)); 731 732 if (be32_to_cpu(attr_key.cnid) != inode->i_ino) 733 goto end_listxattr; 734 735 xattr_name_len = NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN; 736 if (hfsplus_uni2asc(inode->i_sb, 737 (const struct hfsplus_unistr *)&fd.key->attr.key_name, 738 strbuf, &xattr_name_len)) { 739 pr_err("unicode conversion failed\n"); 740 res = -EIO; 741 goto end_listxattr; 742 } 743 744 if (!buffer || !size) { 745 if (can_list(strbuf)) 746 res += name_len(strbuf, xattr_name_len); 747 } else if (can_list(strbuf)) { 748 if (size < (res + name_len(strbuf, xattr_name_len))) { 749 res = -ERANGE; 750 goto end_listxattr; 751 } else 752 res += copy_name(buffer + res, 753 strbuf, xattr_name_len); 754 } 755 756 if (hfs_brec_goto(&fd, 1)) 757 goto end_listxattr; 758 } 759 760end_listxattr: 761 kfree(strbuf); 762out: 763 hfs_find_exit(&fd); 764 return res; 765} 766 767static int hfsplus_removexattr(struct inode *inode, const char *name) 768{ 769 int err = 0; 770 struct hfs_find_data cat_fd; 771 u16 flags; 772 u16 cat_entry_type; 773 int is_xattr_acl_deleted = 0; 774 int is_all_xattrs_deleted = 0; 775 776 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 777 return -EOPNOTSUPP; 778 779 if (!strcmp_xattr_finder_info(name)) 780 return -EOPNOTSUPP; 781 782 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); 783 if (err) { 784 pr_err("can't init xattr find struct\n"); 785 return err; 786 } 787 788 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); 789 if (err) { 790 pr_err("catalog searching failed\n"); 791 goto end_removexattr; 792 } 793 794 err = hfsplus_delete_attr(inode, name); 795 if (err) 796 goto end_removexattr; 797 798 is_xattr_acl_deleted = !strcmp_xattr_acl(name); 799 is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL); 800 801 if (!is_xattr_acl_deleted && !is_all_xattrs_deleted) 802 goto end_removexattr; 803 804 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); 805 806 if (cat_entry_type == HFSPLUS_FOLDER) { 807 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + 808 offsetof(struct hfsplus_cat_folder, flags)); 809 if (is_xattr_acl_deleted) 810 flags &= ~HFSPLUS_ACL_EXISTS; 811 if (is_all_xattrs_deleted) 812 flags &= ~HFSPLUS_XATTR_EXISTS; 813 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 814 offsetof(struct hfsplus_cat_folder, flags), 815 flags); 816 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 817 } else if (cat_entry_type == HFSPLUS_FILE) { 818 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + 819 offsetof(struct hfsplus_cat_file, flags)); 820 if (is_xattr_acl_deleted) 821 flags &= ~HFSPLUS_ACL_EXISTS; 822 if (is_all_xattrs_deleted) 823 flags &= ~HFSPLUS_XATTR_EXISTS; 824 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 825 offsetof(struct hfsplus_cat_file, flags), 826 flags); 827 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 828 } else { 829 pr_err("invalid catalog entry type\n"); 830 err = -EIO; 831 goto end_removexattr; 832 } 833 834end_removexattr: 835 hfs_find_exit(&cat_fd); 836 return err; 837} 838 839static int hfsplus_osx_getxattr(const struct xattr_handler *handler, 840 struct dentry *unused, struct inode *inode, 841 const char *name, void *buffer, size_t size) 842{ 843 /* 844 * Don't allow retrieving properly prefixed attributes 845 * by prepending them with "osx." 846 */ 847 if (is_known_namespace(name)) 848 return -EOPNOTSUPP; 849 850 /* 851 * osx is the namespace we use to indicate an unprefixed 852 * attribute on the filesystem (like the ones that OS X 853 * creates), so we pass the name through unmodified (after 854 * ensuring it doesn't conflict with another namespace). 855 */ 856 return __hfsplus_getxattr(inode, name, buffer, size); 857} 858 859static int hfsplus_osx_setxattr(const struct xattr_handler *handler, 860 struct user_namespace *mnt_userns, 861 struct dentry *unused, struct inode *inode, 862 const char *name, const void *buffer, 863 size_t size, int flags) 864{ 865 /* 866 * Don't allow setting properly prefixed attributes 867 * by prepending them with "osx." 868 */ 869 if (is_known_namespace(name)) 870 return -EOPNOTSUPP; 871 872 /* 873 * osx is the namespace we use to indicate an unprefixed 874 * attribute on the filesystem (like the ones that OS X 875 * creates), so we pass the name through unmodified (after 876 * ensuring it doesn't conflict with another namespace). 877 */ 878 return __hfsplus_setxattr(inode, name, buffer, size, flags); 879} 880 881const struct xattr_handler hfsplus_xattr_osx_handler = { 882 .prefix = XATTR_MAC_OSX_PREFIX, 883 .get = hfsplus_osx_getxattr, 884 .set = hfsplus_osx_setxattr, 885};