linux/fs/hfsplus/xattr.c
<<
>>
Prefs
   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
  12const 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
  20static 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
  29static 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
  38static 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
  49static 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
  78int __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
 218end_setxattr:
 219        hfs_find_exit(&cat_fd);
 220        return err;
 221}
 222
 223static inline int is_osx_xattr(const char *xattr_name)
 224{
 225        return !is_known_namespace(xattr_name);
 226}
 227
 228static 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
 238static 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
 256static 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
 301end_getxattr_finder_info:
 302        if (size >= record_len)
 303                hfs_find_exit(&fd);
 304        return res;
 305}
 306
 307ssize_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
 398out:
 399        hfs_find_exit(&fd);
 400
 401failed_getxattr_init:
 402        hfsplus_destroy_attr_entry(entry);
 403        return res;
 404}
 405
 406static 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
 416static 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
 478end_listxattr_finder_info:
 479        hfs_find_exit(&fd);
 480
 481        return res;
 482}
 483
 484ssize_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
 564end_listxattr:
 565        hfs_find_exit(&fd);
 566        return res;
 567}
 568
 569int 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
 650end_removexattr:
 651        hfs_find_exit(&cat_fd);
 652        return err;
 653}
 654
 655static 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
 674static 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
 693static 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
 703const 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