• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Originally contributed by an anonymous person,
4  * heavily changed by Li Guifu <blucerlee@gmail.com>
5  *                and Gao Xiang <hsiangkao@aol.com>
6  */
7 #define _GNU_SOURCE
8 #include <stdlib.h>
9 #include <sys/xattr.h>
10 #ifdef HAVE_LINUX_XATTR_H
11 #include <linux/xattr.h>
12 #endif
13 #include <sys/stat.h>
14 #include <dirent.h>
15 #include "erofs/print.h"
16 #include "erofs/hashtable.h"
17 #include "erofs/xattr.h"
18 #include "erofs/cache.h"
19 #include "erofs/io.h"
20 #include "liberofs_private.h"
21 
22 #define EA_HASHTABLE_BITS 16
23 
24 struct xattr_item {
25 	const char *kvbuf;
26 	unsigned int hash[2], len[2], count;
27 	int shared_xattr_id;
28 	u8 prefix;
29 	struct hlist_node node;
30 };
31 
32 struct inode_xattr_node {
33 	struct list_head list;
34 	struct xattr_item *item;
35 };
36 
37 static DECLARE_HASHTABLE(ea_hashtable, EA_HASHTABLE_BITS);
38 
39 static LIST_HEAD(shared_xattrs_list);
40 static unsigned int shared_xattrs_count, shared_xattrs_size;
41 
42 static struct xattr_prefix {
43 	const char *prefix;
44 	u16 prefix_len;
45 } xattr_types[] = {
46 	[EROFS_XATTR_INDEX_USER] = {
47 		XATTR_USER_PREFIX,
48 		XATTR_USER_PREFIX_LEN
49 	}, [EROFS_XATTR_INDEX_POSIX_ACL_ACCESS] = {
50 		XATTR_NAME_POSIX_ACL_ACCESS,
51 		sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
52 	}, [EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT] = {
53 		XATTR_NAME_POSIX_ACL_DEFAULT,
54 		sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1
55 	}, [EROFS_XATTR_INDEX_TRUSTED] = {
56 		XATTR_TRUSTED_PREFIX,
57 		XATTR_TRUSTED_PREFIX_LEN
58 	}, [EROFS_XATTR_INDEX_SECURITY] = {
59 		XATTR_SECURITY_PREFIX,
60 		XATTR_SECURITY_PREFIX_LEN
61 	}
62 };
63 
BKDRHash(char * str,unsigned int len)64 static unsigned int BKDRHash(char *str, unsigned int len)
65 {
66 	const unsigned int seed = 131313;
67 	unsigned int hash = 0;
68 
69 	while (len) {
70 		hash = hash * seed + (*str++);
71 		--len;
72 	}
73 	return hash;
74 }
75 
xattr_item_hash(u8 prefix,char * buf,unsigned int len[2],unsigned int hash[2])76 static unsigned int xattr_item_hash(u8 prefix, char *buf,
77 				    unsigned int len[2], unsigned int hash[2])
78 {
79 	hash[0] = BKDRHash(buf, len[0]);	/* key */
80 	hash[1] = BKDRHash(buf + len[0], len[1]);	/* value */
81 
82 	return prefix ^ hash[0] ^ hash[1];
83 }
84 
put_xattritem(struct xattr_item * item)85 static unsigned int put_xattritem(struct xattr_item *item)
86 {
87 	if (item->count > 1)
88 		return --item->count;
89 	free(item);
90 	return 0;
91 }
92 
get_xattritem(u8 prefix,char * kvbuf,unsigned int len[2])93 static struct xattr_item *get_xattritem(u8 prefix, char *kvbuf,
94 					unsigned int len[2])
95 {
96 	struct xattr_item *item;
97 	unsigned int hash[2], hkey;
98 
99 	hkey = xattr_item_hash(prefix, kvbuf, len, hash);
100 
101 	hash_for_each_possible(ea_hashtable, item, node, hkey) {
102 		if (prefix == item->prefix &&
103 		    item->len[0] == len[0] && item->len[1] == len[1] &&
104 		    item->hash[0] == hash[0] && item->hash[1] == hash[1] &&
105 		    !memcmp(kvbuf, item->kvbuf, len[0] + len[1])) {
106 			free(kvbuf);
107 			++item->count;
108 			return item;
109 		}
110 	}
111 
112 	item = malloc(sizeof(*item));
113 	if (!item) {
114 		free(kvbuf);
115 		return ERR_PTR(-ENOMEM);
116 	}
117 	INIT_HLIST_NODE(&item->node);
118 	item->count = 1;
119 	item->kvbuf = kvbuf;
120 	item->len[0] = len[0];
121 	item->len[1] = len[1];
122 	item->hash[0] = hash[0];
123 	item->hash[1] = hash[1];
124 	item->shared_xattr_id = -1;
125 	item->prefix = prefix;
126 	hash_add(ea_hashtable, &item->node, hkey);
127 	return item;
128 }
129 
match_prefix(const char * key,u8 * index,u16 * len)130 static bool match_prefix(const char *key, u8 *index, u16 *len)
131 {
132 	struct xattr_prefix *p;
133 
134 	for (p = xattr_types; p < xattr_types + ARRAY_SIZE(xattr_types); ++p) {
135 		if (p->prefix && !strncmp(p->prefix, key, p->prefix_len)) {
136 			*len = p->prefix_len;
137 			*index = p - xattr_types;
138 			return true;
139 		}
140 	}
141 	return false;
142 }
143 
parse_one_xattr(const char * path,const char * key,unsigned int keylen)144 static struct xattr_item *parse_one_xattr(const char *path, const char *key,
145 					  unsigned int keylen)
146 {
147 	ssize_t ret;
148 	u8 prefix;
149 	u16 prefixlen;
150 	unsigned int len[2];
151 	char *kvbuf;
152 
153 	erofs_dbg("parse xattr [%s] of %s", path, key);
154 
155 	if (!match_prefix(key, &prefix, &prefixlen))
156 		return ERR_PTR(-ENODATA);
157 
158 	DBG_BUGON(keylen < prefixlen);
159 
160 	/* determine length of the value */
161 #ifdef HAVE_LGETXATTR
162 	ret = lgetxattr(path, key, NULL, 0);
163 #elif defined(__APPLE__)
164 	ret = getxattr(path, key, NULL, 0, 0, XATTR_NOFOLLOW);
165 #else
166 	return ERR_PTR(-EOPNOTSUPP);
167 #endif
168 	if (ret < 0)
169 		return ERR_PTR(-errno);
170 	len[1] = ret;
171 
172 	/* allocate key-value buffer */
173 	len[0] = keylen - prefixlen;
174 
175 	kvbuf = malloc(len[0] + len[1]);
176 	if (!kvbuf)
177 		return ERR_PTR(-ENOMEM);
178 	memcpy(kvbuf, key + prefixlen, len[0]);
179 	if (len[1]) {
180 		/* copy value to buffer */
181 #ifdef HAVE_LGETXATTR
182 		ret = lgetxattr(path, key, kvbuf + len[0], len[1]);
183 #elif defined(__APPLE__)
184 		ret = getxattr(path, key, kvbuf + len[0], len[1], 0,
185 			       XATTR_NOFOLLOW);
186 #else
187 		free(kvbuf);
188 		return ERR_PTR(-EOPNOTSUPP);
189 #endif
190 		if (ret < 0) {
191 			free(kvbuf);
192 			return ERR_PTR(-errno);
193 		}
194 		if (len[1] != ret) {
195 			erofs_err("size of xattr value got changed just now (%u-> %ld)",
196 				  len[1], (long)ret);
197 			len[1] = ret;
198 		}
199 	}
200 	return get_xattritem(prefix, kvbuf, len);
201 }
202 
erofs_get_selabel_xattr(const char * srcpath,mode_t mode)203 static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
204 						  mode_t mode)
205 {
206 #ifdef HAVE_LIBSELINUX
207 	if (cfg.sehnd) {
208 		char *secontext;
209 		int ret;
210 		unsigned int len[2];
211 		char *kvbuf, *fspath;
212 
213 #ifdef WITH_ANDROID
214 		if (cfg.mount_point)
215 			ret = asprintf(&fspath, "/%s/%s", cfg.mount_point,
216 				       erofs_fspath(srcpath));
217 		else
218 #endif
219 			ret = asprintf(&fspath, "/%s", erofs_fspath(srcpath));
220 		if (ret <= 0)
221 			return ERR_PTR(-ENOMEM);
222 
223 		ret = selabel_lookup(cfg.sehnd, &secontext, fspath, mode);
224 		free(fspath);
225 
226 		if (ret) {
227 			ret = -errno;
228 			if (ret != -ENOENT) {
229 				erofs_err("failed to lookup selabel for %s: %s",
230 					  srcpath, erofs_strerror(ret));
231 				return ERR_PTR(ret);
232 			}
233 			/* secontext = "u:object_r:unlabeled:s0"; */
234 			return NULL;
235 		}
236 
237 		len[0] = sizeof("selinux") - 1;
238 		len[1] = strlen(secontext);
239 		kvbuf = malloc(len[0] + len[1] + 1);
240 		if (!kvbuf) {
241 			freecon(secontext);
242 			return ERR_PTR(-ENOMEM);
243 		}
244 		sprintf(kvbuf, "selinux%s", secontext);
245 		freecon(secontext);
246 		return get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len);
247 	}
248 #endif
249 	return NULL;
250 }
251 
inode_xattr_add(struct list_head * hlist,struct xattr_item * item)252 static int inode_xattr_add(struct list_head *hlist, struct xattr_item *item)
253 {
254 	struct inode_xattr_node *node = malloc(sizeof(*node));
255 
256 	if (!node)
257 		return -ENOMEM;
258 	init_list_head(&node->list);
259 	node->item = item;
260 	list_add(&node->list, hlist);
261 	return 0;
262 }
263 
shared_xattr_add(struct xattr_item * item)264 static int shared_xattr_add(struct xattr_item *item)
265 {
266 	struct inode_xattr_node *node = malloc(sizeof(*node));
267 
268 	if (!node)
269 		return -ENOMEM;
270 
271 	init_list_head(&node->list);
272 	node->item = item;
273 	list_add(&node->list, &shared_xattrs_list);
274 
275 	shared_xattrs_size += sizeof(struct erofs_xattr_entry);
276 	shared_xattrs_size = EROFS_XATTR_ALIGN(shared_xattrs_size +
277 					       item->len[0] + item->len[1]);
278 	return ++shared_xattrs_count;
279 }
280 
erofs_xattr_add(struct list_head * ixattrs,struct xattr_item * item)281 static int erofs_xattr_add(struct list_head *ixattrs, struct xattr_item *item)
282 {
283 	if (ixattrs)
284 		return inode_xattr_add(ixattrs, item);
285 
286 	if (item->count == cfg.c_inline_xattr_tolerance + 1) {
287 		int ret = shared_xattr_add(item);
288 
289 		if (ret < 0)
290 			return ret;
291 	}
292 	return 0;
293 }
294 
erofs_is_skipped_xattr(const char * key)295 static bool erofs_is_skipped_xattr(const char *key)
296 {
297 #ifdef HAVE_LIBSELINUX
298 	/* if sehnd is valid, selabels will be overridden */
299 	if (cfg.sehnd && !strcmp(key, XATTR_SECURITY_PREFIX "selinux"))
300 		return true;
301 #endif
302 	return false;
303 }
304 
read_xattrs_from_file(const char * path,mode_t mode,struct list_head * ixattrs)305 static int read_xattrs_from_file(const char *path, mode_t mode,
306 				 struct list_head *ixattrs)
307 {
308 #ifdef HAVE_LLISTXATTR
309 	ssize_t kllen = llistxattr(path, NULL, 0);
310 #elif defined(__APPLE__)
311 	ssize_t kllen = listxattr(path, NULL, 0, XATTR_NOFOLLOW);
312 #else
313 	ssize_t kllen = 0;
314 #endif
315 	int ret;
316 	char *keylst, *key, *klend;
317 	unsigned int keylen;
318 	struct xattr_item *item;
319 
320 	if (kllen < 0 && errno != ENODATA) {
321 		erofs_err("llistxattr to get the size of names for %s failed",
322 			  path);
323 		return -errno;
324 	}
325 
326 	ret = 0;
327 	if (kllen <= 1)
328 		goto out;
329 
330 	keylst = malloc(kllen);
331 	if (!keylst)
332 		return -ENOMEM;
333 
334 	/* copy the list of attribute keys to the buffer.*/
335 #ifdef HAVE_LLISTXATTR
336 	kllen = llistxattr(path, keylst, kllen);
337 #elif defined(__APPLE__)
338 	kllen = listxattr(path, keylst, kllen, XATTR_NOFOLLOW);
339 	if (kllen < 0) {
340 		erofs_err("llistxattr to get names for %s failed", path);
341 		ret = -errno;
342 		goto err;
343 	}
344 #else
345 	ret = -EOPNOTSUPP;
346 	goto err;
347 #endif
348 	/*
349 	 * loop over the list of zero terminated strings with the
350 	 * attribute keys. Use the remaining buffer length to determine
351 	 * the end of the list.
352 	 */
353 	klend = keylst + kllen;
354 	ret = 0;
355 
356 	for (key = keylst; key != klend; key += keylen + 1) {
357 		keylen = strlen(key);
358 		if (erofs_is_skipped_xattr(key))
359 			continue;
360 
361 		item = parse_one_xattr(path, key, keylen);
362 		if (IS_ERR(item)) {
363 			ret = PTR_ERR(item);
364 			goto err;
365 		}
366 
367 		ret = erofs_xattr_add(ixattrs, item);
368 		if (ret < 0)
369 			goto err;
370 	}
371 	free(keylst);
372 
373 out:
374 	/* if some selabel is avilable, need to add right now */
375 	item = erofs_get_selabel_xattr(path, mode);
376 	if (IS_ERR(item))
377 		return PTR_ERR(item);
378 	if (item)
379 		ret = erofs_xattr_add(ixattrs, item);
380 	return ret;
381 
382 err:
383 	free(keylst);
384 	return ret;
385 }
386 
387 #ifdef WITH_ANDROID
erofs_droid_xattr_set_caps(struct erofs_inode * inode)388 static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
389 {
390 	const u64 capabilities = inode->capabilities;
391 	char *kvbuf;
392 	unsigned int len[2];
393 	struct vfs_cap_data caps;
394 	struct xattr_item *item;
395 
396 	if (!capabilities)
397 		return 0;
398 
399 	len[0] = sizeof("capability") - 1;
400 	len[1] = sizeof(caps);
401 
402 	kvbuf = malloc(len[0] + len[1]);
403 	if (!kvbuf)
404 		return -ENOMEM;
405 
406 	memcpy(kvbuf, "capability", len[0]);
407 	caps.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;
408 	caps.data[0].permitted = (u32) capabilities;
409 	caps.data[0].inheritable = 0;
410 	caps.data[1].permitted = (u32) (capabilities >> 32);
411 	caps.data[1].inheritable = 0;
412 	memcpy(kvbuf + len[0], &caps, len[1]);
413 
414 	item = get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len);
415 	if (IS_ERR(item))
416 		return PTR_ERR(item);
417 	if (!item)
418 		return 0;
419 
420 	return erofs_xattr_add(&inode->i_xattrs, item);
421 }
422 #else
erofs_droid_xattr_set_caps(struct erofs_inode * inode)423 static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
424 {
425 	return 0;
426 }
427 #endif
428 
erofs_prepare_xattr_ibody(struct erofs_inode * inode)429 int erofs_prepare_xattr_ibody(struct erofs_inode *inode)
430 {
431 	int ret;
432 	struct inode_xattr_node *node;
433 	struct list_head *ixattrs = &inode->i_xattrs;
434 
435 	/* check if xattr is disabled */
436 	if (cfg.c_inline_xattr_tolerance < 0)
437 		return 0;
438 
439 	ret = read_xattrs_from_file(inode->i_srcpath, inode->i_mode, ixattrs);
440 	if (ret < 0)
441 		return ret;
442 
443 	ret = erofs_droid_xattr_set_caps(inode);
444 	if (ret < 0)
445 		return ret;
446 
447 	if (list_empty(ixattrs))
448 		return 0;
449 
450 	/* get xattr ibody size */
451 	ret = sizeof(struct erofs_xattr_ibody_header);
452 	list_for_each_entry(node, ixattrs, list) {
453 		const struct xattr_item *item = node->item;
454 
455 		if (item->shared_xattr_id >= 0) {
456 			ret += sizeof(__le32);
457 			continue;
458 		}
459 		ret += sizeof(struct erofs_xattr_entry);
460 		ret = EROFS_XATTR_ALIGN(ret + item->len[0] + item->len[1]);
461 	}
462 	inode->xattr_isize = ret;
463 	return ret;
464 }
465 
erofs_count_all_xattrs_from_path(const char * path)466 static int erofs_count_all_xattrs_from_path(const char *path)
467 {
468 	int ret;
469 	DIR *_dir;
470 	struct stat64 st;
471 
472 	_dir = opendir(path);
473 	if (!_dir) {
474 		erofs_err("failed to opendir at %s: %s",
475 			  path, erofs_strerror(errno));
476 		return -errno;
477 	}
478 
479 	ret = 0;
480 	while (1) {
481 		struct dirent *dp;
482 		char buf[PATH_MAX];
483 
484 		/*
485 		 * set errno to 0 before calling readdir() in order to
486 		 * distinguish end of stream and from an error.
487 		 */
488 		errno = 0;
489 		dp = readdir(_dir);
490 		if (!dp)
491 			break;
492 
493 		if (is_dot_dotdot(dp->d_name) ||
494 		    !strncmp(dp->d_name, "lost+found", strlen("lost+found")))
495 			continue;
496 
497 		ret = snprintf(buf, PATH_MAX, "%s/%s", path, dp->d_name);
498 
499 		if (ret < 0 || ret >= PATH_MAX) {
500 			/* ignore the too long path */
501 			ret = -ENOMEM;
502 			goto fail;
503 		}
504 
505 		ret = lstat64(buf, &st);
506 		if (ret) {
507 			ret = -errno;
508 			goto fail;
509 		}
510 
511 		ret = read_xattrs_from_file(buf, st.st_mode, NULL);
512 		if (ret)
513 			goto fail;
514 
515 		if (!S_ISDIR(st.st_mode))
516 			continue;
517 
518 		ret = erofs_count_all_xattrs_from_path(buf);
519 		if (ret)
520 			goto fail;
521 	}
522 
523 	if (errno)
524 		ret = -errno;
525 
526 fail:
527 	closedir(_dir);
528 	return ret;
529 }
530 
erofs_cleanxattrs(bool sharedxattrs)531 static void erofs_cleanxattrs(bool sharedxattrs)
532 {
533 	unsigned int i;
534 	struct xattr_item *item;
535 	struct hlist_node *tmp;
536 
537 	hash_for_each_safe(ea_hashtable, i, tmp, item, node) {
538 		if (sharedxattrs && item->shared_xattr_id >= 0)
539 			continue;
540 
541 		hash_del(&item->node);
542 		free(item);
543 	}
544 
545 	if (sharedxattrs)
546 		return;
547 
548 	shared_xattrs_size = shared_xattrs_count = 0;
549 }
550 
erofs_bh_flush_write_shared_xattrs(struct erofs_buffer_head * bh)551 static bool erofs_bh_flush_write_shared_xattrs(struct erofs_buffer_head *bh)
552 {
553 	void *buf = bh->fsprivate;
554 	int err = dev_write(buf, erofs_btell(bh, false), shared_xattrs_size);
555 
556 	if (err)
557 		return false;
558 	free(buf);
559 	return erofs_bh_flush_generic_end(bh);
560 }
561 
562 static struct erofs_bhops erofs_write_shared_xattrs_bhops = {
563 	.flush = erofs_bh_flush_write_shared_xattrs,
564 };
565 
erofs_build_shared_xattrs_from_path(const char * path)566 int erofs_build_shared_xattrs_from_path(const char *path)
567 {
568 	int ret;
569 	struct erofs_buffer_head *bh;
570 	struct inode_xattr_node *node, *n;
571 	char *buf;
572 	unsigned int p;
573 	erofs_off_t off;
574 
575 	/* check if xattr or shared xattr is disabled */
576 	if (cfg.c_inline_xattr_tolerance < 0 ||
577 	    cfg.c_inline_xattr_tolerance == INT_MAX)
578 		return 0;
579 
580 	if (shared_xattrs_size || shared_xattrs_count) {
581 		DBG_BUGON(1);
582 		return -EINVAL;
583 	}
584 
585 	ret = erofs_count_all_xattrs_from_path(path);
586 	if (ret)
587 		return ret;
588 
589 	if (!shared_xattrs_size)
590 		goto out;
591 
592 	buf = calloc(1, shared_xattrs_size);
593 	if (!buf)
594 		return -ENOMEM;
595 
596 	bh = erofs_balloc(XATTR, shared_xattrs_size, 0, 0);
597 	if (IS_ERR(bh)) {
598 		free(buf);
599 		return PTR_ERR(bh);
600 	}
601 	bh->op = &erofs_skip_write_bhops;
602 
603 	erofs_mapbh(bh->block);
604 	off = erofs_btell(bh, false);
605 
606 	sbi.xattr_blkaddr = off / EROFS_BLKSIZ;
607 	off %= EROFS_BLKSIZ;
608 	p = 0;
609 
610 	list_for_each_entry_safe(node, n, &shared_xattrs_list, list) {
611 		struct xattr_item *const item = node->item;
612 		const struct erofs_xattr_entry entry = {
613 			.e_name_index = item->prefix,
614 			.e_name_len = item->len[0],
615 			.e_value_size = cpu_to_le16(item->len[1])
616 		};
617 
618 		list_del(&node->list);
619 
620 		item->shared_xattr_id = (off + p) /
621 			sizeof(struct erofs_xattr_entry);
622 
623 		memcpy(buf + p, &entry, sizeof(entry));
624 		p += sizeof(struct erofs_xattr_entry);
625 		memcpy(buf + p, item->kvbuf, item->len[0] + item->len[1]);
626 		p = EROFS_XATTR_ALIGN(p + item->len[0] + item->len[1]);
627 		free(node);
628 	}
629 	bh->fsprivate = buf;
630 	bh->op = &erofs_write_shared_xattrs_bhops;
631 out:
632 	erofs_cleanxattrs(true);
633 	return 0;
634 }
635 
erofs_export_xattr_ibody(struct list_head * ixattrs,unsigned int size)636 char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size)
637 {
638 	struct inode_xattr_node *node, *n;
639 	struct erofs_xattr_ibody_header *header;
640 	LIST_HEAD(ilst);
641 	unsigned int p;
642 	char *buf = calloc(1, size);
643 
644 	if (!buf)
645 		return ERR_PTR(-ENOMEM);
646 
647 	header = (struct erofs_xattr_ibody_header *)buf;
648 	header->h_shared_count = 0;
649 
650 	p = sizeof(struct erofs_xattr_ibody_header);
651 	list_for_each_entry_safe(node, n, ixattrs, list) {
652 		struct xattr_item *const item = node->item;
653 
654 		list_del(&node->list);
655 
656 		/* move inline xattrs to the onstack list */
657 		if (item->shared_xattr_id < 0) {
658 			list_add(&node->list, &ilst);
659 			continue;
660 		}
661 
662 		*(__le32 *)(buf + p) = cpu_to_le32(item->shared_xattr_id);
663 		p += sizeof(__le32);
664 		++header->h_shared_count;
665 		free(node);
666 		put_xattritem(item);
667 	}
668 
669 	list_for_each_entry_safe(node, n, &ilst, list) {
670 		struct xattr_item *const item = node->item;
671 		const struct erofs_xattr_entry entry = {
672 			.e_name_index = item->prefix,
673 			.e_name_len = item->len[0],
674 			.e_value_size = cpu_to_le16(item->len[1])
675 		};
676 
677 		memcpy(buf + p, &entry, sizeof(entry));
678 		p += sizeof(struct erofs_xattr_entry);
679 		memcpy(buf + p, item->kvbuf, item->len[0] + item->len[1]);
680 		p = EROFS_XATTR_ALIGN(p + item->len[0] + item->len[1]);
681 
682 		list_del(&node->list);
683 		free(node);
684 		put_xattritem(item);
685 	}
686 	DBG_BUGON(p > size);
687 	return buf;
688 }
689