13e05ca20SVyacheslav Dubeyko /* 23e05ca20SVyacheslav Dubeyko * linux/fs/hfsplus/attributes.c 33e05ca20SVyacheslav Dubeyko * 43e05ca20SVyacheslav Dubeyko * Vyacheslav Dubeyko <slava@dubeyko.com> 53e05ca20SVyacheslav Dubeyko * 63e05ca20SVyacheslav Dubeyko * Handling of records in attributes tree 73e05ca20SVyacheslav Dubeyko */ 83e05ca20SVyacheslav Dubeyko 93e05ca20SVyacheslav Dubeyko #include "hfsplus_fs.h" 103e05ca20SVyacheslav Dubeyko #include "hfsplus_raw.h" 113e05ca20SVyacheslav Dubeyko 123e05ca20SVyacheslav Dubeyko static struct kmem_cache *hfsplus_attr_tree_cachep; 133e05ca20SVyacheslav Dubeyko 143e05ca20SVyacheslav Dubeyko int hfsplus_create_attr_tree_cache(void) 153e05ca20SVyacheslav Dubeyko { 163e05ca20SVyacheslav Dubeyko if (hfsplus_attr_tree_cachep) 173e05ca20SVyacheslav Dubeyko return -EEXIST; 183e05ca20SVyacheslav Dubeyko 193e05ca20SVyacheslav Dubeyko hfsplus_attr_tree_cachep = 203e05ca20SVyacheslav Dubeyko kmem_cache_create("hfsplus_attr_cache", 213e05ca20SVyacheslav Dubeyko sizeof(hfsplus_attr_entry), 0, 223e05ca20SVyacheslav Dubeyko SLAB_HWCACHE_ALIGN, NULL); 233e05ca20SVyacheslav Dubeyko if (!hfsplus_attr_tree_cachep) 243e05ca20SVyacheslav Dubeyko return -ENOMEM; 253e05ca20SVyacheslav Dubeyko 263e05ca20SVyacheslav Dubeyko return 0; 273e05ca20SVyacheslav Dubeyko } 283e05ca20SVyacheslav Dubeyko 293e05ca20SVyacheslav Dubeyko void hfsplus_destroy_attr_tree_cache(void) 303e05ca20SVyacheslav Dubeyko { 313e05ca20SVyacheslav Dubeyko kmem_cache_destroy(hfsplus_attr_tree_cachep); 323e05ca20SVyacheslav Dubeyko } 333e05ca20SVyacheslav Dubeyko 343e05ca20SVyacheslav Dubeyko int hfsplus_attr_bin_cmp_key(const hfsplus_btree_key *k1, 353e05ca20SVyacheslav Dubeyko const hfsplus_btree_key *k2) 363e05ca20SVyacheslav Dubeyko { 373e05ca20SVyacheslav Dubeyko __be32 k1_cnid, k2_cnid; 383e05ca20SVyacheslav Dubeyko 393e05ca20SVyacheslav Dubeyko k1_cnid = k1->attr.cnid; 403e05ca20SVyacheslav Dubeyko k2_cnid = k2->attr.cnid; 413e05ca20SVyacheslav Dubeyko if (k1_cnid != k2_cnid) 423e05ca20SVyacheslav Dubeyko return be32_to_cpu(k1_cnid) < be32_to_cpu(k2_cnid) ? -1 : 1; 433e05ca20SVyacheslav Dubeyko 443e05ca20SVyacheslav Dubeyko return hfsplus_strcmp( 453e05ca20SVyacheslav Dubeyko (const struct hfsplus_unistr *)&k1->attr.key_name, 463e05ca20SVyacheslav Dubeyko (const struct hfsplus_unistr *)&k2->attr.key_name); 473e05ca20SVyacheslav Dubeyko } 483e05ca20SVyacheslav Dubeyko 493e05ca20SVyacheslav Dubeyko int hfsplus_attr_build_key(struct super_block *sb, hfsplus_btree_key *key, 503e05ca20SVyacheslav Dubeyko u32 cnid, const char *name) 513e05ca20SVyacheslav Dubeyko { 523e05ca20SVyacheslav Dubeyko int len; 533e05ca20SVyacheslav Dubeyko 543e05ca20SVyacheslav Dubeyko memset(key, 0, sizeof(struct hfsplus_attr_key)); 553e05ca20SVyacheslav Dubeyko key->attr.cnid = cpu_to_be32(cnid); 563e05ca20SVyacheslav Dubeyko if (name) { 573e05ca20SVyacheslav Dubeyko len = strlen(name); 583e05ca20SVyacheslav Dubeyko if (len > HFSPLUS_ATTR_MAX_STRLEN) { 593e05ca20SVyacheslav Dubeyko printk(KERN_ERR "hfs: invalid xattr name's length\n"); 603e05ca20SVyacheslav Dubeyko return -EINVAL; 613e05ca20SVyacheslav Dubeyko } 623e05ca20SVyacheslav Dubeyko hfsplus_asc2uni(sb, 633e05ca20SVyacheslav Dubeyko (struct hfsplus_unistr *)&key->attr.key_name, 643e05ca20SVyacheslav Dubeyko HFSPLUS_ATTR_MAX_STRLEN, name, len); 653e05ca20SVyacheslav Dubeyko len = be16_to_cpu(key->attr.key_name.length); 663e05ca20SVyacheslav Dubeyko } else { 673e05ca20SVyacheslav Dubeyko key->attr.key_name.length = 0; 683e05ca20SVyacheslav Dubeyko len = 0; 693e05ca20SVyacheslav Dubeyko } 703e05ca20SVyacheslav Dubeyko 713e05ca20SVyacheslav Dubeyko /* The length of the key, as stored in key_len field, does not include 723e05ca20SVyacheslav Dubeyko * the size of the key_len field itself. 733e05ca20SVyacheslav Dubeyko * So, offsetof(hfsplus_attr_key, key_name) is a trick because 743e05ca20SVyacheslav Dubeyko * it takes into consideration key_len field (__be16) of 753e05ca20SVyacheslav Dubeyko * hfsplus_attr_key structure instead of length field (__be16) of 763e05ca20SVyacheslav Dubeyko * hfsplus_attr_unistr structure. 773e05ca20SVyacheslav Dubeyko */ 783e05ca20SVyacheslav Dubeyko key->key_len = 793e05ca20SVyacheslav Dubeyko cpu_to_be16(offsetof(struct hfsplus_attr_key, key_name) + 803e05ca20SVyacheslav Dubeyko 2 * len); 813e05ca20SVyacheslav Dubeyko 823e05ca20SVyacheslav Dubeyko return 0; 833e05ca20SVyacheslav Dubeyko } 843e05ca20SVyacheslav Dubeyko 853e05ca20SVyacheslav Dubeyko void hfsplus_attr_build_key_uni(hfsplus_btree_key *key, 863e05ca20SVyacheslav Dubeyko u32 cnid, 873e05ca20SVyacheslav Dubeyko struct hfsplus_attr_unistr *name) 883e05ca20SVyacheslav Dubeyko { 893e05ca20SVyacheslav Dubeyko int ustrlen; 903e05ca20SVyacheslav Dubeyko 913e05ca20SVyacheslav Dubeyko memset(key, 0, sizeof(struct hfsplus_attr_key)); 923e05ca20SVyacheslav Dubeyko ustrlen = be16_to_cpu(name->length); 933e05ca20SVyacheslav Dubeyko key->attr.cnid = cpu_to_be32(cnid); 943e05ca20SVyacheslav Dubeyko key->attr.key_name.length = cpu_to_be16(ustrlen); 953e05ca20SVyacheslav Dubeyko ustrlen *= 2; 963e05ca20SVyacheslav Dubeyko memcpy(key->attr.key_name.unicode, name->unicode, ustrlen); 973e05ca20SVyacheslav Dubeyko 983e05ca20SVyacheslav Dubeyko /* The length of the key, as stored in key_len field, does not include 993e05ca20SVyacheslav Dubeyko * the size of the key_len field itself. 1003e05ca20SVyacheslav Dubeyko * So, offsetof(hfsplus_attr_key, key_name) is a trick because 1013e05ca20SVyacheslav Dubeyko * it takes into consideration key_len field (__be16) of 1023e05ca20SVyacheslav Dubeyko * hfsplus_attr_key structure instead of length field (__be16) of 1033e05ca20SVyacheslav Dubeyko * hfsplus_attr_unistr structure. 1043e05ca20SVyacheslav Dubeyko */ 1053e05ca20SVyacheslav Dubeyko key->key_len = 1063e05ca20SVyacheslav Dubeyko cpu_to_be16(offsetof(struct hfsplus_attr_key, key_name) + 1073e05ca20SVyacheslav Dubeyko ustrlen); 1083e05ca20SVyacheslav Dubeyko } 1093e05ca20SVyacheslav Dubeyko 1103e05ca20SVyacheslav Dubeyko hfsplus_attr_entry *hfsplus_alloc_attr_entry(void) 1113e05ca20SVyacheslav Dubeyko { 1123e05ca20SVyacheslav Dubeyko return kmem_cache_alloc(hfsplus_attr_tree_cachep, GFP_KERNEL); 1133e05ca20SVyacheslav Dubeyko } 1143e05ca20SVyacheslav Dubeyko 1153e05ca20SVyacheslav Dubeyko void hfsplus_destroy_attr_entry(hfsplus_attr_entry *entry) 1163e05ca20SVyacheslav Dubeyko { 1173e05ca20SVyacheslav Dubeyko if (entry) 1183e05ca20SVyacheslav Dubeyko kmem_cache_free(hfsplus_attr_tree_cachep, entry); 1193e05ca20SVyacheslav Dubeyko } 1203e05ca20SVyacheslav Dubeyko 1213e05ca20SVyacheslav Dubeyko #define HFSPLUS_INVALID_ATTR_RECORD -1 1223e05ca20SVyacheslav Dubeyko 1233e05ca20SVyacheslav Dubeyko static int hfsplus_attr_build_record(hfsplus_attr_entry *entry, int record_type, 1243e05ca20SVyacheslav Dubeyko u32 cnid, const void *value, size_t size) 1253e05ca20SVyacheslav Dubeyko { 1263e05ca20SVyacheslav Dubeyko if (record_type == HFSPLUS_ATTR_FORK_DATA) { 1273e05ca20SVyacheslav Dubeyko /* 1283e05ca20SVyacheslav Dubeyko * Mac OS X supports only inline data attributes. 1293e05ca20SVyacheslav Dubeyko * Do nothing 1303e05ca20SVyacheslav Dubeyko */ 1313e05ca20SVyacheslav Dubeyko memset(entry, 0, sizeof(*entry)); 1323e05ca20SVyacheslav Dubeyko return sizeof(struct hfsplus_attr_fork_data); 1333e05ca20SVyacheslav Dubeyko } else if (record_type == HFSPLUS_ATTR_EXTENTS) { 1343e05ca20SVyacheslav Dubeyko /* 1353e05ca20SVyacheslav Dubeyko * Mac OS X supports only inline data attributes. 1363e05ca20SVyacheslav Dubeyko * Do nothing. 1373e05ca20SVyacheslav Dubeyko */ 1383e05ca20SVyacheslav Dubeyko memset(entry, 0, sizeof(*entry)); 1393e05ca20SVyacheslav Dubeyko return sizeof(struct hfsplus_attr_extents); 1403e05ca20SVyacheslav Dubeyko } else if (record_type == HFSPLUS_ATTR_INLINE_DATA) { 1413e05ca20SVyacheslav Dubeyko u16 len; 1423e05ca20SVyacheslav Dubeyko 1433e05ca20SVyacheslav Dubeyko memset(entry, 0, sizeof(struct hfsplus_attr_inline_data)); 1443e05ca20SVyacheslav Dubeyko entry->inline_data.record_type = cpu_to_be32(record_type); 1453e05ca20SVyacheslav Dubeyko if (size <= HFSPLUS_MAX_INLINE_DATA_SIZE) 1463e05ca20SVyacheslav Dubeyko len = size; 1473e05ca20SVyacheslav Dubeyko else 1483e05ca20SVyacheslav Dubeyko return HFSPLUS_INVALID_ATTR_RECORD; 1493e05ca20SVyacheslav Dubeyko entry->inline_data.length = cpu_to_be16(len); 1503e05ca20SVyacheslav Dubeyko memcpy(entry->inline_data.raw_bytes, value, len); 1513e05ca20SVyacheslav Dubeyko /* 1523e05ca20SVyacheslav Dubeyko * Align len on two-byte boundary. 1533e05ca20SVyacheslav Dubeyko * It needs to add pad byte if we have odd len. 1543e05ca20SVyacheslav Dubeyko */ 1553e05ca20SVyacheslav Dubeyko len = round_up(len, 2); 1563e05ca20SVyacheslav Dubeyko return offsetof(struct hfsplus_attr_inline_data, raw_bytes) + 1573e05ca20SVyacheslav Dubeyko len; 1583e05ca20SVyacheslav Dubeyko } else /* invalid input */ 1593e05ca20SVyacheslav Dubeyko memset(entry, 0, sizeof(*entry)); 1603e05ca20SVyacheslav Dubeyko 1613e05ca20SVyacheslav Dubeyko return HFSPLUS_INVALID_ATTR_RECORD; 1623e05ca20SVyacheslav Dubeyko } 1633e05ca20SVyacheslav Dubeyko 1643e05ca20SVyacheslav Dubeyko int hfsplus_find_attr(struct super_block *sb, u32 cnid, 1653e05ca20SVyacheslav Dubeyko const char *name, struct hfs_find_data *fd) 1663e05ca20SVyacheslav Dubeyko { 1673e05ca20SVyacheslav Dubeyko int err = 0; 1683e05ca20SVyacheslav Dubeyko 169*c2b3e1f7SJoe Perches hfs_dbg(ATTR_MOD, "find_attr: %s,%d\n", name ? name : NULL, cnid); 1703e05ca20SVyacheslav Dubeyko 1713e05ca20SVyacheslav Dubeyko if (!HFSPLUS_SB(sb)->attr_tree) { 1723e05ca20SVyacheslav Dubeyko printk(KERN_ERR "hfs: attributes file doesn't exist\n"); 1733e05ca20SVyacheslav Dubeyko return -EINVAL; 1743e05ca20SVyacheslav Dubeyko } 1753e05ca20SVyacheslav Dubeyko 1763e05ca20SVyacheslav Dubeyko if (name) { 1773e05ca20SVyacheslav Dubeyko err = hfsplus_attr_build_key(sb, fd->search_key, cnid, name); 1783e05ca20SVyacheslav Dubeyko if (err) 1793e05ca20SVyacheslav Dubeyko goto failed_find_attr; 1803e05ca20SVyacheslav Dubeyko err = hfs_brec_find(fd, hfs_find_rec_by_key); 1813e05ca20SVyacheslav Dubeyko if (err) 1823e05ca20SVyacheslav Dubeyko goto failed_find_attr; 1833e05ca20SVyacheslav Dubeyko } else { 1843e05ca20SVyacheslav Dubeyko err = hfsplus_attr_build_key(sb, fd->search_key, cnid, NULL); 1853e05ca20SVyacheslav Dubeyko if (err) 1863e05ca20SVyacheslav Dubeyko goto failed_find_attr; 1873e05ca20SVyacheslav Dubeyko err = hfs_brec_find(fd, hfs_find_1st_rec_by_cnid); 1883e05ca20SVyacheslav Dubeyko if (err) 1893e05ca20SVyacheslav Dubeyko goto failed_find_attr; 1903e05ca20SVyacheslav Dubeyko } 1913e05ca20SVyacheslav Dubeyko 1923e05ca20SVyacheslav Dubeyko failed_find_attr: 1933e05ca20SVyacheslav Dubeyko return err; 1943e05ca20SVyacheslav Dubeyko } 1953e05ca20SVyacheslav Dubeyko 1963e05ca20SVyacheslav Dubeyko int hfsplus_attr_exists(struct inode *inode, const char *name) 1973e05ca20SVyacheslav Dubeyko { 1983e05ca20SVyacheslav Dubeyko int err = 0; 1993e05ca20SVyacheslav Dubeyko struct super_block *sb = inode->i_sb; 2003e05ca20SVyacheslav Dubeyko struct hfs_find_data fd; 2013e05ca20SVyacheslav Dubeyko 2023e05ca20SVyacheslav Dubeyko if (!HFSPLUS_SB(sb)->attr_tree) 2033e05ca20SVyacheslav Dubeyko return 0; 2043e05ca20SVyacheslav Dubeyko 2053e05ca20SVyacheslav Dubeyko err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd); 2063e05ca20SVyacheslav Dubeyko if (err) 2073e05ca20SVyacheslav Dubeyko return 0; 2083e05ca20SVyacheslav Dubeyko 2093e05ca20SVyacheslav Dubeyko err = hfsplus_find_attr(sb, inode->i_ino, name, &fd); 2103e05ca20SVyacheslav Dubeyko if (err) 2113e05ca20SVyacheslav Dubeyko goto attr_not_found; 2123e05ca20SVyacheslav Dubeyko 2133e05ca20SVyacheslav Dubeyko hfs_find_exit(&fd); 2143e05ca20SVyacheslav Dubeyko return 1; 2153e05ca20SVyacheslav Dubeyko 2163e05ca20SVyacheslav Dubeyko attr_not_found: 2173e05ca20SVyacheslav Dubeyko hfs_find_exit(&fd); 2183e05ca20SVyacheslav Dubeyko return 0; 2193e05ca20SVyacheslav Dubeyko } 2203e05ca20SVyacheslav Dubeyko 2213e05ca20SVyacheslav Dubeyko int hfsplus_create_attr(struct inode *inode, 2223e05ca20SVyacheslav Dubeyko const char *name, 2233e05ca20SVyacheslav Dubeyko const void *value, size_t size) 2243e05ca20SVyacheslav Dubeyko { 2253e05ca20SVyacheslav Dubeyko struct super_block *sb = inode->i_sb; 2263e05ca20SVyacheslav Dubeyko struct hfs_find_data fd; 2273e05ca20SVyacheslav Dubeyko hfsplus_attr_entry *entry_ptr; 2283e05ca20SVyacheslav Dubeyko int entry_size; 2293e05ca20SVyacheslav Dubeyko int err; 2303e05ca20SVyacheslav Dubeyko 231*c2b3e1f7SJoe Perches hfs_dbg(ATTR_MOD, "create_attr: %s,%ld\n", 2323e05ca20SVyacheslav Dubeyko name ? name : NULL, inode->i_ino); 2333e05ca20SVyacheslav Dubeyko 2343e05ca20SVyacheslav Dubeyko if (!HFSPLUS_SB(sb)->attr_tree) { 2353e05ca20SVyacheslav Dubeyko printk(KERN_ERR "hfs: attributes file doesn't exist\n"); 2363e05ca20SVyacheslav Dubeyko return -EINVAL; 2373e05ca20SVyacheslav Dubeyko } 2383e05ca20SVyacheslav Dubeyko 2393e05ca20SVyacheslav Dubeyko entry_ptr = hfsplus_alloc_attr_entry(); 2403e05ca20SVyacheslav Dubeyko if (!entry_ptr) 2413e05ca20SVyacheslav Dubeyko return -ENOMEM; 2423e05ca20SVyacheslav Dubeyko 2433e05ca20SVyacheslav Dubeyko err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd); 2443e05ca20SVyacheslav Dubeyko if (err) 2453e05ca20SVyacheslav Dubeyko goto failed_init_create_attr; 2463e05ca20SVyacheslav Dubeyko 2473e05ca20SVyacheslav Dubeyko if (name) { 2483e05ca20SVyacheslav Dubeyko err = hfsplus_attr_build_key(sb, fd.search_key, 2493e05ca20SVyacheslav Dubeyko inode->i_ino, name); 2503e05ca20SVyacheslav Dubeyko if (err) 2513e05ca20SVyacheslav Dubeyko goto failed_create_attr; 2523e05ca20SVyacheslav Dubeyko } else { 2533e05ca20SVyacheslav Dubeyko err = -EINVAL; 2543e05ca20SVyacheslav Dubeyko goto failed_create_attr; 2553e05ca20SVyacheslav Dubeyko } 2563e05ca20SVyacheslav Dubeyko 2573e05ca20SVyacheslav Dubeyko /* Mac OS X supports only inline data attributes. */ 2583e05ca20SVyacheslav Dubeyko entry_size = hfsplus_attr_build_record(entry_ptr, 2593e05ca20SVyacheslav Dubeyko HFSPLUS_ATTR_INLINE_DATA, 2603e05ca20SVyacheslav Dubeyko inode->i_ino, 2613e05ca20SVyacheslav Dubeyko value, size); 2623e05ca20SVyacheslav Dubeyko if (entry_size == HFSPLUS_INVALID_ATTR_RECORD) { 2633e05ca20SVyacheslav Dubeyko err = -EINVAL; 2643e05ca20SVyacheslav Dubeyko goto failed_create_attr; 2653e05ca20SVyacheslav Dubeyko } 2663e05ca20SVyacheslav Dubeyko 2673e05ca20SVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 2683e05ca20SVyacheslav Dubeyko if (err != -ENOENT) { 2693e05ca20SVyacheslav Dubeyko if (!err) 2703e05ca20SVyacheslav Dubeyko err = -EEXIST; 2713e05ca20SVyacheslav Dubeyko goto failed_create_attr; 2723e05ca20SVyacheslav Dubeyko } 2733e05ca20SVyacheslav Dubeyko 2743e05ca20SVyacheslav Dubeyko err = hfs_brec_insert(&fd, entry_ptr, entry_size); 2753e05ca20SVyacheslav Dubeyko if (err) 2763e05ca20SVyacheslav Dubeyko goto failed_create_attr; 2773e05ca20SVyacheslav Dubeyko 2783e05ca20SVyacheslav Dubeyko hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY); 2793e05ca20SVyacheslav Dubeyko 2803e05ca20SVyacheslav Dubeyko failed_create_attr: 2813e05ca20SVyacheslav Dubeyko hfs_find_exit(&fd); 2823e05ca20SVyacheslav Dubeyko 2833e05ca20SVyacheslav Dubeyko failed_init_create_attr: 2843e05ca20SVyacheslav Dubeyko hfsplus_destroy_attr_entry(entry_ptr); 2853e05ca20SVyacheslav Dubeyko return err; 2863e05ca20SVyacheslav Dubeyko } 2873e05ca20SVyacheslav Dubeyko 2883e05ca20SVyacheslav Dubeyko static int __hfsplus_delete_attr(struct inode *inode, u32 cnid, 2893e05ca20SVyacheslav Dubeyko struct hfs_find_data *fd) 2903e05ca20SVyacheslav Dubeyko { 2913e05ca20SVyacheslav Dubeyko int err = 0; 2923e05ca20SVyacheslav Dubeyko __be32 found_cnid, record_type; 2933e05ca20SVyacheslav Dubeyko 2943e05ca20SVyacheslav Dubeyko hfs_bnode_read(fd->bnode, &found_cnid, 2953e05ca20SVyacheslav Dubeyko fd->keyoffset + 2963e05ca20SVyacheslav Dubeyko offsetof(struct hfsplus_attr_key, cnid), 2973e05ca20SVyacheslav Dubeyko sizeof(__be32)); 2983e05ca20SVyacheslav Dubeyko if (cnid != be32_to_cpu(found_cnid)) 2993e05ca20SVyacheslav Dubeyko return -ENOENT; 3003e05ca20SVyacheslav Dubeyko 3013e05ca20SVyacheslav Dubeyko hfs_bnode_read(fd->bnode, &record_type, 3023e05ca20SVyacheslav Dubeyko fd->entryoffset, sizeof(record_type)); 3033e05ca20SVyacheslav Dubeyko 3043e05ca20SVyacheslav Dubeyko switch (be32_to_cpu(record_type)) { 3053e05ca20SVyacheslav Dubeyko case HFSPLUS_ATTR_INLINE_DATA: 3063e05ca20SVyacheslav Dubeyko /* All is OK. Do nothing. */ 3073e05ca20SVyacheslav Dubeyko break; 3083e05ca20SVyacheslav Dubeyko case HFSPLUS_ATTR_FORK_DATA: 3093e05ca20SVyacheslav Dubeyko case HFSPLUS_ATTR_EXTENTS: 3103e05ca20SVyacheslav Dubeyko printk(KERN_ERR "hfs: only inline data xattr are supported\n"); 3113e05ca20SVyacheslav Dubeyko return -EOPNOTSUPP; 3123e05ca20SVyacheslav Dubeyko default: 3133e05ca20SVyacheslav Dubeyko printk(KERN_ERR "hfs: invalid extended attribute record\n"); 3143e05ca20SVyacheslav Dubeyko return -ENOENT; 3153e05ca20SVyacheslav Dubeyko } 3163e05ca20SVyacheslav Dubeyko 3173e05ca20SVyacheslav Dubeyko err = hfs_brec_remove(fd); 3183e05ca20SVyacheslav Dubeyko if (err) 3193e05ca20SVyacheslav Dubeyko return err; 3203e05ca20SVyacheslav Dubeyko 3213e05ca20SVyacheslav Dubeyko hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY); 3223e05ca20SVyacheslav Dubeyko return err; 3233e05ca20SVyacheslav Dubeyko } 3243e05ca20SVyacheslav Dubeyko 3253e05ca20SVyacheslav Dubeyko int hfsplus_delete_attr(struct inode *inode, const char *name) 3263e05ca20SVyacheslav Dubeyko { 3273e05ca20SVyacheslav Dubeyko int err = 0; 3283e05ca20SVyacheslav Dubeyko struct super_block *sb = inode->i_sb; 3293e05ca20SVyacheslav Dubeyko struct hfs_find_data fd; 3303e05ca20SVyacheslav Dubeyko 331*c2b3e1f7SJoe Perches hfs_dbg(ATTR_MOD, "delete_attr: %s,%ld\n", 3323e05ca20SVyacheslav Dubeyko name ? name : NULL, inode->i_ino); 3333e05ca20SVyacheslav Dubeyko 3343e05ca20SVyacheslav Dubeyko if (!HFSPLUS_SB(sb)->attr_tree) { 3353e05ca20SVyacheslav Dubeyko printk(KERN_ERR "hfs: attributes file doesn't exist\n"); 3363e05ca20SVyacheslav Dubeyko return -EINVAL; 3373e05ca20SVyacheslav Dubeyko } 3383e05ca20SVyacheslav Dubeyko 3393e05ca20SVyacheslav Dubeyko err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd); 3403e05ca20SVyacheslav Dubeyko if (err) 3413e05ca20SVyacheslav Dubeyko return err; 3423e05ca20SVyacheslav Dubeyko 3433e05ca20SVyacheslav Dubeyko if (name) { 3443e05ca20SVyacheslav Dubeyko err = hfsplus_attr_build_key(sb, fd.search_key, 3453e05ca20SVyacheslav Dubeyko inode->i_ino, name); 3463e05ca20SVyacheslav Dubeyko if (err) 3473e05ca20SVyacheslav Dubeyko goto out; 3483e05ca20SVyacheslav Dubeyko } else { 3493e05ca20SVyacheslav Dubeyko printk(KERN_ERR "hfs: invalid extended attribute name\n"); 3503e05ca20SVyacheslav Dubeyko err = -EINVAL; 3513e05ca20SVyacheslav Dubeyko goto out; 3523e05ca20SVyacheslav Dubeyko } 3533e05ca20SVyacheslav Dubeyko 3543e05ca20SVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 3553e05ca20SVyacheslav Dubeyko if (err) 3563e05ca20SVyacheslav Dubeyko goto out; 3573e05ca20SVyacheslav Dubeyko 3583e05ca20SVyacheslav Dubeyko err = __hfsplus_delete_attr(inode, inode->i_ino, &fd); 3593e05ca20SVyacheslav Dubeyko if (err) 3603e05ca20SVyacheslav Dubeyko goto out; 3613e05ca20SVyacheslav Dubeyko 3623e05ca20SVyacheslav Dubeyko out: 3633e05ca20SVyacheslav Dubeyko hfs_find_exit(&fd); 3643e05ca20SVyacheslav Dubeyko return err; 3653e05ca20SVyacheslav Dubeyko } 3663e05ca20SVyacheslav Dubeyko 3673e05ca20SVyacheslav Dubeyko int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid) 3683e05ca20SVyacheslav Dubeyko { 3693e05ca20SVyacheslav Dubeyko int err = 0; 3703e05ca20SVyacheslav Dubeyko struct hfs_find_data fd; 3713e05ca20SVyacheslav Dubeyko 372*c2b3e1f7SJoe Perches hfs_dbg(ATTR_MOD, "delete_all_attrs: %d\n", cnid); 3733e05ca20SVyacheslav Dubeyko 3743e05ca20SVyacheslav Dubeyko if (!HFSPLUS_SB(dir->i_sb)->attr_tree) { 3753e05ca20SVyacheslav Dubeyko printk(KERN_ERR "hfs: attributes file doesn't exist\n"); 3763e05ca20SVyacheslav Dubeyko return -EINVAL; 3773e05ca20SVyacheslav Dubeyko } 3783e05ca20SVyacheslav Dubeyko 3793e05ca20SVyacheslav Dubeyko err = hfs_find_init(HFSPLUS_SB(dir->i_sb)->attr_tree, &fd); 3803e05ca20SVyacheslav Dubeyko if (err) 3813e05ca20SVyacheslav Dubeyko return err; 3823e05ca20SVyacheslav Dubeyko 3833e05ca20SVyacheslav Dubeyko for (;;) { 3843e05ca20SVyacheslav Dubeyko err = hfsplus_find_attr(dir->i_sb, cnid, NULL, &fd); 3853e05ca20SVyacheslav Dubeyko if (err) { 3863e05ca20SVyacheslav Dubeyko if (err != -ENOENT) 3873e05ca20SVyacheslav Dubeyko printk(KERN_ERR "hfs: xattr search failed.\n"); 3883e05ca20SVyacheslav Dubeyko goto end_delete_all; 3893e05ca20SVyacheslav Dubeyko } 3903e05ca20SVyacheslav Dubeyko 3913e05ca20SVyacheslav Dubeyko err = __hfsplus_delete_attr(dir, cnid, &fd); 3923e05ca20SVyacheslav Dubeyko if (err) 3933e05ca20SVyacheslav Dubeyko goto end_delete_all; 3943e05ca20SVyacheslav Dubeyko } 3953e05ca20SVyacheslav Dubeyko 3963e05ca20SVyacheslav Dubeyko end_delete_all: 3973e05ca20SVyacheslav Dubeyko hfs_find_exit(&fd); 3983e05ca20SVyacheslav Dubeyko return err; 3993e05ca20SVyacheslav Dubeyko } 400