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