Linux Audio

Check our new training course

Loading...
v4.6
 
  1/*
  2 * linux/fs/hfsplus/attributes.c
  3 *
  4 * Vyacheslav Dubeyko <slava@dubeyko.com>
  5 *
  6 * Handling of records in attributes tree
  7 */
  8
  9#include "hfsplus_fs.h"
 10#include "hfsplus_raw.h"
 11
 12static struct kmem_cache *hfsplus_attr_tree_cachep;
 13
 14int __init hfsplus_create_attr_tree_cache(void)
 15{
 16	if (hfsplus_attr_tree_cachep)
 17		return -EEXIST;
 18
 19	hfsplus_attr_tree_cachep =
 20		kmem_cache_create("hfsplus_attr_cache",
 21			sizeof(hfsplus_attr_entry), 0,
 22			SLAB_HWCACHE_ALIGN, NULL);
 23	if (!hfsplus_attr_tree_cachep)
 24		return -ENOMEM;
 25
 26	return 0;
 27}
 28
 29void hfsplus_destroy_attr_tree_cache(void)
 30{
 31	kmem_cache_destroy(hfsplus_attr_tree_cachep);
 32}
 33
 34int hfsplus_attr_bin_cmp_key(const hfsplus_btree_key *k1,
 35				const hfsplus_btree_key *k2)
 36{
 37	__be32 k1_cnid, k2_cnid;
 38
 39	k1_cnid = k1->attr.cnid;
 40	k2_cnid = k2->attr.cnid;
 41	if (k1_cnid != k2_cnid)
 42		return be32_to_cpu(k1_cnid) < be32_to_cpu(k2_cnid) ? -1 : 1;
 43
 44	return hfsplus_strcmp(
 45			(const struct hfsplus_unistr *)&k1->attr.key_name,
 46			(const struct hfsplus_unistr *)&k2->attr.key_name);
 47}
 48
 49int hfsplus_attr_build_key(struct super_block *sb, hfsplus_btree_key *key,
 50			u32 cnid, const char *name)
 51{
 52	int len;
 53
 54	memset(key, 0, sizeof(struct hfsplus_attr_key));
 55	key->attr.cnid = cpu_to_be32(cnid);
 56	if (name) {
 57		int res = hfsplus_asc2uni(sb,
 58				(struct hfsplus_unistr *)&key->attr.key_name,
 59				HFSPLUS_ATTR_MAX_STRLEN, name, strlen(name));
 60		if (res)
 61			return res;
 62		len = be16_to_cpu(key->attr.key_name.length);
 63	} else {
 64		key->attr.key_name.length = 0;
 65		len = 0;
 66	}
 67
 68	/* The length of the key, as stored in key_len field, does not include
 69	 * the size of the key_len field itself.
 70	 * So, offsetof(hfsplus_attr_key, key_name) is a trick because
 71	 * it takes into consideration key_len field (__be16) of
 72	 * hfsplus_attr_key structure instead of length field (__be16) of
 73	 * hfsplus_attr_unistr structure.
 74	 */
 75	key->key_len =
 76		cpu_to_be16(offsetof(struct hfsplus_attr_key, key_name) +
 77				2 * len);
 78
 79	return 0;
 80}
 81
 82hfsplus_attr_entry *hfsplus_alloc_attr_entry(void)
 83{
 84	return kmem_cache_alloc(hfsplus_attr_tree_cachep, GFP_KERNEL);
 85}
 86
 87void hfsplus_destroy_attr_entry(hfsplus_attr_entry *entry)
 88{
 89	if (entry)
 90		kmem_cache_free(hfsplus_attr_tree_cachep, entry);
 91}
 92
 93#define HFSPLUS_INVALID_ATTR_RECORD -1
 94
 95static int hfsplus_attr_build_record(hfsplus_attr_entry *entry, int record_type,
 96				u32 cnid, const void *value, size_t size)
 97{
 98	if (record_type == HFSPLUS_ATTR_FORK_DATA) {
 99		/*
100		 * Mac OS X supports only inline data attributes.
101		 * Do nothing
102		 */
103		memset(entry, 0, sizeof(*entry));
104		return sizeof(struct hfsplus_attr_fork_data);
105	} else if (record_type == HFSPLUS_ATTR_EXTENTS) {
106		/*
107		 * Mac OS X supports only inline data attributes.
108		 * Do nothing.
109		 */
110		memset(entry, 0, sizeof(*entry));
111		return sizeof(struct hfsplus_attr_extents);
112	} else if (record_type == HFSPLUS_ATTR_INLINE_DATA) {
113		u16 len;
114
115		memset(entry, 0, sizeof(struct hfsplus_attr_inline_data));
116		entry->inline_data.record_type = cpu_to_be32(record_type);
117		if (size <= HFSPLUS_MAX_INLINE_DATA_SIZE)
118			len = size;
119		else
120			return HFSPLUS_INVALID_ATTR_RECORD;
121		entry->inline_data.length = cpu_to_be16(len);
122		memcpy(entry->inline_data.raw_bytes, value, len);
123		/*
124		 * Align len on two-byte boundary.
125		 * It needs to add pad byte if we have odd len.
126		 */
127		len = round_up(len, 2);
128		return offsetof(struct hfsplus_attr_inline_data, raw_bytes) +
129					len;
130	} else /* invalid input */
131		memset(entry, 0, sizeof(*entry));
132
133	return HFSPLUS_INVALID_ATTR_RECORD;
134}
135
136int hfsplus_find_attr(struct super_block *sb, u32 cnid,
137			const char *name, struct hfs_find_data *fd)
138{
139	int err = 0;
140
141	hfs_dbg(ATTR_MOD, "find_attr: %s,%d\n", name ? name : NULL, cnid);
142
143	if (!HFSPLUS_SB(sb)->attr_tree) {
144		pr_err("attributes file doesn't exist\n");
145		return -EINVAL;
146	}
147
148	if (name) {
149		err = hfsplus_attr_build_key(sb, fd->search_key, cnid, name);
150		if (err)
151			goto failed_find_attr;
152		err = hfs_brec_find(fd, hfs_find_rec_by_key);
153		if (err)
154			goto failed_find_attr;
155	} else {
156		err = hfsplus_attr_build_key(sb, fd->search_key, cnid, NULL);
157		if (err)
158			goto failed_find_attr;
159		err = hfs_brec_find(fd, hfs_find_1st_rec_by_cnid);
160		if (err)
161			goto failed_find_attr;
162	}
163
164failed_find_attr:
165	return err;
166}
167
168int hfsplus_attr_exists(struct inode *inode, const char *name)
169{
170	int err = 0;
171	struct super_block *sb = inode->i_sb;
172	struct hfs_find_data fd;
173
174	if (!HFSPLUS_SB(sb)->attr_tree)
175		return 0;
176
177	err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd);
178	if (err)
179		return 0;
180
181	err = hfsplus_find_attr(sb, inode->i_ino, name, &fd);
182	if (err)
183		goto attr_not_found;
184
185	hfs_find_exit(&fd);
186	return 1;
187
188attr_not_found:
189	hfs_find_exit(&fd);
190	return 0;
191}
192
193int hfsplus_create_attr(struct inode *inode,
194				const char *name,
195				const void *value, size_t size)
196{
197	struct super_block *sb = inode->i_sb;
198	struct hfs_find_data fd;
199	hfsplus_attr_entry *entry_ptr;
200	int entry_size;
201	int err;
202
203	hfs_dbg(ATTR_MOD, "create_attr: %s,%ld\n",
204		name ? name : NULL, inode->i_ino);
205
206	if (!HFSPLUS_SB(sb)->attr_tree) {
207		pr_err("attributes file doesn't exist\n");
208		return -EINVAL;
209	}
210
211	entry_ptr = hfsplus_alloc_attr_entry();
212	if (!entry_ptr)
213		return -ENOMEM;
214
215	err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd);
216	if (err)
217		goto failed_init_create_attr;
218
 
 
 
 
 
