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