1 /* 2 * linux/fs/hfsplus/xattr.c 3 * 4 * Vyacheslav Dubeyko <slava@dubeyko.com> 5 * 6 * Logic of processing extended attributes 7 */ 8 9 #include "hfsplus_fs.h" 10 #include "xattr.h" 11 #include "acl.h" 12 13 const struct xattr_handler *hfsplus_xattr_handlers[] = { 14 &hfsplus_xattr_osx_handler, 15 &hfsplus_xattr_user_handler, 16 &hfsplus_xattr_trusted_handler, 17 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL 18 &hfsplus_xattr_acl_access_handler, 19 &hfsplus_xattr_acl_default_handler, 20 #endif 21 &hfsplus_xattr_security_handler, 22 NULL 23 }; 24 25 static int strcmp_xattr_finder_info(const char *name) 26 { 27 if (name) { 28 return strncmp(name, HFSPLUS_XATTR_FINDER_INFO_NAME, 29 sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME)); 30 } 31 return -1; 32 } 33 34 static int strcmp_xattr_acl(const char *name) 35 { 36 if (name) { 37 return strncmp(name, HFSPLUS_XATTR_ACL_NAME, 38 sizeof(HFSPLUS_XATTR_ACL_NAME)); 39 } 40 return -1; 41 } 42 43 static inline int is_known_namespace(const char *name) 44 { 45 if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) && 46 strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && 47 strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && 48 strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) 49 return false; 50 51 return true; 52 } 53 54 static int can_set_system_xattr(struct inode *inode, const char *name, 55 const void *value, size_t size) 56 { 57 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL 58 struct posix_acl *acl; 59 int err; 60 61 if (!inode_owner_or_capable(inode)) 62 return -EPERM; 63 64 /* 65 * POSIX_ACL_XATTR_ACCESS is tied to i_mode 66 */ 67 if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) { 68 acl = posix_acl_from_xattr(&init_user_ns, value, size); 69 if (IS_ERR(acl)) 70 return PTR_ERR(acl); 71 if (acl) { 72 err = posix_acl_equiv_mode(acl, &inode->i_mode); 73 posix_acl_release(acl); 74 if (err < 0) 75 return err; 76 mark_inode_dirty(inode); 77 } 78 /* 79 * We're changing the ACL. Get rid of the cached one 80 */ 81 forget_cached_acl(inode, ACL_TYPE_ACCESS); 82 83 return 0; 84 } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { 85 acl = posix_acl_from_xattr(&init_user_ns, value, size); 86 if (IS_ERR(acl)) 87 return PTR_ERR(acl); 88 posix_acl_release(acl); 89 90 /* 91 * We're changing the default ACL. Get rid of the cached one 92 */ 93 forget_cached_acl(inode, ACL_TYPE_DEFAULT); 94 95 return 0; 96 } 97 #endif /* CONFIG_HFSPLUS_FS_POSIX_ACL */ 98 return -EOPNOTSUPP; 99 } 100 101 static int can_set_xattr(struct inode *inode, const char *name, 102 const void *value, size_t value_len) 103 { 104 if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) 105 return can_set_system_xattr(inode, name, value, value_len); 106 107 if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) { 108 /* 109 * This makes sure that we aren't trying to set an 110 * attribute in a different namespace by prefixing it 111 * with "osx." 112 */ 113 if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN)) 114 return -EOPNOTSUPP; 115 116 return 0; 117 } 118 119 /* 120 * Don't allow setting an attribute in an unknown namespace. 121 */ 122 if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && 123 strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && 124 strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) 125 return -EOPNOTSUPP; 126 127 return 0; 128 } 129 130 int __hfsplus_setxattr(struct inode *inode, const char *name, 131 const void *value, size_t size, int flags) 132 { 133 int err = 0; 134 struct hfs_find_data cat_fd; 135 hfsplus_cat_entry entry; 136 u16 cat_entry_flags, cat_entry_type; 137 u16 folder_finderinfo_len = sizeof(struct DInfo) + 138 sizeof(struct DXInfo); 139 u16 file_finderinfo_len = sizeof(struct FInfo) + 140 sizeof(struct FXInfo); 141 142 if ((!S_ISREG(inode->i_mode) && 143 !S_ISDIR(inode->i_mode)) || 144 HFSPLUS_IS_RSRC(inode)) 145 return -EOPNOTSUPP; 146 147 err = can_set_xattr(inode, name, value, size); 148 if (err) 149 return err; 150 151 if (strncmp(name, XATTR_MAC_OSX_PREFIX, 152 XATTR_MAC_OSX_PREFIX_LEN) == 0) 153 name += XATTR_MAC_OSX_PREFIX_LEN; 154 155 if (value == NULL) { 156 value = ""; 157 size = 0; 158 } 159 160 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); 161 if (err) { 162 pr_err("can't init xattr find struct\n"); 163 return err; 164 } 165 166 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); 167 if (err) { 168 pr_err("catalog searching failed\n"); 169 goto end_setxattr; 170 } 171 172 if (!strcmp_xattr_finder_info(name)) { 173 if (flags & XATTR_CREATE) { 174 pr_err("xattr exists yet\n"); 175 err = -EOPNOTSUPP; 176 goto end_setxattr; 177 } 178 hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset, 179 sizeof(hfsplus_cat_entry)); 180 if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) { 181 if (size == folder_finderinfo_len) { 182 memcpy(&entry.folder.user_info, value, 183 folder_finderinfo_len); 184 hfs_bnode_write(cat_fd.bnode, &entry, 185 cat_fd.entryoffset, 186 sizeof(struct hfsplus_cat_folder)); 187 hfsplus_mark_inode_dirty(inode, 188 HFSPLUS_I_CAT_DIRTY); 189 } else { 190 err = -ERANGE; 191 goto end_setxattr; 192 } 193 } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) { 194 if (size == file_finderinfo_len) { 195 memcpy(&entry.file.user_info, value, 196 file_finderinfo_len); 197 hfs_bnode_write(cat_fd.bnode, &entry, 198 cat_fd.entryoffset, 199 sizeof(struct hfsplus_cat_file)); 200 hfsplus_mark_inode_dirty(inode, 201 HFSPLUS_I_CAT_DIRTY); 202 } else { 203 err = -ERANGE; 204 goto end_setxattr; 205 } 206 } else { 207 err = -EOPNOTSUPP; 208 goto end_setxattr; 209 } 210 goto end_setxattr; 211 } 212 213 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) { 214 err = -EOPNOTSUPP; 215 goto end_setxattr; 216 } 217 218 if (hfsplus_attr_exists(inode, name)) { 219 if (flags & XATTR_CREATE) { 220 pr_err("xattr exists yet\n"); 221 err = -EOPNOTSUPP; 222 goto end_setxattr; 223 } 224 err = hfsplus_delete_attr(inode, name); 225 if (err) 226 goto end_setxattr; 227 err = hfsplus_create_attr(inode, name, value, size); 228 if (err) 229 goto end_setxattr; 230 } else { 231 if (flags & XATTR_REPLACE) { 232 pr_err("cannot replace xattr\n"); 233 err = -EOPNOTSUPP; 234 goto end_setxattr; 235 } 236 err = hfsplus_create_attr(inode, name, value, size); 237 if (err) 238 goto end_setxattr; 239 } 240 241 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); 242 if (cat_entry_type == HFSPLUS_FOLDER) { 243 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, 244 cat_fd.entryoffset + 245 offsetof(struct hfsplus_cat_folder, flags)); 246 cat_entry_flags |= HFSPLUS_XATTR_EXISTS; 247 if (!strcmp_xattr_acl(name)) 248 cat_entry_flags |= HFSPLUS_ACL_EXISTS; 249 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 250 offsetof(struct hfsplus_cat_folder, flags), 251 cat_entry_flags); 252 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 253 } else if (cat_entry_type == HFSPLUS_FILE) { 254 cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, 255 cat_fd.entryoffset + 256 offsetof(struct hfsplus_cat_file, flags)); 257 cat_entry_flags |= HFSPLUS_XATTR_EXISTS; 258 if (!strcmp_xattr_acl(name)) 259 cat_entry_flags |= HFSPLUS_ACL_EXISTS; 260 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 261 offsetof(struct hfsplus_cat_file, flags), 262 cat_entry_flags); 263 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 264 } else { 265 pr_err("invalid catalog entry type\n"); 266 err = -EIO; 267 goto end_setxattr; 268 } 269 270 end_setxattr: 271 hfs_find_exit(&cat_fd); 272 return err; 273 } 274 275 static inline int is_osx_xattr(const char *xattr_name) 276 { 277 return !is_known_namespace(xattr_name); 278 } 279 280 static int name_len(const char *xattr_name, int xattr_name_len) 281 { 282 int len = xattr_name_len + 1; 283 284 if (is_osx_xattr(xattr_name)) 285 len += XATTR_MAC_OSX_PREFIX_LEN; 286 287 return len; 288 } 289 290 static int copy_name(char *buffer, const char *xattr_name, int name_len) 291 { 292 int len = name_len; 293 int offset = 0; 294 295 if (is_osx_xattr(xattr_name)) { 296 strncpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN); 297 offset += XATTR_MAC_OSX_PREFIX_LEN; 298 len += XATTR_MAC_OSX_PREFIX_LEN; 299 } 300 301 strncpy(buffer + offset, xattr_name, name_len); 302 memset(buffer + offset + name_len, 0, 1); 303 len += 1; 304 305 return len; 306 } 307 308 static ssize_t hfsplus_getxattr_finder_info(struct inode *inode, 309 void *value, size_t size) 310 { 311 ssize_t res = 0; 312 struct hfs_find_data fd; 313 u16 entry_type; 314 u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo); 315 u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo); 316 u16 record_len = max(folder_rec_len, file_rec_len); 317 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; 318 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; 319 320 if (size >= record_len) { 321 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 322 if (res) { 323 pr_err("can't init xattr find struct\n"); 324 return res; 325 } 326 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 327 if (res) 328 goto end_getxattr_finder_info; 329 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 330 331 if (entry_type == HFSPLUS_FOLDER) { 332 hfs_bnode_read(fd.bnode, folder_finder_info, 333 fd.entryoffset + 334 offsetof(struct hfsplus_cat_folder, user_info), 335 folder_rec_len); 336 memcpy(value, folder_finder_info, folder_rec_len); 337 res = folder_rec_len; 338 } else if (entry_type == HFSPLUS_FILE) { 339 hfs_bnode_read(fd.bnode, file_finder_info, 340 fd.entryoffset + 341 offsetof(struct hfsplus_cat_file, user_info), 342 file_rec_len); 343 memcpy(value, file_finder_info, file_rec_len); 344 res = file_rec_len; 345 } else { 346 res = -EOPNOTSUPP; 347 goto end_getxattr_finder_info; 348 } 349 } else 350 res = size ? -ERANGE : record_len; 351 352 end_getxattr_finder_info: 353 if (size >= record_len) 354 hfs_find_exit(&fd); 355 return res; 356 } 357 358 ssize_t __hfsplus_getxattr(struct inode *inode, const char *name, 359 void *value, size_t size) 360 { 361 struct hfs_find_data fd; 362 hfsplus_attr_entry *entry; 363 __be32 xattr_record_type; 364 u32 record_type; 365 u16 record_length = 0; 366 ssize_t res = 0; 367 368 if ((!S_ISREG(inode->i_mode) && 369 !S_ISDIR(inode->i_mode)) || 370 HFSPLUS_IS_RSRC(inode)) 371 return -EOPNOTSUPP; 372 373 if (strncmp(name, XATTR_MAC_OSX_PREFIX, 374 XATTR_MAC_OSX_PREFIX_LEN) == 0) { 375 /* skip "osx." prefix */ 376 name += XATTR_MAC_OSX_PREFIX_LEN; 377 /* 378 * Don't allow retrieving properly prefixed attributes 379 * by prepending them with "osx." 380 */ 381 if (is_known_namespace(name)) 382 return -EOPNOTSUPP; 383 } 384 385 if (!strcmp_xattr_finder_info(name)) 386 return hfsplus_getxattr_finder_info(inode, value, size); 387 388 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 389 return -EOPNOTSUPP; 390 391 entry = hfsplus_alloc_attr_entry(); 392 if (!entry) { 393 pr_err("can't allocate xattr entry\n"); 394 return -ENOMEM; 395 } 396 397 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); 398 if (res) { 399 pr_err("can't init xattr find struct\n"); 400 goto failed_getxattr_init; 401 } 402 403 res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd); 404 if (res) { 405 if (res == -ENOENT) 406 res = -ENODATA; 407 else 408 pr_err("xattr searching failed\n"); 409 goto out; 410 } 411 412 hfs_bnode_read(fd.bnode, &xattr_record_type, 413 fd.entryoffset, sizeof(xattr_record_type)); 414 record_type = be32_to_cpu(xattr_record_type); 415 if (record_type == HFSPLUS_ATTR_INLINE_DATA) { 416 record_length = hfs_bnode_read_u16(fd.bnode, 417 fd.entryoffset + 418 offsetof(struct hfsplus_attr_inline_data, 419 length)); 420 if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) { 421 pr_err("invalid xattr record size\n"); 422 res = -EIO; 423 goto out; 424 } 425 } else if (record_type == HFSPLUS_ATTR_FORK_DATA || 426 record_type == HFSPLUS_ATTR_EXTENTS) { 427 pr_err("only inline data xattr are supported\n"); 428 res = -EOPNOTSUPP; 429 goto out; 430 } else { 431 pr_err("invalid xattr record\n"); 432 res = -EIO; 433 goto out; 434 } 435 436 if (size) { 437 hfs_bnode_read(fd.bnode, entry, fd.entryoffset, 438 offsetof(struct hfsplus_attr_inline_data, 439 raw_bytes) + record_length); 440 } 441 442 if (size >= record_length) { 443 memcpy(value, entry->inline_data.raw_bytes, record_length); 444 res = record_length; 445 } else 446 res = size ? -ERANGE : record_length; 447 448 out: 449 hfs_find_exit(&fd); 450 451 failed_getxattr_init: 452 hfsplus_destroy_attr_entry(entry); 453 return res; 454 } 455 456 static inline int can_list(const char *xattr_name) 457 { 458 if (!xattr_name) 459 return 0; 460 461 return strncmp(xattr_name, XATTR_TRUSTED_PREFIX, 462 XATTR_TRUSTED_PREFIX_LEN) || 463 capable(CAP_SYS_ADMIN); 464 } 465 466 static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry, 467 char *buffer, size_t size) 468 { 469 ssize_t res = 0; 470 struct inode *inode = dentry->d_inode; 471 struct hfs_find_data fd; 472 u16 entry_type; 473 u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; 474 u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; 475 unsigned long len, found_bit; 476 int xattr_name_len, symbols_count; 477 478 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 479 if (res) { 480 pr_err("can't init xattr find struct\n"); 481 return res; 482 } 483 484 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 485 if (res) 486 goto end_listxattr_finder_info; 487 488 entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 489 if (entry_type == HFSPLUS_FOLDER) { 490 len = sizeof(struct DInfo) + sizeof(struct DXInfo); 491 hfs_bnode_read(fd.bnode, folder_finder_info, 492 fd.entryoffset + 493 offsetof(struct hfsplus_cat_folder, user_info), 494 len); 495 found_bit = find_first_bit((void *)folder_finder_info, len*8); 496 } else if (entry_type == HFSPLUS_FILE) { 497 len = sizeof(struct FInfo) + sizeof(struct FXInfo); 498 hfs_bnode_read(fd.bnode, file_finder_info, 499 fd.entryoffset + 500 offsetof(struct hfsplus_cat_file, user_info), 501 len); 502 found_bit = find_first_bit((void *)file_finder_info, len*8); 503 } else { 504 res = -EOPNOTSUPP; 505 goto end_listxattr_finder_info; 506 } 507 508 if (found_bit >= (len*8)) 509 res = 0; 510 else { 511 symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1; 512 xattr_name_len = 513 name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count); 514 if (!buffer || !size) { 515 if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) 516 res = xattr_name_len; 517 } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) { 518 if (size < xattr_name_len) 519 res = -ERANGE; 520 else { 521 res = copy_name(buffer, 522 HFSPLUS_XATTR_FINDER_INFO_NAME, 523 symbols_count); 524 } 525 } 526 } 527 528 end_listxattr_finder_info: 529 hfs_find_exit(&fd); 530 531 return res; 532 } 533 534 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) 535 { 536 ssize_t err; 537 ssize_t res = 0; 538 struct inode *inode = dentry->d_inode; 539 struct hfs_find_data fd; 540 u16 key_len = 0; 541 struct hfsplus_attr_key attr_key; 542 char strbuf[HFSPLUS_ATTR_MAX_STRLEN + 543 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; 544 int xattr_name_len; 545 546 if ((!S_ISREG(inode->i_mode) && 547 !S_ISDIR(inode->i_mode)) || 548 HFSPLUS_IS_RSRC(inode)) 549 return -EOPNOTSUPP; 550 551 res = hfsplus_listxattr_finder_info(dentry, buffer, size); 552 if (res < 0) 553 return res; 554 else if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 555 return (res == 0) ? -EOPNOTSUPP : res; 556 557 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); 558 if (err) { 559 pr_err("can't init xattr find struct\n"); 560 return err; 561 } 562 563 err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd); 564 if (err) { 565 if (err == -ENOENT) { 566 if (res == 0) 567 res = -ENODATA; 568 goto end_listxattr; 569 } else { 570 res = err; 571 goto end_listxattr; 572 } 573 } 574 575 for (;;) { 576 key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset); 577 if (key_len == 0 || key_len > fd.tree->max_key_len) { 578 pr_err("invalid xattr key length: %d\n", key_len); 579 res = -EIO; 580 goto end_listxattr; 581 } 582 583 hfs_bnode_read(fd.bnode, &attr_key, 584 fd.keyoffset, key_len + sizeof(key_len)); 585 586 if (be32_to_cpu(attr_key.cnid) != inode->i_ino) 587 goto end_listxattr; 588 589 xattr_name_len = HFSPLUS_ATTR_MAX_STRLEN; 590 if (hfsplus_uni2asc(inode->i_sb, 591 (const struct hfsplus_unistr *)&fd.key->attr.key_name, 592 strbuf, &xattr_name_len)) { 593 pr_err("unicode conversion failed\n"); 594 res = -EIO; 595 goto end_listxattr; 596 } 597 598 if (!buffer || !size) { 599 if (can_list(strbuf)) 600 res += name_len(strbuf, xattr_name_len); 601 } else if (can_list(strbuf)) { 602 if (size < (res + name_len(strbuf, xattr_name_len))) { 603 res = -ERANGE; 604 goto end_listxattr; 605 } else 606 res += copy_name(buffer + res, 607 strbuf, xattr_name_len); 608 } 609 610 if (hfs_brec_goto(&fd, 1)) 611 goto end_listxattr; 612 } 613 614 end_listxattr: 615 hfs_find_exit(&fd); 616 return res; 617 } 618 619 int hfsplus_removexattr(struct dentry *dentry, const char *name) 620 { 621 int err = 0; 622 struct inode *inode = dentry->d_inode; 623 struct hfs_find_data cat_fd; 624 u16 flags; 625 u16 cat_entry_type; 626 int is_xattr_acl_deleted = 0; 627 int is_all_xattrs_deleted = 0; 628 629 if ((!S_ISREG(inode->i_mode) && 630 !S_ISDIR(inode->i_mode)) || 631 HFSPLUS_IS_RSRC(inode)) 632 return -EOPNOTSUPP; 633 634 if (!HFSPLUS_SB(inode->i_sb)->attr_tree) 635 return -EOPNOTSUPP; 636 637 err = can_set_xattr(inode, name, NULL, 0); 638 if (err) 639 return err; 640 641 if (strncmp(name, XATTR_MAC_OSX_PREFIX, 642 XATTR_MAC_OSX_PREFIX_LEN) == 0) 643 name += XATTR_MAC_OSX_PREFIX_LEN; 644 645 if (!strcmp_xattr_finder_info(name)) 646 return -EOPNOTSUPP; 647 648 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); 649 if (err) { 650 pr_err("can't init xattr find struct\n"); 651 return err; 652 } 653 654 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); 655 if (err) { 656 pr_err("catalog searching failed\n"); 657 goto end_removexattr; 658 } 659 660 err = hfsplus_delete_attr(inode, name); 661 if (err) 662 goto end_removexattr; 663 664 is_xattr_acl_deleted = !strcmp_xattr_acl(name); 665 is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL); 666 667 if (!is_xattr_acl_deleted && !is_all_xattrs_deleted) 668 goto end_removexattr; 669 670 cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); 671 672 if (cat_entry_type == HFSPLUS_FOLDER) { 673 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + 674 offsetof(struct hfsplus_cat_folder, flags)); 675 if (is_xattr_acl_deleted) 676 flags &= ~HFSPLUS_ACL_EXISTS; 677 if (is_all_xattrs_deleted) 678 flags &= ~HFSPLUS_XATTR_EXISTS; 679 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 680 offsetof(struct hfsplus_cat_folder, flags), 681 flags); 682 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 683 } else if (cat_entry_type == HFSPLUS_FILE) { 684 flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + 685 offsetof(struct hfsplus_cat_file, flags)); 686 if (is_xattr_acl_deleted) 687 flags &= ~HFSPLUS_ACL_EXISTS; 688 if (is_all_xattrs_deleted) 689 flags &= ~HFSPLUS_XATTR_EXISTS; 690 hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + 691 offsetof(struct hfsplus_cat_file, flags), 692 flags); 693 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 694 } else { 695 pr_err("invalid catalog entry type\n"); 696 err = -EIO; 697 goto end_removexattr; 698 } 699 700 end_removexattr: 701 hfs_find_exit(&cat_fd); 702 return err; 703 } 704 705 static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name, 706 void *buffer, size_t size, int type) 707 { 708 char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 709 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; 710 size_t len = strlen(name); 711 712 if (!strcmp(name, "")) 713 return -EINVAL; 714 715 if (len > HFSPLUS_ATTR_MAX_STRLEN) 716 return -EOPNOTSUPP; 717 718 strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); 719 strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); 720 721 return hfsplus_getxattr(dentry, xattr_name, buffer, size); 722 } 723 724 static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name, 725 const void *buffer, size_t size, int flags, int type) 726 { 727 char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 728 XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; 729 size_t len = strlen(name); 730 731 if (!strcmp(name, "")) 732 return -EINVAL; 733 734 if (len > HFSPLUS_ATTR_MAX_STRLEN) 735 return -EOPNOTSUPP; 736 737 strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); 738 strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); 739 740 return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); 741 } 742 743 static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list, 744 size_t list_size, const char *name, size_t name_len, int type) 745 { 746 /* 747 * This method is not used. 748 * It is used hfsplus_listxattr() instead of generic_listxattr(). 749 */ 750 return -EOPNOTSUPP; 751 } 752 753 const struct xattr_handler hfsplus_xattr_osx_handler = { 754 .prefix = XATTR_MAC_OSX_PREFIX, 755 .list = hfsplus_osx_listxattr, 756 .get = hfsplus_osx_getxattr, 757 .set = hfsplus_osx_setxattr, 758 }; 759