219	if (name) {
220		err = hfsplus_attr_build_key(sb, fd.search_key,
221						inode->i_ino, name);
222		if (err)
223			goto failed_create_attr;
224	} else {
225		err = -EINVAL;
226		goto failed_create_attr;
227	}
228
229	/* Mac OS X supports only inline data attributes. */
230	entry_size = hfsplus_attr_build_record(entry_ptr,
231					HFSPLUS_ATTR_INLINE_DATA,
232					inode->i_ino,
233					value, size);
234	if (entry_size == HFSPLUS_INVALID_ATTR_RECORD) {
235		err = -EINVAL;
236		goto failed_create_attr;
237	}
238
239	err = hfs_brec_find(&fd, hfs_find_rec_by_key);
240	if (err != -ENOENT) {
241		if (!err)
242			err = -EEXIST;
243		goto failed_create_attr;
244	}
245
246	err = hfs_brec_insert(&fd, entry_ptr, entry_size);
247	if (err)
248		goto failed_create_attr;
249
250	hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY);
251
252failed_create_attr:
253	hfs_find_exit(&fd);
254
255failed_init_create_attr:
256	hfsplus_destroy_attr_entry(entry_ptr);
257	return err;
258}
259
260static int __hfsplus_delete_attr(struct inode *inode, u32 cnid,
261					struct hfs_find_data *fd)
262{
263	int err = 0;
264	__be32 found_cnid, record_type;
265
266	hfs_bnode_read(fd->bnode, &found_cnid,
267			fd->keyoffset +
268			offsetof(struct hfsplus_attr_key, cnid),
269			sizeof(__be32));
270	if (cnid != be32_to_cpu(found_cnid))
271		return -ENOENT;
272
273	hfs_bnode_read(fd->bnode, &record_type,
274			fd->entryoffset, sizeof(record_type));
275
276	switch (be32_to_cpu(record_type)) {
277	case HFSPLUS_ATTR_INLINE_DATA:
278		/* All is OK. Do nothing. */
279		break;
280	case HFSPLUS_ATTR_FORK_DATA:
281	case HFSPLUS_ATTR_EXTENTS:
282		pr_err("only inline data xattr are supported\n");
283		return -EOPNOTSUPP;
284	default:
285		pr_err("invalid extended attribute record\n");
286		return -ENOENT;
287	}
288
289	err = hfs_brec_remove(fd);
290	if (err)
291		return err;
292
293	hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY);
294	return err;
295}
296
297int hfsplus_delete_attr(struct inode *inode, const char *name)
298{
299	int err = 0;
300	struct super_block *sb = inode->i_sb;
301	struct hfs_find_data fd;
302
303	hfs_dbg(ATTR_MOD, "delete_attr: %s,%ld\n",
304		name ? name : NULL, inode->i_ino);
305
306	if (!HFSPLUS_SB(sb)->attr_tree) {
307		pr_err("attributes file doesn't exist\n");
308		return -EINVAL;
309	}
310
311	err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd);
312	if (err)
313		return err;
 
 
 
 
 
