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#include "acl.h"
  12
  13const 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
  25static 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
  34static 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
  43static 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
  54static 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
 101static 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
 130int __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
 270end_setxattr:
 271        hfs_find_exit(&cat_fd);
 272        return err;
 273}
 274
 275static inline int is_osx_xattr(const char *xattr_name)
 276{
 277        return !is_known_namespace(xattr_name);
 278}
 279
 280static 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
 290static 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
 308static 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
 352end_getxattr_finder_info:
 353        if (size >= record_len)
 354                hfs_find_exit(&fd);
 355        return res;
 356}
 357
 358ssize_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
 448out:
 449        hfs_find_exit(&fd);
 450
 451failed_getxattr_init:
 452        hfsplus_destroy_attr_entry(entry);
 453        return res;
 454}
 455
 456static 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
 466static 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
 528end_listxattr_finder_info:
 529        hfs_find_exit(&fd);
 530
 531        return res;
 532}
 533
 534ssize_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
 614end_listxattr:
 615        hfs_find_exit(&fd);
 616        return res;
 617}
 618
 619int 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
 700end_removexattr:
 701        hfs_find_exit(&cat_fd);
 702        return err;
 703}
 704
 705static 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
 724static 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
 743static 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
 753const 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