xref: /linux/fs/hfsplus/attributes.c (revision c2b3e1f76e5c90215bc7f740b376c0220eb8a8e3)
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