314
315	if (name) {
316		err = hfsplus_attr_build_key(sb, fd.search_key,
317						inode->i_ino, name);
318		if (err)
319			goto out;
320	} else {
321		pr_err("invalid extended attribute name\n");
322		err = -EINVAL;
323		goto out;
324	}
325
326	err = hfs_brec_find(&fd, hfs_find_rec_by_key);
327	if (err)
328		goto out;
329
330	err = __hfsplus_delete_attr(inode, inode->i_ino, &fd);
331	if (err)
332		goto out;
333
334out:
335	hfs_find_exit(&fd);
336	return err;
337}
338
339int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid)
340{
341	int err = 0;
342	struct hfs_find_data fd;
343
344	hfs_dbg(ATTR_MOD, "delete_all_attrs: %d\n", cnid);
345
346	if (!HFSPLUS_SB(dir->i_sb)->attr_tree) {
347		pr_err("attributes file doesn't exist\n");
348		return -EINVAL;
349	}
350
351	err = hfs_find_init(HFSPLUS_SB(dir->i_sb)->attr_tree, &fd);
352	if (err)
353		return err;
354
355	for (;;) {
356		err = hfsplus_find_attr(dir->i_sb, cnid, NULL, &fd);
357		if (err) {
358			if (err != -ENOENT)
359				pr_err("xattr search failed\n");
360			goto end_delete_all;
361		}
362
363		err = __hfsplus_delete_attr(dir, cnid, &fd);
364		if (err)
365			goto end_delete_all;
366	}
367
368end_delete_all:
369	hfs_find_exit(&fd);
370	return err;
371}
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * linux/fs/hfsplus/attributes.c
  4 *
  5 * Vyacheslav Dubeyko <slava@dubeyko.com>
  6 *
  7 * Handling of records in attributes tree
  8 */
  9
 10#include "hfsplus_fs.h"
 11#include "hfsplus_raw.h"
 12
 13static struct kmem_cache *hfsplus_attr_tree_cachep;
 14
 15int __init hfsplus_create_attr_tree_cache(void)
 16{
 17	if (hfsplus_attr_tree_cachep)
 18		return -EEXIST;
 19
 20	hfsplus_attr_tree_cachep =
 21		kmem_cache_create("hfsplus_attr_cache",
 22			sizeof(hfsplus_attr_entry), 0,
 23			SLAB_HWCACHE_ALIGN, NULL);
 24	if (!hfsplus_attr_tree_cachep)
 25		return -ENOMEM;
 26
 27	return 0;
 28}
 29
 30void hfsplus_destroy_attr_tree_cache(void)
 31{
 32	kmem_cache_destroy(hfsplus_attr_tree_cachep);
 33}
 34
 35int hfsplus_attr_bin_cmp_key(const hfsplus_btree_key *k1,
 36				const hfsplus_btree_key *k2)
 37{
 38	__be32 k1_cnid, k2_cnid;
 39
 40	k1_cnid = k1->attr.cnid;
 41	k2_cnid = k2->attr.cnid;
 42	if (k1_cnid != k2_cnid)
 43		return be32_to_cpu(k1_cnid) < be32_to_cpu(k2_cnid) ? -1 : 1;
 44
 45	return hfsplus_strcmp(
 46			(const struct hfsplus_unistr *)&k1->attr.key_name,
 47			(const struct hfsplus_unistr *)&k2->attr.key_name);
 48}
 49
 50int hfsplus_attr_build_key(struct super_block *sb, hfsplus_btree_key *key,
 51			u32 cnid, const char *name)
 52{
 53	int len;
 54
 55	memset(key, 0, sizeof(struct hfsplus_attr_key));
 56	key->attr.cnid = cpu_to_be32(cnid);
 57	if (name) {
 58		int res = hfsplus_asc2uni(sb,
 59				(struct hfsplus_unistr *)&key->attr.key_name,
 60				HFSPLUS_ATTR_MAX_STRLEN, name, strlen(name));
 61		if (res)
 62			return res;
 63		len = be16_to_cpu(key->attr.key_name.length);
 64	} else {
 65		key->attr.key_name.length = 0;
 66		len = 0;
 67	}
 68
 69	/* The length of the key, as stored in key_len field, does not include
 70	 * the size of the key_len field itself.
 71	 * So, offsetof(hfsplus_attr_key, key_name) is a trick because
 72	 * it takes into consideration key_len field (__be16) of
 73	 * hfsplus_attr_key structure instead of length field (__be16) of
 74	 * hfsplus_attr_unistr structure.
 75	 */
 76	key->key_len =
 77		cpu_to_be16(offsetof(struct hfsplus_attr_key, key_name) +
 78				2 * len);
 79
 80	return 0;
 81}
 82
 83hfsplus_attr_entry *hfsplus_alloc_attr_entry(void)
 84{
 85	return kmem_cache_alloc(hfsplus_attr_tree_cachep, GFP_KERNEL);
 86}
 87
 88void hfsplus_destroy_attr_entry(hfsplus_attr_entry *entry)
 89{
 90	if (entry)
 91		kmem_cache_free(hfsplus_attr_tree_cachep, entry);
 92}
 93
 94#define HFSPLUS_INVALID_ATTR_RECORD -1
 95
 96static int hfsplus_attr_build_record(hfsplus_attr_entry *entry, int record_type,
 97				u32 cnid, const void *value, size_t size)
 98{
 99	if (record_type == HFSPLUS_ATTR_FORK_DATA) {
100		/*
101		 * Mac OS X supports only inline data attributes.
102		 * Do nothing
103		 */
104		memset(entry, 0, sizeof(*entry));
105		return sizeof(struct hfsplus_attr_fork_data);
106	} else if (record_type == HFSPLUS_ATTR_EXTENTS) {
107		/*
108		 * Mac OS X supports only inline data attributes.
109		 * Do nothing.
110		 */
111		memset(entry, 0, sizeof(*entry));
112		return sizeof(struct hfsplus_attr_extents);
113	} else if (record_type == HFSPLUS_ATTR_INLINE_DATA) {
114		u16 len;
115
116		memset(entry, 0, sizeof(struct hfsplus_attr_inline_data));
117		entry->inline_data.record_type = cpu_to_be32(record_type);
118		if (size <= HFSPLUS_MAX_INLINE_DATA_SIZE)
119			len = size;
120		else
121			return HFSPLUS_INVALID_ATTR_RECORD;
122		entry->inline_data.length = cpu_to_be16(len);
123		memcpy(entry->inline_data.raw_bytes, value, len);
124		/*
125		 * Align len on two-byte boundary.
126		 * It needs to add pad byte if we have odd len.
127		 */
128		len = round_up(len, 2);
129		return offsetof(struct hfsplus_attr_inline_data, raw_bytes) +
130					len;
131	} else /* invalid input */
132		memset(entry, 0, sizeof(*entry));
133
134	return HFSPLUS_INVALID_ATTR_RECORD;
135}
136
137int hfsplus_find_attr(struct super_block *sb, u32 cnid,
138			const char *name, struct hfs_find_data *fd)
139{
140	int err = 0;
141
142	hfs_dbg(ATTR_MOD, "find_attr: %s,%d\n", name ? name : NULL, cnid);
143
144	if (!HFSPLUS_SB(sb)->attr_tree) {
145		pr_err("attributes file doesn't exist\n");
146		return -EINVAL;
147	}
148
149	if (name) {
150		err = hfsplus_attr_build_key(sb, fd->search_key, cnid, name);
151		if (err)
152			goto failed_find_attr;
153		err = hfs_brec_find(fd, hfs_find_rec_by_key);
154		if (err)
155			goto failed_find_attr;
156	} else {
157		err = hfsplus_attr_build_key(sb, fd->search_key, cnid, NULL);
158		if (err)
159			goto failed_find_attr;
160		err = hfs_brec_find(fd, hfs_find_1st_rec_by_cnid);
161		if (err)
162			goto failed_find_attr;
163	}
164
165failed_find_attr:
166	return err;
167}
168
169int hfsplus_attr_exists(struct inode *inode, const char *name)
170{
171	int err = 0;
172	struct super_block *sb = inode->i_sb;
173	struct hfs_find_data fd;
174
175	if (!HFSPLUS_SB(sb)->attr_tree)
176		return 0;
177
178	err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd);
179	if (err)
180		return 0;
181
182	err = hfsplus_find_attr(sb, inode->i_ino, name, &fd);
183	if (err)
184		goto attr_not_found;
185
186	hfs_find_exit(&fd);
187	return 1;
188
189attr_not_found:
190	hfs_find_exit(&fd);
191	return 0;
192}
193
194int hfsplus_create_attr(struct inode *inode,
195				const char *name,
196				const void *value, size_t size)
197{
198	struct super_block *sb = inode->i_sb;
199	struct hfs_find_data fd;
200	hfsplus_attr_entry *entry_ptr;
201	int entry_size;
202	int err;
203
204	hfs_dbg(ATTR_MOD, "create_attr: %s,%ld\n",
205		name ? name : NULL, inode->i_ino);
206
207	if (!HFSPLUS_SB(sb)->attr_tree) {
208		pr_err("attributes file doesn't exist\n");
209		return -EINVAL;
210	}
211
212	entry_ptr = hfsplus_alloc_attr_entry();
213	if (!entry_ptr)
214		return -ENOMEM;
215
216	err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd);
217	if (err)
218		goto failed_init_create_attr;
219
220	/* Fail early and avoid ENOSPC during the btree operation */
221	err = hfs_bmap_reserve(fd.tree, fd.tree->depth + 1);
222	if (err)
223		goto failed_create_attr;
224
225	if (name) {
226		err = hfsplus_attr_build_key(sb, fd.search_key,
227						inode->i_ino, name);
228		if (err)
229			goto failed_create_attr;
230	} else {
231		err = -EINVAL;
232		goto failed_create_attr;
233	}
234
235	/* Mac OS X supports only inline data attributes. */
236	entry_size = hfsplus_attr_build_record(entry_ptr,
237					HFSPLUS_ATTR_INLINE_DATA,
238					inode->i_ino,
239					value, size);
240	if (entry_size == HFSPLUS_INVALID_ATTR_RECORD) {
241		err = -EINVAL;
242		goto failed_create_attr;
243	}
244
245	err = hfs_brec_find(&fd, hfs_find_rec_by_key);
246	if (err != -ENOENT) {
247		if (!err)
248			err = -EEXIST;
249		goto failed_create_attr;
250	}
251
252	err = hfs_brec_insert(&fd, entry_ptr, entry_size);
253	if (err)
254		goto failed_create_attr;
255
256	hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY);
257
258failed_create_attr:
259	hfs_find_exit(&fd);
260
261failed_init_create_attr:
262	hfsplus_destroy_attr_entry(entry_ptr);
263	return err;
264}
265
266static int __hfsplus_delete_attr(struct inode *inode, u32 cnid,
267					struct hfs_find_data *fd)
268{
269	int err = 0;
270	__be32 found_cnid, record_type;
271
272	hfs_bnode_read(fd->bnode, &found_cnid,
273			fd->keyoffset +
274			offsetof(struct hfsplus_attr_key, cnid),
275			sizeof(__be32));
276	if (cnid != be32_to_cpu(found_cnid))
277		return -ENOENT;
278
279	hfs_bnode_read(fd->bnode, &record_type,
280			fd->entryoffset, sizeof(record_type));
281
282	switch (be32_to_cpu(record_type)) {
283	case HFSPLUS_ATTR_INLINE_DATA:
284		/* All is OK. Do nothing. */
285		break;
286	case HFSPLUS_ATTR_FORK_DATA:
287	case HFSPLUS_ATTR_EXTENTS:
288		pr_err("only inline data xattr are supported\n");
289		return -EOPNOTSUPP;
290	default:
291		pr_err("invalid extended attribute record\n");
292		return -ENOENT;
293	}
294
295	err = hfs_brec_remove(fd);
296	if (err)
297		return err;
298
299	hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY);
300	return err;
301}
302
303int hfsplus_delete_attr(struct inode *inode, const char *name)
304{
305	int err = 0;
306	struct super_block *sb = inode->i_sb;
307	struct hfs_find_data fd;
308
309	hfs_dbg(ATTR_MOD, "delete_attr: %s,%ld\n",
310		name ? name : NULL, inode->i_ino);
311
312	if (!HFSPLUS_SB(sb)->attr_tree) {
313		pr_err("attributes file doesn't exist\n");
314		return -EINVAL;
315	}
316
317	err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd);
318	if (err)
319		return err;
320
321	/* Fail early and avoid ENOSPC during the btree operation */
322	err = hfs_bmap_reserve(fd.tree, fd.tree->depth);
323	if (err)
324		goto out;
325
326	if (name) {
327		err = hfsplus_attr_build_key(sb, fd.search_key,
328						inode->i_ino, name);
329		if (err)
330			goto out;
331	} else {
332		pr_err("invalid extended attribute name\n");
333		err = -EINVAL;
334		goto out;
335	}
336
337	err = hfs_brec_find(&fd, hfs_find_rec_by_key);
338	if (err)
339		goto out;
340
341	err = __hfsplus_delete_attr(inode, inode->i_ino, &fd);
342	if (err)
343		goto out;
344
345out:
346	hfs_find_exit(&fd);
347	return err;
348}
349
350int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid)
351{
352	int err = 0;
353	struct hfs_find_data fd;
354
355	hfs_dbg(ATTR_MOD, "delete_all_attrs: %d\n", cnid);
356
357	if (!HFSPLUS_SB(dir->i_sb)->attr_tree) {
358		pr_err("attributes file doesn't exist\n");
359		return -EINVAL;
360	}
361
362	err = hfs_find_init(HFSPLUS_SB(dir->i_sb)->attr_tree, &fd);
363	if (err)
364		return err;
365
366	for (;;) {
367		err = hfsplus_find_attr(dir->i_sb, cnid, NULL, &fd);
368		if (err) {
369			if (err != -ENOENT)
370				pr_err("xattr search failed\n");
371			goto end_delete_all;
372		}
373
374		err = __hfsplus_delete_attr(dir, cnid, &fd);
375		if (err)
376			goto end_delete_all;
377	}
378
379end_delete_all:
380	hfs_find_exit(&fd);
381	return err;
382}