xref: /aosp_15_r20/external/erofs-utils/lib/xattr.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2*33b1fccfSAndroid Build Coastguard Worker /*
3*33b1fccfSAndroid Build Coastguard Worker  * Originally contributed by an anonymous person,
4*33b1fccfSAndroid Build Coastguard Worker  * heavily changed by Li Guifu <[email protected]>
5*33b1fccfSAndroid Build Coastguard Worker  *                and Gao Xiang <[email protected]>
6*33b1fccfSAndroid Build Coastguard Worker  */
7*33b1fccfSAndroid Build Coastguard Worker #define _GNU_SOURCE
8*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
9*33b1fccfSAndroid Build Coastguard Worker #include <sys/xattr.h>
10*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LINUX_XATTR_H
11*33b1fccfSAndroid Build Coastguard Worker #include <linux/xattr.h>
12*33b1fccfSAndroid Build Coastguard Worker #endif
13*33b1fccfSAndroid Build Coastguard Worker #include <sys/stat.h>
14*33b1fccfSAndroid Build Coastguard Worker #include <dirent.h>
15*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
16*33b1fccfSAndroid Build Coastguard Worker #include "erofs/hashtable.h"
17*33b1fccfSAndroid Build Coastguard Worker #include "erofs/xattr.h"
18*33b1fccfSAndroid Build Coastguard Worker #include "erofs/cache.h"
19*33b1fccfSAndroid Build Coastguard Worker #include "erofs/fragments.h"
20*33b1fccfSAndroid Build Coastguard Worker #include "xxhash.h"
21*33b1fccfSAndroid Build Coastguard Worker #include "liberofs_private.h"
22*33b1fccfSAndroid Build Coastguard Worker 
23*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_SYSTEM_PREFIX
24*33b1fccfSAndroid Build Coastguard Worker #define XATTR_SYSTEM_PREFIX	"system."
25*33b1fccfSAndroid Build Coastguard Worker #endif
26*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_SYSTEM_PREFIX_LEN
27*33b1fccfSAndroid Build Coastguard Worker #define XATTR_SYSTEM_PREFIX_LEN (sizeof(XATTR_SYSTEM_PREFIX) - 1)
28*33b1fccfSAndroid Build Coastguard Worker #endif
29*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_USER_PREFIX
30*33b1fccfSAndroid Build Coastguard Worker #define XATTR_USER_PREFIX	"user."
31*33b1fccfSAndroid Build Coastguard Worker #endif
32*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_USER_PREFIX_LEN
33*33b1fccfSAndroid Build Coastguard Worker #define XATTR_USER_PREFIX_LEN (sizeof(XATTR_USER_PREFIX) - 1)
34*33b1fccfSAndroid Build Coastguard Worker #endif
35*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_SECURITY_PREFIX
36*33b1fccfSAndroid Build Coastguard Worker #define XATTR_SECURITY_PREFIX	"security."
37*33b1fccfSAndroid Build Coastguard Worker #endif
38*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_SECURITY_PREFIX_LEN
39*33b1fccfSAndroid Build Coastguard Worker #define XATTR_SECURITY_PREFIX_LEN (sizeof(XATTR_SECURITY_PREFIX) - 1)
40*33b1fccfSAndroid Build Coastguard Worker #endif
41*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_TRUSTED_PREFIX
42*33b1fccfSAndroid Build Coastguard Worker #define XATTR_TRUSTED_PREFIX	"trusted."
43*33b1fccfSAndroid Build Coastguard Worker #endif
44*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_TRUSTED_PREFIX_LEN
45*33b1fccfSAndroid Build Coastguard Worker #define XATTR_TRUSTED_PREFIX_LEN (sizeof(XATTR_TRUSTED_PREFIX) - 1)
46*33b1fccfSAndroid Build Coastguard Worker #endif
47*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_NAME_POSIX_ACL_ACCESS
48*33b1fccfSAndroid Build Coastguard Worker #define XATTR_NAME_POSIX_ACL_ACCESS "system.posix_acl_access"
49*33b1fccfSAndroid Build Coastguard Worker #endif
50*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_NAME_POSIX_ACL_DEFAULT
51*33b1fccfSAndroid Build Coastguard Worker #define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
52*33b1fccfSAndroid Build Coastguard Worker #endif
53*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_NAME_SECURITY_SELINUX
54*33b1fccfSAndroid Build Coastguard Worker #define XATTR_NAME_SECURITY_SELINUX "security.selinux"
55*33b1fccfSAndroid Build Coastguard Worker #endif
56*33b1fccfSAndroid Build Coastguard Worker #ifndef XATTR_NAME_SECURITY_CAPABILITY
57*33b1fccfSAndroid Build Coastguard Worker #define XATTR_NAME_SECURITY_CAPABILITY "security.capability"
58*33b1fccfSAndroid Build Coastguard Worker #endif
59*33b1fccfSAndroid Build Coastguard Worker #ifndef OVL_XATTR_NAMESPACE
60*33b1fccfSAndroid Build Coastguard Worker #define OVL_XATTR_NAMESPACE "overlay."
61*33b1fccfSAndroid Build Coastguard Worker #endif
62*33b1fccfSAndroid Build Coastguard Worker #ifndef OVL_XATTR_OPAQUE_POSTFIX
63*33b1fccfSAndroid Build Coastguard Worker #define OVL_XATTR_OPAQUE_POSTFIX "opaque"
64*33b1fccfSAndroid Build Coastguard Worker #endif
65*33b1fccfSAndroid Build Coastguard Worker #ifndef OVL_XATTR_ORIGIN_POSTFIX
66*33b1fccfSAndroid Build Coastguard Worker #define OVL_XATTR_ORIGIN_POSTFIX "origin"
67*33b1fccfSAndroid Build Coastguard Worker #endif
68*33b1fccfSAndroid Build Coastguard Worker #ifndef OVL_XATTR_TRUSTED_PREFIX
69*33b1fccfSAndroid Build Coastguard Worker #define OVL_XATTR_TRUSTED_PREFIX XATTR_TRUSTED_PREFIX OVL_XATTR_NAMESPACE
70*33b1fccfSAndroid Build Coastguard Worker #endif
71*33b1fccfSAndroid Build Coastguard Worker #ifndef OVL_XATTR_OPAQUE
72*33b1fccfSAndroid Build Coastguard Worker #define OVL_XATTR_OPAQUE OVL_XATTR_TRUSTED_PREFIX OVL_XATTR_OPAQUE_POSTFIX
73*33b1fccfSAndroid Build Coastguard Worker #endif
74*33b1fccfSAndroid Build Coastguard Worker #ifndef OVL_XATTR_ORIGIN
75*33b1fccfSAndroid Build Coastguard Worker #define OVL_XATTR_ORIGIN OVL_XATTR_TRUSTED_PREFIX OVL_XATTR_ORIGIN_POSTFIX
76*33b1fccfSAndroid Build Coastguard Worker #endif
77*33b1fccfSAndroid Build Coastguard Worker 
78*33b1fccfSAndroid Build Coastguard Worker #define EA_HASHTABLE_BITS 16
79*33b1fccfSAndroid Build Coastguard Worker 
80*33b1fccfSAndroid Build Coastguard Worker /* one extra byte for the trailing `\0` of attribute name */
81*33b1fccfSAndroid Build Coastguard Worker #define EROFS_XATTR_KSIZE(kvlen)	(kvlen[0] + 1)
82*33b1fccfSAndroid Build Coastguard Worker #define EROFS_XATTR_KVSIZE(kvlen)	(EROFS_XATTR_KSIZE(kvlen) + kvlen[1])
83*33b1fccfSAndroid Build Coastguard Worker 
84*33b1fccfSAndroid Build Coastguard Worker /*
85*33b1fccfSAndroid Build Coastguard Worker  * @base_index:	the index of the matched predefined short prefix
86*33b1fccfSAndroid Build Coastguard Worker  * @prefix:	the index of the matched long prefix, if any;
87*33b1fccfSAndroid Build Coastguard Worker  *		same as base_index otherwise
88*33b1fccfSAndroid Build Coastguard Worker  * @prefix_len:	the length of the matched long prefix if any;
89*33b1fccfSAndroid Build Coastguard Worker  *		the length of the matched predefined short prefix otherwise
90*33b1fccfSAndroid Build Coastguard Worker  */
91*33b1fccfSAndroid Build Coastguard Worker struct xattr_item {
92*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_item *next_shared_xattr;
93*33b1fccfSAndroid Build Coastguard Worker 	const char *kvbuf;
94*33b1fccfSAndroid Build Coastguard Worker 	unsigned int hash[2], len[2], count;
95*33b1fccfSAndroid Build Coastguard Worker 	int shared_xattr_id;
96*33b1fccfSAndroid Build Coastguard Worker 	unsigned int prefix, base_index, prefix_len;
97*33b1fccfSAndroid Build Coastguard Worker 	struct hlist_node node;
98*33b1fccfSAndroid Build Coastguard Worker };
99*33b1fccfSAndroid Build Coastguard Worker 
100*33b1fccfSAndroid Build Coastguard Worker struct inode_xattr_node {
101*33b1fccfSAndroid Build Coastguard Worker 	struct list_head list;
102*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_item *item;
103*33b1fccfSAndroid Build Coastguard Worker };
104*33b1fccfSAndroid Build Coastguard Worker 
105*33b1fccfSAndroid Build Coastguard Worker static DECLARE_HASHTABLE(ea_hashtable, EA_HASHTABLE_BITS);
106*33b1fccfSAndroid Build Coastguard Worker 
107*33b1fccfSAndroid Build Coastguard Worker static struct xattr_item *shared_xattrs_list;
108*33b1fccfSAndroid Build Coastguard Worker static unsigned int shared_xattrs_count;
109*33b1fccfSAndroid Build Coastguard Worker 
110*33b1fccfSAndroid Build Coastguard Worker static struct xattr_prefix {
111*33b1fccfSAndroid Build Coastguard Worker 	const char *prefix;
112*33b1fccfSAndroid Build Coastguard Worker 	unsigned int prefix_len;
113*33b1fccfSAndroid Build Coastguard Worker } xattr_types[] = {
114*33b1fccfSAndroid Build Coastguard Worker 	[EROFS_XATTR_INDEX_USER] = {
115*33b1fccfSAndroid Build Coastguard Worker 		XATTR_USER_PREFIX,
116*33b1fccfSAndroid Build Coastguard Worker 		XATTR_USER_PREFIX_LEN
117*33b1fccfSAndroid Build Coastguard Worker 	}, [EROFS_XATTR_INDEX_POSIX_ACL_ACCESS] = {
118*33b1fccfSAndroid Build Coastguard Worker 		XATTR_NAME_POSIX_ACL_ACCESS,
119*33b1fccfSAndroid Build Coastguard Worker 		sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
120*33b1fccfSAndroid Build Coastguard Worker 	}, [EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT] = {
121*33b1fccfSAndroid Build Coastguard Worker 		XATTR_NAME_POSIX_ACL_DEFAULT,
122*33b1fccfSAndroid Build Coastguard Worker 		sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1
123*33b1fccfSAndroid Build Coastguard Worker 	}, [EROFS_XATTR_INDEX_TRUSTED] = {
124*33b1fccfSAndroid Build Coastguard Worker 		XATTR_TRUSTED_PREFIX,
125*33b1fccfSAndroid Build Coastguard Worker 		XATTR_TRUSTED_PREFIX_LEN
126*33b1fccfSAndroid Build Coastguard Worker 	}, [EROFS_XATTR_INDEX_SECURITY] = {
127*33b1fccfSAndroid Build Coastguard Worker 		XATTR_SECURITY_PREFIX,
128*33b1fccfSAndroid Build Coastguard Worker 		XATTR_SECURITY_PREFIX_LEN
129*33b1fccfSAndroid Build Coastguard Worker 	}
130*33b1fccfSAndroid Build Coastguard Worker };
131*33b1fccfSAndroid Build Coastguard Worker 
132*33b1fccfSAndroid Build Coastguard Worker struct ea_type_node {
133*33b1fccfSAndroid Build Coastguard Worker 	struct list_head list;
134*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_prefix type;
135*33b1fccfSAndroid Build Coastguard Worker 	unsigned int index, base_index, base_len;
136*33b1fccfSAndroid Build Coastguard Worker };
137*33b1fccfSAndroid Build Coastguard Worker 
138*33b1fccfSAndroid Build Coastguard Worker static LIST_HEAD(ea_name_prefixes);
139*33b1fccfSAndroid Build Coastguard Worker static unsigned int ea_prefix_count;
140*33b1fccfSAndroid Build Coastguard Worker 
match_prefix(const char * key,unsigned int * index,unsigned int * len)141*33b1fccfSAndroid Build Coastguard Worker static bool match_prefix(const char *key, unsigned int *index,
142*33b1fccfSAndroid Build Coastguard Worker 			 unsigned int *len)
143*33b1fccfSAndroid Build Coastguard Worker {
144*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_prefix *p;
145*33b1fccfSAndroid Build Coastguard Worker 
146*33b1fccfSAndroid Build Coastguard Worker 	for (p = xattr_types; p < xattr_types + ARRAY_SIZE(xattr_types); ++p) {
147*33b1fccfSAndroid Build Coastguard Worker 		if (p->prefix && !strncmp(p->prefix, key, p->prefix_len)) {
148*33b1fccfSAndroid Build Coastguard Worker 			*len = p->prefix_len;
149*33b1fccfSAndroid Build Coastguard Worker 			*index = p - xattr_types;
150*33b1fccfSAndroid Build Coastguard Worker 			return true;
151*33b1fccfSAndroid Build Coastguard Worker 		}
152*33b1fccfSAndroid Build Coastguard Worker 	}
153*33b1fccfSAndroid Build Coastguard Worker 	return false;
154*33b1fccfSAndroid Build Coastguard Worker }
155*33b1fccfSAndroid Build Coastguard Worker 
BKDRHash(char * str,unsigned int len)156*33b1fccfSAndroid Build Coastguard Worker static unsigned int BKDRHash(char *str, unsigned int len)
157*33b1fccfSAndroid Build Coastguard Worker {
158*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int seed = 131313;
159*33b1fccfSAndroid Build Coastguard Worker 	unsigned int hash = 0;
160*33b1fccfSAndroid Build Coastguard Worker 
161*33b1fccfSAndroid Build Coastguard Worker 	while (len) {
162*33b1fccfSAndroid Build Coastguard Worker 		hash = hash * seed + (*str++);
163*33b1fccfSAndroid Build Coastguard Worker 		--len;
164*33b1fccfSAndroid Build Coastguard Worker 	}
165*33b1fccfSAndroid Build Coastguard Worker 	return hash;
166*33b1fccfSAndroid Build Coastguard Worker }
167*33b1fccfSAndroid Build Coastguard Worker 
put_xattritem(struct xattr_item * item)168*33b1fccfSAndroid Build Coastguard Worker static unsigned int put_xattritem(struct xattr_item *item)
169*33b1fccfSAndroid Build Coastguard Worker {
170*33b1fccfSAndroid Build Coastguard Worker 	if (item->count > 1)
171*33b1fccfSAndroid Build Coastguard Worker 		return --item->count;
172*33b1fccfSAndroid Build Coastguard Worker 	free(item);
173*33b1fccfSAndroid Build Coastguard Worker 	return 0;
174*33b1fccfSAndroid Build Coastguard Worker }
175*33b1fccfSAndroid Build Coastguard Worker 
get_xattritem(char * kvbuf,unsigned int len[2])176*33b1fccfSAndroid Build Coastguard Worker static struct xattr_item *get_xattritem(char *kvbuf, unsigned int len[2])
177*33b1fccfSAndroid Build Coastguard Worker {
178*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_item *item;
179*33b1fccfSAndroid Build Coastguard Worker 	struct ea_type_node *tnode;
180*33b1fccfSAndroid Build Coastguard Worker 	unsigned int hash[2], hkey;
181*33b1fccfSAndroid Build Coastguard Worker 
182*33b1fccfSAndroid Build Coastguard Worker 	hash[0] = BKDRHash(kvbuf, len[0]);
183*33b1fccfSAndroid Build Coastguard Worker 	hash[1] = BKDRHash(kvbuf + EROFS_XATTR_KSIZE(len), len[1]);
184*33b1fccfSAndroid Build Coastguard Worker 	hkey = hash[0] ^ hash[1];
185*33b1fccfSAndroid Build Coastguard Worker 	hash_for_each_possible(ea_hashtable, item, node, hkey) {
186*33b1fccfSAndroid Build Coastguard Worker 		if (item->len[0] == len[0] && item->len[1] == len[1] &&
187*33b1fccfSAndroid Build Coastguard Worker 		    item->hash[0] == hash[0] && item->hash[1] == hash[1] &&
188*33b1fccfSAndroid Build Coastguard Worker 		    !memcmp(kvbuf, item->kvbuf, EROFS_XATTR_KVSIZE(len))) {
189*33b1fccfSAndroid Build Coastguard Worker 			free(kvbuf);
190*33b1fccfSAndroid Build Coastguard Worker 			++item->count;
191*33b1fccfSAndroid Build Coastguard Worker 			return item;
192*33b1fccfSAndroid Build Coastguard Worker 		}
193*33b1fccfSAndroid Build Coastguard Worker 	}
194*33b1fccfSAndroid Build Coastguard Worker 
195*33b1fccfSAndroid Build Coastguard Worker 	item = malloc(sizeof(*item));
196*33b1fccfSAndroid Build Coastguard Worker 	if (!item)
197*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(-ENOMEM);
198*33b1fccfSAndroid Build Coastguard Worker 
199*33b1fccfSAndroid Build Coastguard Worker 	if (!match_prefix(kvbuf, &item->base_index, &item->prefix_len)) {
200*33b1fccfSAndroid Build Coastguard Worker 		free(item);
201*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(-ENODATA);
202*33b1fccfSAndroid Build Coastguard Worker 	}
203*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(len[0] < item->prefix_len);
204*33b1fccfSAndroid Build Coastguard Worker 
205*33b1fccfSAndroid Build Coastguard Worker 	INIT_HLIST_NODE(&item->node);
206*33b1fccfSAndroid Build Coastguard Worker 	item->count = 1;
207*33b1fccfSAndroid Build Coastguard Worker 	item->kvbuf = kvbuf;
208*33b1fccfSAndroid Build Coastguard Worker 	item->len[0] = len[0];
209*33b1fccfSAndroid Build Coastguard Worker 	item->len[1] = len[1];
210*33b1fccfSAndroid Build Coastguard Worker 	item->hash[0] = hash[0];
211*33b1fccfSAndroid Build Coastguard Worker 	item->hash[1] = hash[1];
212*33b1fccfSAndroid Build Coastguard Worker 	item->shared_xattr_id = -1;
213*33b1fccfSAndroid Build Coastguard Worker 	item->prefix = item->base_index;
214*33b1fccfSAndroid Build Coastguard Worker 
215*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry(tnode, &ea_name_prefixes, list) {
216*33b1fccfSAndroid Build Coastguard Worker 		if (item->base_index == tnode->base_index &&
217*33b1fccfSAndroid Build Coastguard Worker 		    !strncmp(tnode->type.prefix, kvbuf,
218*33b1fccfSAndroid Build Coastguard Worker 			     tnode->type.prefix_len)) {
219*33b1fccfSAndroid Build Coastguard Worker 			item->prefix = tnode->index;
220*33b1fccfSAndroid Build Coastguard Worker 			item->prefix_len = tnode->type.prefix_len;
221*33b1fccfSAndroid Build Coastguard Worker 			break;
222*33b1fccfSAndroid Build Coastguard Worker 		}
223*33b1fccfSAndroid Build Coastguard Worker 	}
224*33b1fccfSAndroid Build Coastguard Worker 	hash_add(ea_hashtable, &item->node, hkey);
225*33b1fccfSAndroid Build Coastguard Worker 	return item;
226*33b1fccfSAndroid Build Coastguard Worker }
227*33b1fccfSAndroid Build Coastguard Worker 
parse_one_xattr(const char * path,const char * key,unsigned int keylen)228*33b1fccfSAndroid Build Coastguard Worker static struct xattr_item *parse_one_xattr(const char *path, const char *key,
229*33b1fccfSAndroid Build Coastguard Worker 					  unsigned int keylen)
230*33b1fccfSAndroid Build Coastguard Worker {
231*33b1fccfSAndroid Build Coastguard Worker 	ssize_t ret;
232*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_item *item;
233*33b1fccfSAndroid Build Coastguard Worker 	unsigned int len[2];
234*33b1fccfSAndroid Build Coastguard Worker 	char *kvbuf;
235*33b1fccfSAndroid Build Coastguard Worker 
236*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("parse xattr [%s] of %s", path, key);
237*33b1fccfSAndroid Build Coastguard Worker 
238*33b1fccfSAndroid Build Coastguard Worker 	/* length of the key */
239*33b1fccfSAndroid Build Coastguard Worker 	len[0] = keylen;
240*33b1fccfSAndroid Build Coastguard Worker 
241*33b1fccfSAndroid Build Coastguard Worker 	/* determine length of the value */
242*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LGETXATTR
243*33b1fccfSAndroid Build Coastguard Worker 	ret = lgetxattr(path, key, NULL, 0);
244*33b1fccfSAndroid Build Coastguard Worker #elif defined(__APPLE__)
245*33b1fccfSAndroid Build Coastguard Worker 	ret = getxattr(path, key, NULL, 0, 0, XATTR_NOFOLLOW);
246*33b1fccfSAndroid Build Coastguard Worker #else
247*33b1fccfSAndroid Build Coastguard Worker 	return ERR_PTR(-EOPNOTSUPP);
248*33b1fccfSAndroid Build Coastguard Worker #endif
249*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
250*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(-errno);
251*33b1fccfSAndroid Build Coastguard Worker 	len[1] = ret;
252*33b1fccfSAndroid Build Coastguard Worker 
253*33b1fccfSAndroid Build Coastguard Worker 	/* allocate key-value buffer */
254*33b1fccfSAndroid Build Coastguard Worker 	kvbuf = malloc(EROFS_XATTR_KVSIZE(len));
255*33b1fccfSAndroid Build Coastguard Worker 	if (!kvbuf)
256*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(-ENOMEM);
257*33b1fccfSAndroid Build Coastguard Worker 	memcpy(kvbuf, key, EROFS_XATTR_KSIZE(len));
258*33b1fccfSAndroid Build Coastguard Worker 	if (len[1]) {
259*33b1fccfSAndroid Build Coastguard Worker 		/* copy value to buffer */
260*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LGETXATTR
261*33b1fccfSAndroid Build Coastguard Worker 		ret = lgetxattr(path, key, kvbuf + EROFS_XATTR_KSIZE(len),
262*33b1fccfSAndroid Build Coastguard Worker 				len[1]);
263*33b1fccfSAndroid Build Coastguard Worker #elif defined(__APPLE__)
264*33b1fccfSAndroid Build Coastguard Worker 		ret = getxattr(path, key, kvbuf + EROFS_XATTR_KSIZE(len),
265*33b1fccfSAndroid Build Coastguard Worker 			       len[1], 0, XATTR_NOFOLLOW);
266*33b1fccfSAndroid Build Coastguard Worker #else
267*33b1fccfSAndroid Build Coastguard Worker 		ret = -EOPNOTSUPP;
268*33b1fccfSAndroid Build Coastguard Worker 		goto out;
269*33b1fccfSAndroid Build Coastguard Worker #endif
270*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0) {
271*33b1fccfSAndroid Build Coastguard Worker 			ret = -errno;
272*33b1fccfSAndroid Build Coastguard Worker 			goto out;
273*33b1fccfSAndroid Build Coastguard Worker 		}
274*33b1fccfSAndroid Build Coastguard Worker 		if (len[1] != ret) {
275*33b1fccfSAndroid Build Coastguard Worker 			erofs_warn("size of xattr value got changed just now (%u-> %ld)",
276*33b1fccfSAndroid Build Coastguard Worker 				  len[1], (long)ret);
277*33b1fccfSAndroid Build Coastguard Worker 			len[1] = ret;
278*33b1fccfSAndroid Build Coastguard Worker 		}
279*33b1fccfSAndroid Build Coastguard Worker 	}
280*33b1fccfSAndroid Build Coastguard Worker 
281*33b1fccfSAndroid Build Coastguard Worker 	item = get_xattritem(kvbuf, len);
282*33b1fccfSAndroid Build Coastguard Worker 	if (!IS_ERR(item))
283*33b1fccfSAndroid Build Coastguard Worker 		return item;
284*33b1fccfSAndroid Build Coastguard Worker 	if (item == ERR_PTR(-ENODATA)) {
285*33b1fccfSAndroid Build Coastguard Worker 		erofs_warn("skipped unidentified xattr: %s", key);
286*33b1fccfSAndroid Build Coastguard Worker 		ret = 0;
287*33b1fccfSAndroid Build Coastguard Worker 	} else {
288*33b1fccfSAndroid Build Coastguard Worker 		ret = PTR_ERR(item);
289*33b1fccfSAndroid Build Coastguard Worker 	}
290*33b1fccfSAndroid Build Coastguard Worker out:
291*33b1fccfSAndroid Build Coastguard Worker 	free(kvbuf);
292*33b1fccfSAndroid Build Coastguard Worker 	return ERR_PTR(ret);
293*33b1fccfSAndroid Build Coastguard Worker }
294*33b1fccfSAndroid Build Coastguard Worker 
erofs_get_selabel_xattr(const char * srcpath,mode_t mode)295*33b1fccfSAndroid Build Coastguard Worker static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
296*33b1fccfSAndroid Build Coastguard Worker 						  mode_t mode)
297*33b1fccfSAndroid Build Coastguard Worker {
298*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBSELINUX
299*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.sehnd) {
300*33b1fccfSAndroid Build Coastguard Worker 		char *secontext;
301*33b1fccfSAndroid Build Coastguard Worker 		int ret;
302*33b1fccfSAndroid Build Coastguard Worker 		unsigned int len[2];
303*33b1fccfSAndroid Build Coastguard Worker 		char *kvbuf, *fspath;
304*33b1fccfSAndroid Build Coastguard Worker 		struct xattr_item *item;
305*33b1fccfSAndroid Build Coastguard Worker 
306*33b1fccfSAndroid Build Coastguard Worker 		if (cfg.mount_point)
307*33b1fccfSAndroid Build Coastguard Worker 			ret = asprintf(&fspath, "/%s/%s", cfg.mount_point,
308*33b1fccfSAndroid Build Coastguard Worker 				       erofs_fspath(srcpath));
309*33b1fccfSAndroid Build Coastguard Worker 		else
310*33b1fccfSAndroid Build Coastguard Worker 			ret = asprintf(&fspath, "/%s", erofs_fspath(srcpath));
311*33b1fccfSAndroid Build Coastguard Worker 		if (ret <= 0)
312*33b1fccfSAndroid Build Coastguard Worker 			return ERR_PTR(-ENOMEM);
313*33b1fccfSAndroid Build Coastguard Worker 
314*33b1fccfSAndroid Build Coastguard Worker 		ret = selabel_lookup(cfg.sehnd, &secontext, fspath, mode);
315*33b1fccfSAndroid Build Coastguard Worker 		free(fspath);
316*33b1fccfSAndroid Build Coastguard Worker 
317*33b1fccfSAndroid Build Coastguard Worker 		if (ret) {
318*33b1fccfSAndroid Build Coastguard Worker 			ret = -errno;
319*33b1fccfSAndroid Build Coastguard Worker 			if (ret != -ENOENT) {
320*33b1fccfSAndroid Build Coastguard Worker 				erofs_err("failed to lookup selabel for %s: %s",
321*33b1fccfSAndroid Build Coastguard Worker 					  srcpath, erofs_strerror(ret));
322*33b1fccfSAndroid Build Coastguard Worker 				return ERR_PTR(ret);
323*33b1fccfSAndroid Build Coastguard Worker 			}
324*33b1fccfSAndroid Build Coastguard Worker 			/* secontext = "u:object_r:unlabeled:s0"; */
325*33b1fccfSAndroid Build Coastguard Worker 			return NULL;
326*33b1fccfSAndroid Build Coastguard Worker 		}
327*33b1fccfSAndroid Build Coastguard Worker 
328*33b1fccfSAndroid Build Coastguard Worker 		len[0] = sizeof(XATTR_NAME_SECURITY_SELINUX) - 1;
329*33b1fccfSAndroid Build Coastguard Worker 		len[1] = strlen(secontext);
330*33b1fccfSAndroid Build Coastguard Worker 		kvbuf = malloc(EROFS_XATTR_KVSIZE(len));
331*33b1fccfSAndroid Build Coastguard Worker 		if (!kvbuf) {
332*33b1fccfSAndroid Build Coastguard Worker 			freecon(secontext);
333*33b1fccfSAndroid Build Coastguard Worker 			return ERR_PTR(-ENOMEM);
334*33b1fccfSAndroid Build Coastguard Worker 		}
335*33b1fccfSAndroid Build Coastguard Worker 		sprintf(kvbuf, "%s", XATTR_NAME_SECURITY_SELINUX);
336*33b1fccfSAndroid Build Coastguard Worker 		memcpy(kvbuf + EROFS_XATTR_KSIZE(len), secontext, len[1]);
337*33b1fccfSAndroid Build Coastguard Worker 		freecon(secontext);
338*33b1fccfSAndroid Build Coastguard Worker 		item = get_xattritem(kvbuf, len);
339*33b1fccfSAndroid Build Coastguard Worker 		if (IS_ERR(item))
340*33b1fccfSAndroid Build Coastguard Worker 			free(kvbuf);
341*33b1fccfSAndroid Build Coastguard Worker 		return item;
342*33b1fccfSAndroid Build Coastguard Worker 	}
343*33b1fccfSAndroid Build Coastguard Worker #endif
344*33b1fccfSAndroid Build Coastguard Worker 	return NULL;
345*33b1fccfSAndroid Build Coastguard Worker }
346*33b1fccfSAndroid Build Coastguard Worker 
inode_xattr_add(struct list_head * hlist,struct xattr_item * item)347*33b1fccfSAndroid Build Coastguard Worker static int inode_xattr_add(struct list_head *hlist, struct xattr_item *item)
348*33b1fccfSAndroid Build Coastguard Worker {
349*33b1fccfSAndroid Build Coastguard Worker 	struct inode_xattr_node *node = malloc(sizeof(*node));
350*33b1fccfSAndroid Build Coastguard Worker 
351*33b1fccfSAndroid Build Coastguard Worker 	if (!node)
352*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
353*33b1fccfSAndroid Build Coastguard Worker 	init_list_head(&node->list);
354*33b1fccfSAndroid Build Coastguard Worker 	node->item = item;
355*33b1fccfSAndroid Build Coastguard Worker 	list_add(&node->list, hlist);
356*33b1fccfSAndroid Build Coastguard Worker 	return 0;
357*33b1fccfSAndroid Build Coastguard Worker }
358*33b1fccfSAndroid Build Coastguard Worker 
shared_xattr_add(struct xattr_item * item)359*33b1fccfSAndroid Build Coastguard Worker static int shared_xattr_add(struct xattr_item *item)
360*33b1fccfSAndroid Build Coastguard Worker {
361*33b1fccfSAndroid Build Coastguard Worker 	item->next_shared_xattr = shared_xattrs_list;
362*33b1fccfSAndroid Build Coastguard Worker 	shared_xattrs_list = item;
363*33b1fccfSAndroid Build Coastguard Worker 	return ++shared_xattrs_count;
364*33b1fccfSAndroid Build Coastguard Worker }
365*33b1fccfSAndroid Build Coastguard Worker 
erofs_xattr_add(struct list_head * ixattrs,struct xattr_item * item)366*33b1fccfSAndroid Build Coastguard Worker static int erofs_xattr_add(struct list_head *ixattrs, struct xattr_item *item)
367*33b1fccfSAndroid Build Coastguard Worker {
368*33b1fccfSAndroid Build Coastguard Worker 	if (ixattrs)
369*33b1fccfSAndroid Build Coastguard Worker 		return inode_xattr_add(ixattrs, item);
370*33b1fccfSAndroid Build Coastguard Worker 
371*33b1fccfSAndroid Build Coastguard Worker 	if (item->count == cfg.c_inline_xattr_tolerance + 1) {
372*33b1fccfSAndroid Build Coastguard Worker 		int ret = shared_xattr_add(item);
373*33b1fccfSAndroid Build Coastguard Worker 
374*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
375*33b1fccfSAndroid Build Coastguard Worker 			return ret;
376*33b1fccfSAndroid Build Coastguard Worker 	}
377*33b1fccfSAndroid Build Coastguard Worker 	return 0;
378*33b1fccfSAndroid Build Coastguard Worker }
379*33b1fccfSAndroid Build Coastguard Worker 
erofs_is_skipped_xattr(const char * key)380*33b1fccfSAndroid Build Coastguard Worker static bool erofs_is_skipped_xattr(const char *key)
381*33b1fccfSAndroid Build Coastguard Worker {
382*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBSELINUX
383*33b1fccfSAndroid Build Coastguard Worker 	/* if sehnd is valid, selabels will be overridden */
384*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.sehnd && !strcmp(key, XATTR_SECURITY_PREFIX "selinux"))
385*33b1fccfSAndroid Build Coastguard Worker 		return true;
386*33b1fccfSAndroid Build Coastguard Worker #endif
387*33b1fccfSAndroid Build Coastguard Worker 	return false;
388*33b1fccfSAndroid Build Coastguard Worker }
389*33b1fccfSAndroid Build Coastguard Worker 
read_xattrs_from_file(const char * path,mode_t mode,struct list_head * ixattrs)390*33b1fccfSAndroid Build Coastguard Worker static int read_xattrs_from_file(const char *path, mode_t mode,
391*33b1fccfSAndroid Build Coastguard Worker 				 struct list_head *ixattrs)
392*33b1fccfSAndroid Build Coastguard Worker {
393*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LLISTXATTR
394*33b1fccfSAndroid Build Coastguard Worker 	ssize_t kllen = llistxattr(path, NULL, 0);
395*33b1fccfSAndroid Build Coastguard Worker #elif defined(__APPLE__)
396*33b1fccfSAndroid Build Coastguard Worker 	ssize_t kllen = listxattr(path, NULL, 0, XATTR_NOFOLLOW);
397*33b1fccfSAndroid Build Coastguard Worker #else
398*33b1fccfSAndroid Build Coastguard Worker 	ssize_t kllen = 0;
399*33b1fccfSAndroid Build Coastguard Worker #endif
400*33b1fccfSAndroid Build Coastguard Worker 	int ret;
401*33b1fccfSAndroid Build Coastguard Worker 	char *keylst, *key, *klend;
402*33b1fccfSAndroid Build Coastguard Worker 	unsigned int keylen;
403*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_item *item;
404*33b1fccfSAndroid Build Coastguard Worker 
405*33b1fccfSAndroid Build Coastguard Worker 	if (kllen < 0 && errno != ENODATA && errno != EOPNOTSUPP) {
406*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("llistxattr to get the size of names for %s failed",
407*33b1fccfSAndroid Build Coastguard Worker 			  path);
408*33b1fccfSAndroid Build Coastguard Worker 		return -errno;
409*33b1fccfSAndroid Build Coastguard Worker 	}
410*33b1fccfSAndroid Build Coastguard Worker 
411*33b1fccfSAndroid Build Coastguard Worker 	ret = 0;
412*33b1fccfSAndroid Build Coastguard Worker 	if (kllen <= 1)
413*33b1fccfSAndroid Build Coastguard Worker 		goto out;
414*33b1fccfSAndroid Build Coastguard Worker 
415*33b1fccfSAndroid Build Coastguard Worker 	keylst = malloc(kllen);
416*33b1fccfSAndroid Build Coastguard Worker 	if (!keylst)
417*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
418*33b1fccfSAndroid Build Coastguard Worker 
419*33b1fccfSAndroid Build Coastguard Worker 	/* copy the list of attribute keys to the buffer.*/
420*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LLISTXATTR
421*33b1fccfSAndroid Build Coastguard Worker 	kllen = llistxattr(path, keylst, kllen);
422*33b1fccfSAndroid Build Coastguard Worker #elif defined(__APPLE__)
423*33b1fccfSAndroid Build Coastguard Worker 	kllen = listxattr(path, keylst, kllen, XATTR_NOFOLLOW);
424*33b1fccfSAndroid Build Coastguard Worker 	if (kllen < 0) {
425*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("llistxattr to get names for %s failed", path);
426*33b1fccfSAndroid Build Coastguard Worker 		ret = -errno;
427*33b1fccfSAndroid Build Coastguard Worker 		goto err;
428*33b1fccfSAndroid Build Coastguard Worker 	}
429*33b1fccfSAndroid Build Coastguard Worker #else
430*33b1fccfSAndroid Build Coastguard Worker 	ret = -EOPNOTSUPP;
431*33b1fccfSAndroid Build Coastguard Worker 	goto err;
432*33b1fccfSAndroid Build Coastguard Worker #endif
433*33b1fccfSAndroid Build Coastguard Worker 	/*
434*33b1fccfSAndroid Build Coastguard Worker 	 * loop over the list of zero terminated strings with the
435*33b1fccfSAndroid Build Coastguard Worker 	 * attribute keys. Use the remaining buffer length to determine
436*33b1fccfSAndroid Build Coastguard Worker 	 * the end of the list.
437*33b1fccfSAndroid Build Coastguard Worker 	 */
438*33b1fccfSAndroid Build Coastguard Worker 	klend = keylst + kllen;
439*33b1fccfSAndroid Build Coastguard Worker 	ret = 0;
440*33b1fccfSAndroid Build Coastguard Worker 
441*33b1fccfSAndroid Build Coastguard Worker 	for (key = keylst; key != klend; key += keylen + 1) {
442*33b1fccfSAndroid Build Coastguard Worker 		keylen = strlen(key);
443*33b1fccfSAndroid Build Coastguard Worker 		if (erofs_is_skipped_xattr(key))
444*33b1fccfSAndroid Build Coastguard Worker 			continue;
445*33b1fccfSAndroid Build Coastguard Worker 
446*33b1fccfSAndroid Build Coastguard Worker 		item = parse_one_xattr(path, key, keylen);
447*33b1fccfSAndroid Build Coastguard Worker 		if (IS_ERR(item)) {
448*33b1fccfSAndroid Build Coastguard Worker 			ret = PTR_ERR(item);
449*33b1fccfSAndroid Build Coastguard Worker 			goto err;
450*33b1fccfSAndroid Build Coastguard Worker 		}
451*33b1fccfSAndroid Build Coastguard Worker 
452*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_xattr_add(ixattrs, item);
453*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
454*33b1fccfSAndroid Build Coastguard Worker 			goto err;
455*33b1fccfSAndroid Build Coastguard Worker 	}
456*33b1fccfSAndroid Build Coastguard Worker 	free(keylst);
457*33b1fccfSAndroid Build Coastguard Worker 
458*33b1fccfSAndroid Build Coastguard Worker out:
459*33b1fccfSAndroid Build Coastguard Worker 	/* if some selabel is avilable, need to add right now */
460*33b1fccfSAndroid Build Coastguard Worker 	item = erofs_get_selabel_xattr(path, mode);
461*33b1fccfSAndroid Build Coastguard Worker 	if (IS_ERR(item))
462*33b1fccfSAndroid Build Coastguard Worker 		return PTR_ERR(item);
463*33b1fccfSAndroid Build Coastguard Worker 	if (item)
464*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_xattr_add(ixattrs, item);
465*33b1fccfSAndroid Build Coastguard Worker 	return ret;
466*33b1fccfSAndroid Build Coastguard Worker 
467*33b1fccfSAndroid Build Coastguard Worker err:
468*33b1fccfSAndroid Build Coastguard Worker 	free(keylst);
469*33b1fccfSAndroid Build Coastguard Worker 	return ret;
470*33b1fccfSAndroid Build Coastguard Worker }
471*33b1fccfSAndroid Build Coastguard Worker 
erofs_setxattr(struct erofs_inode * inode,char * key,const void * value,size_t size)472*33b1fccfSAndroid Build Coastguard Worker int erofs_setxattr(struct erofs_inode *inode, char *key,
473*33b1fccfSAndroid Build Coastguard Worker 		   const void *value, size_t size)
474*33b1fccfSAndroid Build Coastguard Worker {
475*33b1fccfSAndroid Build Coastguard Worker 	char *kvbuf;
476*33b1fccfSAndroid Build Coastguard Worker 	unsigned int len[2];
477*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_item *item;
478*33b1fccfSAndroid Build Coastguard Worker 
479*33b1fccfSAndroid Build Coastguard Worker 	len[0] = strlen(key);
480*33b1fccfSAndroid Build Coastguard Worker 	len[1] = size;
481*33b1fccfSAndroid Build Coastguard Worker 
482*33b1fccfSAndroid Build Coastguard Worker 	kvbuf = malloc(EROFS_XATTR_KVSIZE(len));
483*33b1fccfSAndroid Build Coastguard Worker 	if (!kvbuf)
484*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
485*33b1fccfSAndroid Build Coastguard Worker 
486*33b1fccfSAndroid Build Coastguard Worker 	memcpy(kvbuf, key, EROFS_XATTR_KSIZE(len));
487*33b1fccfSAndroid Build Coastguard Worker 	memcpy(kvbuf + EROFS_XATTR_KSIZE(len), value, size);
488*33b1fccfSAndroid Build Coastguard Worker 
489*33b1fccfSAndroid Build Coastguard Worker 	item = get_xattritem(kvbuf, len);
490*33b1fccfSAndroid Build Coastguard Worker 	if (IS_ERR(item)) {
491*33b1fccfSAndroid Build Coastguard Worker 		free(kvbuf);
492*33b1fccfSAndroid Build Coastguard Worker 		return PTR_ERR(item);
493*33b1fccfSAndroid Build Coastguard Worker 	}
494*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(!item);
495*33b1fccfSAndroid Build Coastguard Worker 
496*33b1fccfSAndroid Build Coastguard Worker 	return erofs_xattr_add(&inode->i_xattrs, item);
497*33b1fccfSAndroid Build Coastguard Worker }
498*33b1fccfSAndroid Build Coastguard Worker 
erofs_removexattr(struct erofs_inode * inode,const char * key)499*33b1fccfSAndroid Build Coastguard Worker static void erofs_removexattr(struct erofs_inode *inode, const char *key)
500*33b1fccfSAndroid Build Coastguard Worker {
501*33b1fccfSAndroid Build Coastguard Worker 	struct inode_xattr_node *node, *n;
502*33b1fccfSAndroid Build Coastguard Worker 
503*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry_safe(node, n, &inode->i_xattrs, list) {
504*33b1fccfSAndroid Build Coastguard Worker 		if (!strcmp(node->item->kvbuf, key)) {
505*33b1fccfSAndroid Build Coastguard Worker 			list_del(&node->list);
506*33b1fccfSAndroid Build Coastguard Worker 			put_xattritem(node->item);
507*33b1fccfSAndroid Build Coastguard Worker 			free(node);
508*33b1fccfSAndroid Build Coastguard Worker 		}
509*33b1fccfSAndroid Build Coastguard Worker 	}
510*33b1fccfSAndroid Build Coastguard Worker }
511*33b1fccfSAndroid Build Coastguard Worker 
erofs_set_opaque_xattr(struct erofs_inode * inode)512*33b1fccfSAndroid Build Coastguard Worker int erofs_set_opaque_xattr(struct erofs_inode *inode)
513*33b1fccfSAndroid Build Coastguard Worker {
514*33b1fccfSAndroid Build Coastguard Worker 	return erofs_setxattr(inode, OVL_XATTR_OPAQUE, "y", 1);
515*33b1fccfSAndroid Build Coastguard Worker }
516*33b1fccfSAndroid Build Coastguard Worker 
erofs_clear_opaque_xattr(struct erofs_inode * inode)517*33b1fccfSAndroid Build Coastguard Worker void erofs_clear_opaque_xattr(struct erofs_inode *inode)
518*33b1fccfSAndroid Build Coastguard Worker {
519*33b1fccfSAndroid Build Coastguard Worker 	erofs_removexattr(inode, OVL_XATTR_OPAQUE);
520*33b1fccfSAndroid Build Coastguard Worker }
521*33b1fccfSAndroid Build Coastguard Worker 
erofs_set_origin_xattr(struct erofs_inode * inode)522*33b1fccfSAndroid Build Coastguard Worker int erofs_set_origin_xattr(struct erofs_inode *inode)
523*33b1fccfSAndroid Build Coastguard Worker {
524*33b1fccfSAndroid Build Coastguard Worker 	return erofs_setxattr(inode, OVL_XATTR_ORIGIN, NULL, 0);
525*33b1fccfSAndroid Build Coastguard Worker }
526*33b1fccfSAndroid Build Coastguard Worker 
527*33b1fccfSAndroid Build Coastguard Worker #ifdef WITH_ANDROID
erofs_droid_xattr_set_caps(struct erofs_inode * inode)528*33b1fccfSAndroid Build Coastguard Worker static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
529*33b1fccfSAndroid Build Coastguard Worker {
530*33b1fccfSAndroid Build Coastguard Worker 	const u64 capabilities = inode->capabilities;
531*33b1fccfSAndroid Build Coastguard Worker 	char *kvbuf;
532*33b1fccfSAndroid Build Coastguard Worker 	unsigned int len[2];
533*33b1fccfSAndroid Build Coastguard Worker 	struct vfs_cap_data caps;
534*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_item *item;
535*33b1fccfSAndroid Build Coastguard Worker 
536*33b1fccfSAndroid Build Coastguard Worker 	if (!capabilities)
537*33b1fccfSAndroid Build Coastguard Worker 		return 0;
538*33b1fccfSAndroid Build Coastguard Worker 
539*33b1fccfSAndroid Build Coastguard Worker 	len[0] = sizeof(XATTR_NAME_SECURITY_CAPABILITY) - 1;
540*33b1fccfSAndroid Build Coastguard Worker 	len[1] = sizeof(caps);
541*33b1fccfSAndroid Build Coastguard Worker 
542*33b1fccfSAndroid Build Coastguard Worker 	kvbuf = malloc(EROFS_XATTR_KVSIZE(len));
543*33b1fccfSAndroid Build Coastguard Worker 	if (!kvbuf)
544*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
545*33b1fccfSAndroid Build Coastguard Worker 
546*33b1fccfSAndroid Build Coastguard Worker 	sprintf(kvbuf, "%s", XATTR_NAME_SECURITY_CAPABILITY);
547*33b1fccfSAndroid Build Coastguard Worker 	caps.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;
548*33b1fccfSAndroid Build Coastguard Worker 	caps.data[0].permitted = (u32) capabilities;
549*33b1fccfSAndroid Build Coastguard Worker 	caps.data[0].inheritable = 0;
550*33b1fccfSAndroid Build Coastguard Worker 	caps.data[1].permitted = (u32) (capabilities >> 32);
551*33b1fccfSAndroid Build Coastguard Worker 	caps.data[1].inheritable = 0;
552*33b1fccfSAndroid Build Coastguard Worker 	memcpy(kvbuf + EROFS_XATTR_KSIZE(len), &caps, len[1]);
553*33b1fccfSAndroid Build Coastguard Worker 
554*33b1fccfSAndroid Build Coastguard Worker 	item = get_xattritem(kvbuf, len);
555*33b1fccfSAndroid Build Coastguard Worker 	if (IS_ERR(item)) {
556*33b1fccfSAndroid Build Coastguard Worker 		free(kvbuf);
557*33b1fccfSAndroid Build Coastguard Worker 		return PTR_ERR(item);
558*33b1fccfSAndroid Build Coastguard Worker 	}
559*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(!item);
560*33b1fccfSAndroid Build Coastguard Worker 
561*33b1fccfSAndroid Build Coastguard Worker 	return erofs_xattr_add(&inode->i_xattrs, item);
562*33b1fccfSAndroid Build Coastguard Worker }
563*33b1fccfSAndroid Build Coastguard Worker #else
erofs_droid_xattr_set_caps(struct erofs_inode * inode)564*33b1fccfSAndroid Build Coastguard Worker static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
565*33b1fccfSAndroid Build Coastguard Worker {
566*33b1fccfSAndroid Build Coastguard Worker 	return 0;
567*33b1fccfSAndroid Build Coastguard Worker }
568*33b1fccfSAndroid Build Coastguard Worker #endif
569*33b1fccfSAndroid Build Coastguard Worker 
erofs_scan_file_xattrs(struct erofs_inode * inode)570*33b1fccfSAndroid Build Coastguard Worker int erofs_scan_file_xattrs(struct erofs_inode *inode)
571*33b1fccfSAndroid Build Coastguard Worker {
572*33b1fccfSAndroid Build Coastguard Worker 	int ret;
573*33b1fccfSAndroid Build Coastguard Worker 	struct list_head *ixattrs = &inode->i_xattrs;
574*33b1fccfSAndroid Build Coastguard Worker 
575*33b1fccfSAndroid Build Coastguard Worker 	/* check if xattr is disabled */
576*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_inline_xattr_tolerance < 0)
577*33b1fccfSAndroid Build Coastguard Worker 		return 0;
578*33b1fccfSAndroid Build Coastguard Worker 
579*33b1fccfSAndroid Build Coastguard Worker 	ret = read_xattrs_from_file(inode->i_srcpath, inode->i_mode, ixattrs);
580*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
581*33b1fccfSAndroid Build Coastguard Worker 		return ret;
582*33b1fccfSAndroid Build Coastguard Worker 
583*33b1fccfSAndroid Build Coastguard Worker 	return erofs_droid_xattr_set_caps(inode);
584*33b1fccfSAndroid Build Coastguard Worker }
585*33b1fccfSAndroid Build Coastguard Worker 
erofs_read_xattrs_from_disk(struct erofs_inode * inode)586*33b1fccfSAndroid Build Coastguard Worker int erofs_read_xattrs_from_disk(struct erofs_inode *inode)
587*33b1fccfSAndroid Build Coastguard Worker {
588*33b1fccfSAndroid Build Coastguard Worker 	ssize_t kllen;
589*33b1fccfSAndroid Build Coastguard Worker 	char *keylst, *key;
590*33b1fccfSAndroid Build Coastguard Worker 	int ret;
591*33b1fccfSAndroid Build Coastguard Worker 
592*33b1fccfSAndroid Build Coastguard Worker 	init_list_head(&inode->i_xattrs);
593*33b1fccfSAndroid Build Coastguard Worker 	kllen = erofs_listxattr(inode, NULL, 0);
594*33b1fccfSAndroid Build Coastguard Worker 	if (kllen < 0)
595*33b1fccfSAndroid Build Coastguard Worker 		return kllen;
596*33b1fccfSAndroid Build Coastguard Worker 	if (kllen <= 1)
597*33b1fccfSAndroid Build Coastguard Worker 		return 0;
598*33b1fccfSAndroid Build Coastguard Worker 
599*33b1fccfSAndroid Build Coastguard Worker 	keylst = malloc(kllen);
600*33b1fccfSAndroid Build Coastguard Worker 	if (!keylst)
601*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
602*33b1fccfSAndroid Build Coastguard Worker 
603*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_listxattr(inode, keylst, kllen);
604*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
605*33b1fccfSAndroid Build Coastguard Worker 		goto out;
606*33b1fccfSAndroid Build Coastguard Worker 
607*33b1fccfSAndroid Build Coastguard Worker 	for (key = keylst; key < keylst + kllen; key += strlen(key) + 1) {
608*33b1fccfSAndroid Build Coastguard Worker 		void *value = NULL;
609*33b1fccfSAndroid Build Coastguard Worker 		size_t size = 0;
610*33b1fccfSAndroid Build Coastguard Worker 
611*33b1fccfSAndroid Build Coastguard Worker 		if (!strcmp(key, OVL_XATTR_OPAQUE)) {
612*33b1fccfSAndroid Build Coastguard Worker 			if (!S_ISDIR(inode->i_mode)) {
613*33b1fccfSAndroid Build Coastguard Worker 				erofs_dbg("file %s: opaque xattr on non-dir",
614*33b1fccfSAndroid Build Coastguard Worker 					  inode->i_srcpath);
615*33b1fccfSAndroid Build Coastguard Worker 				ret = -EINVAL;
616*33b1fccfSAndroid Build Coastguard Worker 				goto out;
617*33b1fccfSAndroid Build Coastguard Worker 			}
618*33b1fccfSAndroid Build Coastguard Worker 			inode->opaque = true;
619*33b1fccfSAndroid Build Coastguard Worker 		}
620*33b1fccfSAndroid Build Coastguard Worker 
621*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_getxattr(inode, key, NULL, 0);
622*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
623*33b1fccfSAndroid Build Coastguard Worker 			goto out;
624*33b1fccfSAndroid Build Coastguard Worker 		if (ret) {
625*33b1fccfSAndroid Build Coastguard Worker 			size = ret;
626*33b1fccfSAndroid Build Coastguard Worker 			value = malloc(size);
627*33b1fccfSAndroid Build Coastguard Worker 			if (!value) {
628*33b1fccfSAndroid Build Coastguard Worker 				ret = -ENOMEM;
629*33b1fccfSAndroid Build Coastguard Worker 				goto out;
630*33b1fccfSAndroid Build Coastguard Worker 			}
631*33b1fccfSAndroid Build Coastguard Worker 
632*33b1fccfSAndroid Build Coastguard Worker 			ret = erofs_getxattr(inode, key, value, size);
633*33b1fccfSAndroid Build Coastguard Worker 			if (ret < 0) {
634*33b1fccfSAndroid Build Coastguard Worker 				free(value);
635*33b1fccfSAndroid Build Coastguard Worker 				goto out;
636*33b1fccfSAndroid Build Coastguard Worker 			}
637*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(ret != size);
638*33b1fccfSAndroid Build Coastguard Worker 		} else if (S_ISDIR(inode->i_mode) &&
639*33b1fccfSAndroid Build Coastguard Worker 			   !strcmp(key, OVL_XATTR_ORIGIN)) {
640*33b1fccfSAndroid Build Coastguard Worker 			ret = 0;
641*33b1fccfSAndroid Build Coastguard Worker 			inode->whiteouts = true;
642*33b1fccfSAndroid Build Coastguard Worker 			continue;
643*33b1fccfSAndroid Build Coastguard Worker 		}
644*33b1fccfSAndroid Build Coastguard Worker 
645*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_setxattr(inode, key, value, size);
646*33b1fccfSAndroid Build Coastguard Worker 		free(value);
647*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
648*33b1fccfSAndroid Build Coastguard Worker 			break;
649*33b1fccfSAndroid Build Coastguard Worker 	}
650*33b1fccfSAndroid Build Coastguard Worker out:
651*33b1fccfSAndroid Build Coastguard Worker 	free(keylst);
652*33b1fccfSAndroid Build Coastguard Worker 	return ret;
653*33b1fccfSAndroid Build Coastguard Worker }
654*33b1fccfSAndroid Build Coastguard Worker 
erofs_next_xattr_align(unsigned int pos,struct xattr_item * item)655*33b1fccfSAndroid Build Coastguard Worker static inline unsigned int erofs_next_xattr_align(unsigned int pos,
656*33b1fccfSAndroid Build Coastguard Worker 						  struct xattr_item *item)
657*33b1fccfSAndroid Build Coastguard Worker {
658*33b1fccfSAndroid Build Coastguard Worker 	return EROFS_XATTR_ALIGN(pos + sizeof(struct erofs_xattr_entry) +
659*33b1fccfSAndroid Build Coastguard Worker 			item->len[0] + item->len[1] - item->prefix_len);
660*33b1fccfSAndroid Build Coastguard Worker }
661*33b1fccfSAndroid Build Coastguard Worker 
erofs_prepare_xattr_ibody(struct erofs_inode * inode,bool noroom)662*33b1fccfSAndroid Build Coastguard Worker int erofs_prepare_xattr_ibody(struct erofs_inode *inode, bool noroom)
663*33b1fccfSAndroid Build Coastguard Worker {
664*33b1fccfSAndroid Build Coastguard Worker 	unsigned int target_xattr_isize = inode->xattr_isize;
665*33b1fccfSAndroid Build Coastguard Worker 	struct list_head *ixattrs = &inode->i_xattrs;
666*33b1fccfSAndroid Build Coastguard Worker 	struct inode_xattr_node *node;
667*33b1fccfSAndroid Build Coastguard Worker 	unsigned int h_shared_count;
668*33b1fccfSAndroid Build Coastguard Worker 	int ret;
669*33b1fccfSAndroid Build Coastguard Worker 
670*33b1fccfSAndroid Build Coastguard Worker 	if (list_empty(ixattrs)) {
671*33b1fccfSAndroid Build Coastguard Worker 		ret = 0;
672*33b1fccfSAndroid Build Coastguard Worker 		goto out;
673*33b1fccfSAndroid Build Coastguard Worker 	}
674*33b1fccfSAndroid Build Coastguard Worker 
675*33b1fccfSAndroid Build Coastguard Worker 	/* get xattr ibody size */
676*33b1fccfSAndroid Build Coastguard Worker 	h_shared_count = 0;
677*33b1fccfSAndroid Build Coastguard Worker 	ret = sizeof(struct erofs_xattr_ibody_header);
678*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry(node, ixattrs, list) {
679*33b1fccfSAndroid Build Coastguard Worker 		struct xattr_item *item = node->item;
680*33b1fccfSAndroid Build Coastguard Worker 
681*33b1fccfSAndroid Build Coastguard Worker 		if (item->shared_xattr_id >= 0 && h_shared_count < UCHAR_MAX) {
682*33b1fccfSAndroid Build Coastguard Worker 			++h_shared_count;
683*33b1fccfSAndroid Build Coastguard Worker 			ret += sizeof(__le32);
684*33b1fccfSAndroid Build Coastguard Worker 			continue;
685*33b1fccfSAndroid Build Coastguard Worker 		}
686*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_next_xattr_align(ret, item);
687*33b1fccfSAndroid Build Coastguard Worker 	}
688*33b1fccfSAndroid Build Coastguard Worker out:
689*33b1fccfSAndroid Build Coastguard Worker 	while (ret < target_xattr_isize) {
690*33b1fccfSAndroid Build Coastguard Worker 		ret += sizeof(struct erofs_xattr_entry);
691*33b1fccfSAndroid Build Coastguard Worker 		if (ret < target_xattr_isize)
692*33b1fccfSAndroid Build Coastguard Worker 			ret = EROFS_XATTR_ALIGN(ret +
693*33b1fccfSAndroid Build Coastguard Worker 				min_t(int, target_xattr_isize - ret, UINT16_MAX));
694*33b1fccfSAndroid Build Coastguard Worker 	}
695*33b1fccfSAndroid Build Coastguard Worker 	if (noroom && target_xattr_isize && ret > target_xattr_isize) {
696*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("no enough space to keep xattrs @ nid %llu",
697*33b1fccfSAndroid Build Coastguard Worker 			  inode->nid | 0ULL);
698*33b1fccfSAndroid Build Coastguard Worker 		return -ENOSPC;
699*33b1fccfSAndroid Build Coastguard Worker 	}
700*33b1fccfSAndroid Build Coastguard Worker 	inode->xattr_isize = ret;
701*33b1fccfSAndroid Build Coastguard Worker 	return ret;
702*33b1fccfSAndroid Build Coastguard Worker }
703*33b1fccfSAndroid Build Coastguard Worker 
erofs_count_all_xattrs_from_path(const char * path)704*33b1fccfSAndroid Build Coastguard Worker static int erofs_count_all_xattrs_from_path(const char *path)
705*33b1fccfSAndroid Build Coastguard Worker {
706*33b1fccfSAndroid Build Coastguard Worker 	int ret;
707*33b1fccfSAndroid Build Coastguard Worker 	DIR *_dir;
708*33b1fccfSAndroid Build Coastguard Worker 	struct stat st;
709*33b1fccfSAndroid Build Coastguard Worker 
710*33b1fccfSAndroid Build Coastguard Worker 	_dir = opendir(path);
711*33b1fccfSAndroid Build Coastguard Worker 	if (!_dir) {
712*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("failed to opendir at %s: %s",
713*33b1fccfSAndroid Build Coastguard Worker 			  path, erofs_strerror(-errno));
714*33b1fccfSAndroid Build Coastguard Worker 		return -errno;
715*33b1fccfSAndroid Build Coastguard Worker 	}
716*33b1fccfSAndroid Build Coastguard Worker 
717*33b1fccfSAndroid Build Coastguard Worker 	ret = 0;
718*33b1fccfSAndroid Build Coastguard Worker 	while (1) {
719*33b1fccfSAndroid Build Coastguard Worker 		struct dirent *dp;
720*33b1fccfSAndroid Build Coastguard Worker 		char buf[PATH_MAX];
721*33b1fccfSAndroid Build Coastguard Worker 
722*33b1fccfSAndroid Build Coastguard Worker 		/*
723*33b1fccfSAndroid Build Coastguard Worker 		 * set errno to 0 before calling readdir() in order to
724*33b1fccfSAndroid Build Coastguard Worker 		 * distinguish end of stream and from an error.
725*33b1fccfSAndroid Build Coastguard Worker 		 */
726*33b1fccfSAndroid Build Coastguard Worker 		errno = 0;
727*33b1fccfSAndroid Build Coastguard Worker 		dp = readdir(_dir);
728*33b1fccfSAndroid Build Coastguard Worker 		if (!dp)
729*33b1fccfSAndroid Build Coastguard Worker 			break;
730*33b1fccfSAndroid Build Coastguard Worker 
731*33b1fccfSAndroid Build Coastguard Worker 		if (is_dot_dotdot(dp->d_name) ||
732*33b1fccfSAndroid Build Coastguard Worker 		    !strncmp(dp->d_name, "lost+found", strlen("lost+found")))
733*33b1fccfSAndroid Build Coastguard Worker 			continue;
734*33b1fccfSAndroid Build Coastguard Worker 
735*33b1fccfSAndroid Build Coastguard Worker 		ret = snprintf(buf, PATH_MAX, "%s/%s", path, dp->d_name);
736*33b1fccfSAndroid Build Coastguard Worker 
737*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0 || ret >= PATH_MAX) {
738*33b1fccfSAndroid Build Coastguard Worker 			/* ignore the too long path */
739*33b1fccfSAndroid Build Coastguard Worker 			ret = -ENOMEM;
740*33b1fccfSAndroid Build Coastguard Worker 			goto fail;
741*33b1fccfSAndroid Build Coastguard Worker 		}
742*33b1fccfSAndroid Build Coastguard Worker 
743*33b1fccfSAndroid Build Coastguard Worker 		ret = lstat(buf, &st);
744*33b1fccfSAndroid Build Coastguard Worker 		if (ret) {
745*33b1fccfSAndroid Build Coastguard Worker 			ret = -errno;
746*33b1fccfSAndroid Build Coastguard Worker 			goto fail;
747*33b1fccfSAndroid Build Coastguard Worker 		}
748*33b1fccfSAndroid Build Coastguard Worker 
749*33b1fccfSAndroid Build Coastguard Worker 		ret = read_xattrs_from_file(buf, st.st_mode, NULL);
750*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
751*33b1fccfSAndroid Build Coastguard Worker 			goto fail;
752*33b1fccfSAndroid Build Coastguard Worker 
753*33b1fccfSAndroid Build Coastguard Worker 		if (!S_ISDIR(st.st_mode))
754*33b1fccfSAndroid Build Coastguard Worker 			continue;
755*33b1fccfSAndroid Build Coastguard Worker 
756*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_count_all_xattrs_from_path(buf);
757*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
758*33b1fccfSAndroid Build Coastguard Worker 			goto fail;
759*33b1fccfSAndroid Build Coastguard Worker 	}
760*33b1fccfSAndroid Build Coastguard Worker 
761*33b1fccfSAndroid Build Coastguard Worker 	if (errno)
762*33b1fccfSAndroid Build Coastguard Worker 		ret = -errno;
763*33b1fccfSAndroid Build Coastguard Worker 
764*33b1fccfSAndroid Build Coastguard Worker fail:
765*33b1fccfSAndroid Build Coastguard Worker 	closedir(_dir);
766*33b1fccfSAndroid Build Coastguard Worker 	return ret;
767*33b1fccfSAndroid Build Coastguard Worker }
768*33b1fccfSAndroid Build Coastguard Worker 
erofs_cleanxattrs(bool sharedxattrs)769*33b1fccfSAndroid Build Coastguard Worker static void erofs_cleanxattrs(bool sharedxattrs)
770*33b1fccfSAndroid Build Coastguard Worker {
771*33b1fccfSAndroid Build Coastguard Worker 	unsigned int i;
772*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_item *item;
773*33b1fccfSAndroid Build Coastguard Worker 	struct hlist_node *tmp;
774*33b1fccfSAndroid Build Coastguard Worker 
775*33b1fccfSAndroid Build Coastguard Worker 	hash_for_each_safe(ea_hashtable, i, tmp, item, node) {
776*33b1fccfSAndroid Build Coastguard Worker 		if (sharedxattrs && item->shared_xattr_id >= 0)
777*33b1fccfSAndroid Build Coastguard Worker 			continue;
778*33b1fccfSAndroid Build Coastguard Worker 
779*33b1fccfSAndroid Build Coastguard Worker 		hash_del(&item->node);
780*33b1fccfSAndroid Build Coastguard Worker 		free(item);
781*33b1fccfSAndroid Build Coastguard Worker 	}
782*33b1fccfSAndroid Build Coastguard Worker 
783*33b1fccfSAndroid Build Coastguard Worker 	if (sharedxattrs)
784*33b1fccfSAndroid Build Coastguard Worker 		return;
785*33b1fccfSAndroid Build Coastguard Worker 
786*33b1fccfSAndroid Build Coastguard Worker 	shared_xattrs_count = 0;
787*33b1fccfSAndroid Build Coastguard Worker }
788*33b1fccfSAndroid Build Coastguard Worker 
comp_shared_xattr_item(const void * a,const void * b)789*33b1fccfSAndroid Build Coastguard Worker static int comp_shared_xattr_item(const void *a, const void *b)
790*33b1fccfSAndroid Build Coastguard Worker {
791*33b1fccfSAndroid Build Coastguard Worker 	const struct xattr_item *ia, *ib;
792*33b1fccfSAndroid Build Coastguard Worker 	unsigned int la, lb;
793*33b1fccfSAndroid Build Coastguard Worker 	int ret;
794*33b1fccfSAndroid Build Coastguard Worker 
795*33b1fccfSAndroid Build Coastguard Worker 	ia = *((const struct xattr_item **)a);
796*33b1fccfSAndroid Build Coastguard Worker 	ib = *((const struct xattr_item **)b);
797*33b1fccfSAndroid Build Coastguard Worker 	la = ia->len[0] + ia->len[1];
798*33b1fccfSAndroid Build Coastguard Worker 	lb = ib->len[0] + ib->len[1];
799*33b1fccfSAndroid Build Coastguard Worker 
800*33b1fccfSAndroid Build Coastguard Worker 	ret = strncmp(ia->kvbuf, ib->kvbuf, min(la, lb));
801*33b1fccfSAndroid Build Coastguard Worker 	if (ret != 0)
802*33b1fccfSAndroid Build Coastguard Worker 		return ret;
803*33b1fccfSAndroid Build Coastguard Worker 
804*33b1fccfSAndroid Build Coastguard Worker 	return la > lb;
805*33b1fccfSAndroid Build Coastguard Worker }
806*33b1fccfSAndroid Build Coastguard Worker 
erofs_xattr_write_name_prefixes(struct erofs_sb_info * sbi,FILE * f)807*33b1fccfSAndroid Build Coastguard Worker int erofs_xattr_write_name_prefixes(struct erofs_sb_info *sbi, FILE *f)
808*33b1fccfSAndroid Build Coastguard Worker {
809*33b1fccfSAndroid Build Coastguard Worker 	struct ea_type_node *tnode;
810*33b1fccfSAndroid Build Coastguard Worker 	off_t offset;
811*33b1fccfSAndroid Build Coastguard Worker 
812*33b1fccfSAndroid Build Coastguard Worker 	if (!ea_prefix_count)
813*33b1fccfSAndroid Build Coastguard Worker 		return 0;
814*33b1fccfSAndroid Build Coastguard Worker 	offset = ftello(f);
815*33b1fccfSAndroid Build Coastguard Worker 	if (offset < 0)
816*33b1fccfSAndroid Build Coastguard Worker 		return -errno;
817*33b1fccfSAndroid Build Coastguard Worker 	if (offset > UINT32_MAX)
818*33b1fccfSAndroid Build Coastguard Worker 		return -EOVERFLOW;
819*33b1fccfSAndroid Build Coastguard Worker 
820*33b1fccfSAndroid Build Coastguard Worker 	offset = round_up(offset, 4);
821*33b1fccfSAndroid Build Coastguard Worker 	if (fseek(f, offset, SEEK_SET))
822*33b1fccfSAndroid Build Coastguard Worker 		return -errno;
823*33b1fccfSAndroid Build Coastguard Worker 	sbi->xattr_prefix_start = (u32)offset >> 2;
824*33b1fccfSAndroid Build Coastguard Worker 	sbi->xattr_prefix_count = ea_prefix_count;
825*33b1fccfSAndroid Build Coastguard Worker 
826*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry(tnode, &ea_name_prefixes, list) {
827*33b1fccfSAndroid Build Coastguard Worker 		union {
828*33b1fccfSAndroid Build Coastguard Worker 			struct {
829*33b1fccfSAndroid Build Coastguard Worker 				__le16 size;
830*33b1fccfSAndroid Build Coastguard Worker 				struct erofs_xattr_long_prefix prefix;
831*33b1fccfSAndroid Build Coastguard Worker 			} s;
832*33b1fccfSAndroid Build Coastguard Worker 			u8 data[EROFS_NAME_LEN + 2 +
833*33b1fccfSAndroid Build Coastguard Worker 				sizeof(struct erofs_xattr_long_prefix)];
834*33b1fccfSAndroid Build Coastguard Worker 		} u;
835*33b1fccfSAndroid Build Coastguard Worker 		int len, infix_len;
836*33b1fccfSAndroid Build Coastguard Worker 
837*33b1fccfSAndroid Build Coastguard Worker 		u.s.prefix.base_index = tnode->base_index;
838*33b1fccfSAndroid Build Coastguard Worker 		infix_len = tnode->type.prefix_len - tnode->base_len;
839*33b1fccfSAndroid Build Coastguard Worker 		memcpy(u.s.prefix.infix, tnode->type.prefix + tnode->base_len,
840*33b1fccfSAndroid Build Coastguard Worker 		       infix_len);
841*33b1fccfSAndroid Build Coastguard Worker 		len = sizeof(struct erofs_xattr_long_prefix) + infix_len;
842*33b1fccfSAndroid Build Coastguard Worker 		u.s.size = cpu_to_le16(len);
843*33b1fccfSAndroid Build Coastguard Worker 		if (fwrite(&u.s, sizeof(__le16) + len, 1, f) != 1)
844*33b1fccfSAndroid Build Coastguard Worker 			return -EIO;
845*33b1fccfSAndroid Build Coastguard Worker 		offset = round_up(offset + sizeof(__le16) + len, 4);
846*33b1fccfSAndroid Build Coastguard Worker 		if (fseek(f, offset, SEEK_SET))
847*33b1fccfSAndroid Build Coastguard Worker 			return -errno;
848*33b1fccfSAndroid Build Coastguard Worker 	}
849*33b1fccfSAndroid Build Coastguard Worker 	erofs_sb_set_fragments(sbi);
850*33b1fccfSAndroid Build Coastguard Worker 	erofs_sb_set_xattr_prefixes(sbi);
851*33b1fccfSAndroid Build Coastguard Worker 	return 0;
852*33b1fccfSAndroid Build Coastguard Worker }
853*33b1fccfSAndroid Build Coastguard Worker 
erofs_write_xattr_entry(char * buf,struct xattr_item * item)854*33b1fccfSAndroid Build Coastguard Worker static void erofs_write_xattr_entry(char *buf, struct xattr_item *item)
855*33b1fccfSAndroid Build Coastguard Worker {
856*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_xattr_entry entry = {
857*33b1fccfSAndroid Build Coastguard Worker 		.e_name_index = item->prefix,
858*33b1fccfSAndroid Build Coastguard Worker 		.e_name_len = item->len[0] - item->prefix_len,
859*33b1fccfSAndroid Build Coastguard Worker 		.e_value_size = cpu_to_le16(item->len[1]),
860*33b1fccfSAndroid Build Coastguard Worker 	};
861*33b1fccfSAndroid Build Coastguard Worker 
862*33b1fccfSAndroid Build Coastguard Worker 	memcpy(buf, &entry, sizeof(entry));
863*33b1fccfSAndroid Build Coastguard Worker 	buf += sizeof(struct erofs_xattr_entry);
864*33b1fccfSAndroid Build Coastguard Worker 	memcpy(buf, item->kvbuf + item->prefix_len,
865*33b1fccfSAndroid Build Coastguard Worker 	       item->len[0] - item->prefix_len);
866*33b1fccfSAndroid Build Coastguard Worker 	buf += item->len[0] - item->prefix_len;
867*33b1fccfSAndroid Build Coastguard Worker 	memcpy(buf, item->kvbuf + item->len[0] + 1, item->len[1]);
868*33b1fccfSAndroid Build Coastguard Worker 
869*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("writing xattr %d %s (%d %s)", item->base_index, item->kvbuf,
870*33b1fccfSAndroid Build Coastguard Worker 			item->prefix, item->kvbuf + item->prefix_len);
871*33b1fccfSAndroid Build Coastguard Worker }
872*33b1fccfSAndroid Build Coastguard Worker 
erofs_build_shared_xattrs_from_path(struct erofs_sb_info * sbi,const char * path)873*33b1fccfSAndroid Build Coastguard Worker int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *path)
874*33b1fccfSAndroid Build Coastguard Worker {
875*33b1fccfSAndroid Build Coastguard Worker 	int ret;
876*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_head *bh;
877*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_item *item, *n, **sorted_n;
878*33b1fccfSAndroid Build Coastguard Worker 	char *buf;
879*33b1fccfSAndroid Build Coastguard Worker 	unsigned int p, i;
880*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t off;
881*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t shared_xattrs_size = 0;
882*33b1fccfSAndroid Build Coastguard Worker 
883*33b1fccfSAndroid Build Coastguard Worker 	/* check if xattr or shared xattr is disabled */
884*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_inline_xattr_tolerance < 0 ||
885*33b1fccfSAndroid Build Coastguard Worker 	    cfg.c_inline_xattr_tolerance == INT_MAX)
886*33b1fccfSAndroid Build Coastguard Worker 		return 0;
887*33b1fccfSAndroid Build Coastguard Worker 
888*33b1fccfSAndroid Build Coastguard Worker 	if (shared_xattrs_count) {
889*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(1);
890*33b1fccfSAndroid Build Coastguard Worker 		return -EINVAL;
891*33b1fccfSAndroid Build Coastguard Worker 	}
892*33b1fccfSAndroid Build Coastguard Worker 
893*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_count_all_xattrs_from_path(path);
894*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
895*33b1fccfSAndroid Build Coastguard Worker 		return ret;
896*33b1fccfSAndroid Build Coastguard Worker 
897*33b1fccfSAndroid Build Coastguard Worker 	if (!shared_xattrs_count)
898*33b1fccfSAndroid Build Coastguard Worker 		goto out;
899*33b1fccfSAndroid Build Coastguard Worker 
900*33b1fccfSAndroid Build Coastguard Worker 	sorted_n = malloc((shared_xattrs_count + 1) * sizeof(n));
901*33b1fccfSAndroid Build Coastguard Worker 	if (!sorted_n)
902*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
903*33b1fccfSAndroid Build Coastguard Worker 
904*33b1fccfSAndroid Build Coastguard Worker 	i = 0;
905*33b1fccfSAndroid Build Coastguard Worker 	while (shared_xattrs_list) {
906*33b1fccfSAndroid Build Coastguard Worker 		item = shared_xattrs_list;
907*33b1fccfSAndroid Build Coastguard Worker 		sorted_n[i++] = item;
908*33b1fccfSAndroid Build Coastguard Worker 		shared_xattrs_list = item->next_shared_xattr;
909*33b1fccfSAndroid Build Coastguard Worker 		shared_xattrs_size = erofs_next_xattr_align(shared_xattrs_size,
910*33b1fccfSAndroid Build Coastguard Worker 							    item);
911*33b1fccfSAndroid Build Coastguard Worker 	}
912*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(i != shared_xattrs_count);
913*33b1fccfSAndroid Build Coastguard Worker 	sorted_n[i] = NULL;
914*33b1fccfSAndroid Build Coastguard Worker 	qsort(sorted_n, shared_xattrs_count, sizeof(n), comp_shared_xattr_item);
915*33b1fccfSAndroid Build Coastguard Worker 
916*33b1fccfSAndroid Build Coastguard Worker 	buf = calloc(1, shared_xattrs_size);
917*33b1fccfSAndroid Build Coastguard Worker 	if (!buf) {
918*33b1fccfSAndroid Build Coastguard Worker 		free(sorted_n);
919*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
920*33b1fccfSAndroid Build Coastguard Worker 	}
921*33b1fccfSAndroid Build Coastguard Worker 
922*33b1fccfSAndroid Build Coastguard Worker 	bh = erofs_balloc(sbi->bmgr, XATTR, shared_xattrs_size, 0, 0);
923*33b1fccfSAndroid Build Coastguard Worker 	if (IS_ERR(bh)) {
924*33b1fccfSAndroid Build Coastguard Worker 		free(sorted_n);
925*33b1fccfSAndroid Build Coastguard Worker 		free(buf);
926*33b1fccfSAndroid Build Coastguard Worker 		return PTR_ERR(bh);
927*33b1fccfSAndroid Build Coastguard Worker 	}
928*33b1fccfSAndroid Build Coastguard Worker 	bh->op = &erofs_skip_write_bhops;
929*33b1fccfSAndroid Build Coastguard Worker 
930*33b1fccfSAndroid Build Coastguard Worker 	erofs_mapbh(NULL, bh->block);
931*33b1fccfSAndroid Build Coastguard Worker 	off = erofs_btell(bh, false);
932*33b1fccfSAndroid Build Coastguard Worker 
933*33b1fccfSAndroid Build Coastguard Worker 	sbi->xattr_blkaddr = off / erofs_blksiz(sbi);
934*33b1fccfSAndroid Build Coastguard Worker 	off %= erofs_blksiz(sbi);
935*33b1fccfSAndroid Build Coastguard Worker 	p = 0;
936*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < shared_xattrs_count; i++) {
937*33b1fccfSAndroid Build Coastguard Worker 		item = sorted_n[i];
938*33b1fccfSAndroid Build Coastguard Worker 		erofs_write_xattr_entry(buf + p, item);
939*33b1fccfSAndroid Build Coastguard Worker 		item->next_shared_xattr = sorted_n[i + 1];
940*33b1fccfSAndroid Build Coastguard Worker 		item->shared_xattr_id = (off + p) / sizeof(__le32);
941*33b1fccfSAndroid Build Coastguard Worker 		p = erofs_next_xattr_align(p, item);
942*33b1fccfSAndroid Build Coastguard Worker 	}
943*33b1fccfSAndroid Build Coastguard Worker 	shared_xattrs_list = sorted_n[0];
944*33b1fccfSAndroid Build Coastguard Worker 	free(sorted_n);
945*33b1fccfSAndroid Build Coastguard Worker 	bh->op = &erofs_drop_directly_bhops;
946*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_dev_write(sbi, buf, erofs_btell(bh, false), shared_xattrs_size);
947*33b1fccfSAndroid Build Coastguard Worker 	free(buf);
948*33b1fccfSAndroid Build Coastguard Worker 	erofs_bdrop(bh, false);
949*33b1fccfSAndroid Build Coastguard Worker out:
950*33b1fccfSAndroid Build Coastguard Worker 	erofs_cleanxattrs(true);
951*33b1fccfSAndroid Build Coastguard Worker 	return ret;
952*33b1fccfSAndroid Build Coastguard Worker }
953*33b1fccfSAndroid Build Coastguard Worker 
erofs_export_xattr_ibody(struct erofs_inode * inode)954*33b1fccfSAndroid Build Coastguard Worker char *erofs_export_xattr_ibody(struct erofs_inode *inode)
955*33b1fccfSAndroid Build Coastguard Worker {
956*33b1fccfSAndroid Build Coastguard Worker 	struct list_head *ixattrs = &inode->i_xattrs;
957*33b1fccfSAndroid Build Coastguard Worker 	unsigned int size = inode->xattr_isize;
958*33b1fccfSAndroid Build Coastguard Worker 	struct inode_xattr_node *node, *n;
959*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_item *item;
960*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_xattr_ibody_header *header;
961*33b1fccfSAndroid Build Coastguard Worker 	LIST_HEAD(ilst);
962*33b1fccfSAndroid Build Coastguard Worker 	unsigned int p;
963*33b1fccfSAndroid Build Coastguard Worker 	char *buf = calloc(1, size);
964*33b1fccfSAndroid Build Coastguard Worker 
965*33b1fccfSAndroid Build Coastguard Worker 	if (!buf)
966*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(-ENOMEM);
967*33b1fccfSAndroid Build Coastguard Worker 
968*33b1fccfSAndroid Build Coastguard Worker 	header = (struct erofs_xattr_ibody_header *)buf;
969*33b1fccfSAndroid Build Coastguard Worker 	header->h_shared_count = 0;
970*33b1fccfSAndroid Build Coastguard Worker 
971*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_xattr_name_filter) {
972*33b1fccfSAndroid Build Coastguard Worker 		u32 name_filter = 0;
973*33b1fccfSAndroid Build Coastguard Worker 		int hashbit;
974*33b1fccfSAndroid Build Coastguard Worker 		unsigned int base_len;
975*33b1fccfSAndroid Build Coastguard Worker 
976*33b1fccfSAndroid Build Coastguard Worker 		list_for_each_entry(node, ixattrs, list) {
977*33b1fccfSAndroid Build Coastguard Worker 			item = node->item;
978*33b1fccfSAndroid Build Coastguard Worker 			base_len = xattr_types[item->base_index].prefix_len;
979*33b1fccfSAndroid Build Coastguard Worker 			hashbit = xxh32(item->kvbuf + base_len,
980*33b1fccfSAndroid Build Coastguard Worker 					item->len[0] - base_len,
981*33b1fccfSAndroid Build Coastguard Worker 					EROFS_XATTR_FILTER_SEED + item->base_index) &
982*33b1fccfSAndroid Build Coastguard Worker 				  (EROFS_XATTR_FILTER_BITS - 1);
983*33b1fccfSAndroid Build Coastguard Worker 			name_filter |= (1UL << hashbit);
984*33b1fccfSAndroid Build Coastguard Worker 		}
985*33b1fccfSAndroid Build Coastguard Worker 		name_filter = EROFS_XATTR_FILTER_DEFAULT & ~name_filter;
986*33b1fccfSAndroid Build Coastguard Worker 
987*33b1fccfSAndroid Build Coastguard Worker 		header->h_name_filter = cpu_to_le32(name_filter);
988*33b1fccfSAndroid Build Coastguard Worker 		if (header->h_name_filter)
989*33b1fccfSAndroid Build Coastguard Worker 			erofs_sb_set_xattr_filter(inode->sbi);
990*33b1fccfSAndroid Build Coastguard Worker 	}
991*33b1fccfSAndroid Build Coastguard Worker 
992*33b1fccfSAndroid Build Coastguard Worker 	p = sizeof(struct erofs_xattr_ibody_header);
993*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry_safe(node, n, ixattrs, list) {
994*33b1fccfSAndroid Build Coastguard Worker 		item = node->item;
995*33b1fccfSAndroid Build Coastguard Worker 		list_del(&node->list);
996*33b1fccfSAndroid Build Coastguard Worker 
997*33b1fccfSAndroid Build Coastguard Worker 		/* move inline xattrs to the onstack list */
998*33b1fccfSAndroid Build Coastguard Worker 		if (item->shared_xattr_id < 0 ||
999*33b1fccfSAndroid Build Coastguard Worker 		    header->h_shared_count >= UCHAR_MAX) {
1000*33b1fccfSAndroid Build Coastguard Worker 			list_add(&node->list, &ilst);
1001*33b1fccfSAndroid Build Coastguard Worker 			continue;
1002*33b1fccfSAndroid Build Coastguard Worker 		}
1003*33b1fccfSAndroid Build Coastguard Worker 
1004*33b1fccfSAndroid Build Coastguard Worker 		*(__le32 *)(buf + p) = cpu_to_le32(item->shared_xattr_id);
1005*33b1fccfSAndroid Build Coastguard Worker 		p += sizeof(__le32);
1006*33b1fccfSAndroid Build Coastguard Worker 		++header->h_shared_count;
1007*33b1fccfSAndroid Build Coastguard Worker 		free(node);
1008*33b1fccfSAndroid Build Coastguard Worker 		put_xattritem(item);
1009*33b1fccfSAndroid Build Coastguard Worker 	}
1010*33b1fccfSAndroid Build Coastguard Worker 
1011*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry_safe(node, n, &ilst, list) {
1012*33b1fccfSAndroid Build Coastguard Worker 		item = node->item;
1013*33b1fccfSAndroid Build Coastguard Worker 		erofs_write_xattr_entry(buf + p, item);
1014*33b1fccfSAndroid Build Coastguard Worker 		p = erofs_next_xattr_align(p, item);
1015*33b1fccfSAndroid Build Coastguard Worker 		list_del(&node->list);
1016*33b1fccfSAndroid Build Coastguard Worker 		free(node);
1017*33b1fccfSAndroid Build Coastguard Worker 		put_xattritem(item);
1018*33b1fccfSAndroid Build Coastguard Worker 	}
1019*33b1fccfSAndroid Build Coastguard Worker 	if (p < size) {
1020*33b1fccfSAndroid Build Coastguard Worker 		memset(buf + p, 0, size - p);
1021*33b1fccfSAndroid Build Coastguard Worker 	} else if (__erofs_unlikely(p > size)) {
1022*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(1);
1023*33b1fccfSAndroid Build Coastguard Worker 		free(buf);
1024*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(-EFAULT);
1025*33b1fccfSAndroid Build Coastguard Worker 	}
1026*33b1fccfSAndroid Build Coastguard Worker 	return buf;
1027*33b1fccfSAndroid Build Coastguard Worker }
1028*33b1fccfSAndroid Build Coastguard Worker 
1029*33b1fccfSAndroid Build Coastguard Worker struct xattr_iter {
1030*33b1fccfSAndroid Build Coastguard Worker 	char page[EROFS_MAX_BLOCK_SIZE];
1031*33b1fccfSAndroid Build Coastguard Worker 
1032*33b1fccfSAndroid Build Coastguard Worker 	void *kaddr;
1033*33b1fccfSAndroid Build Coastguard Worker 
1034*33b1fccfSAndroid Build Coastguard Worker 	erofs_blk_t blkaddr;
1035*33b1fccfSAndroid Build Coastguard Worker 	unsigned int ofs;
1036*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi;
1037*33b1fccfSAndroid Build Coastguard Worker };
1038*33b1fccfSAndroid Build Coastguard Worker 
init_inode_xattrs(struct erofs_inode * vi)1039*33b1fccfSAndroid Build Coastguard Worker static int init_inode_xattrs(struct erofs_inode *vi)
1040*33b1fccfSAndroid Build Coastguard Worker {
1041*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = vi->sbi;
1042*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_iter it;
1043*33b1fccfSAndroid Build Coastguard Worker 	unsigned int i;
1044*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_xattr_ibody_header *ih;
1045*33b1fccfSAndroid Build Coastguard Worker 	int ret = 0;
1046*33b1fccfSAndroid Build Coastguard Worker 
1047*33b1fccfSAndroid Build Coastguard Worker 	/* the most case is that xattrs of this inode are initialized. */
1048*33b1fccfSAndroid Build Coastguard Worker 	if (vi->flags & EROFS_I_EA_INITED)
1049*33b1fccfSAndroid Build Coastguard Worker 		return ret;
1050*33b1fccfSAndroid Build Coastguard Worker 
1051*33b1fccfSAndroid Build Coastguard Worker 	/*
1052*33b1fccfSAndroid Build Coastguard Worker 	 * bypass all xattr operations if ->xattr_isize is not greater than
1053*33b1fccfSAndroid Build Coastguard Worker 	 * sizeof(struct erofs_xattr_ibody_header), in detail:
1054*33b1fccfSAndroid Build Coastguard Worker 	 * 1) it is not enough to contain erofs_xattr_ibody_header then
1055*33b1fccfSAndroid Build Coastguard Worker 	 *    ->xattr_isize should be 0 (it means no xattr);
1056*33b1fccfSAndroid Build Coastguard Worker 	 * 2) it is just to contain erofs_xattr_ibody_header, which is on-disk
1057*33b1fccfSAndroid Build Coastguard Worker 	 *    undefined right now (maybe use later with some new sb feature).
1058*33b1fccfSAndroid Build Coastguard Worker 	 */
1059*33b1fccfSAndroid Build Coastguard Worker 	if (vi->xattr_isize == sizeof(struct erofs_xattr_ibody_header)) {
1060*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("xattr_isize %d of nid %llu is not supported yet",
1061*33b1fccfSAndroid Build Coastguard Worker 			  vi->xattr_isize, vi->nid);
1062*33b1fccfSAndroid Build Coastguard Worker 		return -EOPNOTSUPP;
1063*33b1fccfSAndroid Build Coastguard Worker 	} else if (vi->xattr_isize < sizeof(struct erofs_xattr_ibody_header)) {
1064*33b1fccfSAndroid Build Coastguard Worker 		if (vi->xattr_isize) {
1065*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("bogus xattr ibody @ nid %llu", vi->nid);
1066*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(1);
1067*33b1fccfSAndroid Build Coastguard Worker 			return -EFSCORRUPTED;	/* xattr ondisk layout error */
1068*33b1fccfSAndroid Build Coastguard Worker 		}
1069*33b1fccfSAndroid Build Coastguard Worker 		return -ENOATTR;
1070*33b1fccfSAndroid Build Coastguard Worker 	}
1071*33b1fccfSAndroid Build Coastguard Worker 
1072*33b1fccfSAndroid Build Coastguard Worker 	it.blkaddr = erofs_blknr(sbi, erofs_iloc(vi) + vi->inode_isize);
1073*33b1fccfSAndroid Build Coastguard Worker 	it.ofs = erofs_blkoff(sbi, erofs_iloc(vi) + vi->inode_isize);
1074*33b1fccfSAndroid Build Coastguard Worker 
1075*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_blk_read(sbi, 0, it.page, it.blkaddr, 1);
1076*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
1077*33b1fccfSAndroid Build Coastguard Worker 		return -EIO;
1078*33b1fccfSAndroid Build Coastguard Worker 
1079*33b1fccfSAndroid Build Coastguard Worker 	it.kaddr = it.page;
1080*33b1fccfSAndroid Build Coastguard Worker 	ih = (struct erofs_xattr_ibody_header *)(it.kaddr + it.ofs);
1081*33b1fccfSAndroid Build Coastguard Worker 
1082*33b1fccfSAndroid Build Coastguard Worker 	vi->xattr_shared_count = ih->h_shared_count;
1083*33b1fccfSAndroid Build Coastguard Worker 	vi->xattr_shared_xattrs = malloc(vi->xattr_shared_count * sizeof(uint));
1084*33b1fccfSAndroid Build Coastguard Worker 	if (!vi->xattr_shared_xattrs)
1085*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
1086*33b1fccfSAndroid Build Coastguard Worker 
1087*33b1fccfSAndroid Build Coastguard Worker 	/* let's skip ibody header */
1088*33b1fccfSAndroid Build Coastguard Worker 	it.ofs += sizeof(struct erofs_xattr_ibody_header);
1089*33b1fccfSAndroid Build Coastguard Worker 
1090*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < vi->xattr_shared_count; ++i) {
1091*33b1fccfSAndroid Build Coastguard Worker 		if (it.ofs >= erofs_blksiz(sbi)) {
1092*33b1fccfSAndroid Build Coastguard Worker 			/* cannot be unaligned */
1093*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(it.ofs != erofs_blksiz(sbi));
1094*33b1fccfSAndroid Build Coastguard Worker 
1095*33b1fccfSAndroid Build Coastguard Worker 			ret = erofs_blk_read(sbi, 0, it.page, ++it.blkaddr, 1);
1096*33b1fccfSAndroid Build Coastguard Worker 			if (ret < 0) {
1097*33b1fccfSAndroid Build Coastguard Worker 				free(vi->xattr_shared_xattrs);
1098*33b1fccfSAndroid Build Coastguard Worker 				vi->xattr_shared_xattrs = NULL;
1099*33b1fccfSAndroid Build Coastguard Worker 				return -EIO;
1100*33b1fccfSAndroid Build Coastguard Worker 			}
1101*33b1fccfSAndroid Build Coastguard Worker 
1102*33b1fccfSAndroid Build Coastguard Worker 			it.kaddr = it.page;
1103*33b1fccfSAndroid Build Coastguard Worker 			it.ofs = 0;
1104*33b1fccfSAndroid Build Coastguard Worker 		}
1105*33b1fccfSAndroid Build Coastguard Worker 		vi->xattr_shared_xattrs[i] =
1106*33b1fccfSAndroid Build Coastguard Worker 			le32_to_cpu(*(__le32 *)(it.kaddr + it.ofs));
1107*33b1fccfSAndroid Build Coastguard Worker 		it.ofs += sizeof(__le32);
1108*33b1fccfSAndroid Build Coastguard Worker 	}
1109*33b1fccfSAndroid Build Coastguard Worker 
1110*33b1fccfSAndroid Build Coastguard Worker 	vi->flags |= EROFS_I_EA_INITED;
1111*33b1fccfSAndroid Build Coastguard Worker 
1112*33b1fccfSAndroid Build Coastguard Worker 	return ret;
1113*33b1fccfSAndroid Build Coastguard Worker }
1114*33b1fccfSAndroid Build Coastguard Worker 
1115*33b1fccfSAndroid Build Coastguard Worker /*
1116*33b1fccfSAndroid Build Coastguard Worker  * the general idea for these return values is
1117*33b1fccfSAndroid Build Coastguard Worker  * if    0 is returned, go on processing the current xattr;
1118*33b1fccfSAndroid Build Coastguard Worker  *       1 (> 0) is returned, skip this round to process the next xattr;
1119*33b1fccfSAndroid Build Coastguard Worker  *    -err (< 0) is returned, an error (maybe ENOXATTR) occurred
1120*33b1fccfSAndroid Build Coastguard Worker  *                            and need to be handled
1121*33b1fccfSAndroid Build Coastguard Worker  */
1122*33b1fccfSAndroid Build Coastguard Worker struct xattr_iter_handlers {
1123*33b1fccfSAndroid Build Coastguard Worker 	int (*entry)(struct xattr_iter *_it, struct erofs_xattr_entry *entry);
1124*33b1fccfSAndroid Build Coastguard Worker 	int (*name)(struct xattr_iter *_it, unsigned int processed, char *buf,
1125*33b1fccfSAndroid Build Coastguard Worker 		    unsigned int len);
1126*33b1fccfSAndroid Build Coastguard Worker 	int (*alloc_buffer)(struct xattr_iter *_it, unsigned int value_sz);
1127*33b1fccfSAndroid Build Coastguard Worker 	void (*value)(struct xattr_iter *_it, unsigned int processed, char *buf,
1128*33b1fccfSAndroid Build Coastguard Worker 		      unsigned int len);
1129*33b1fccfSAndroid Build Coastguard Worker };
1130*33b1fccfSAndroid Build Coastguard Worker 
xattr_iter_fixup(struct xattr_iter * it)1131*33b1fccfSAndroid Build Coastguard Worker static inline int xattr_iter_fixup(struct xattr_iter *it)
1132*33b1fccfSAndroid Build Coastguard Worker {
1133*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = it->sbi;
1134*33b1fccfSAndroid Build Coastguard Worker 	int ret;
1135*33b1fccfSAndroid Build Coastguard Worker 
1136*33b1fccfSAndroid Build Coastguard Worker 	if (it->ofs < erofs_blksiz(sbi))
1137*33b1fccfSAndroid Build Coastguard Worker 		return 0;
1138*33b1fccfSAndroid Build Coastguard Worker 
1139*33b1fccfSAndroid Build Coastguard Worker 	it->blkaddr += erofs_blknr(sbi, it->ofs);
1140*33b1fccfSAndroid Build Coastguard Worker 
1141*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_blk_read(sbi, 0, it->page, it->blkaddr, 1);
1142*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
1143*33b1fccfSAndroid Build Coastguard Worker 		return -EIO;
1144*33b1fccfSAndroid Build Coastguard Worker 
1145*33b1fccfSAndroid Build Coastguard Worker 	it->kaddr = it->page;
1146*33b1fccfSAndroid Build Coastguard Worker 	it->ofs = erofs_blkoff(sbi, it->ofs);
1147*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1148*33b1fccfSAndroid Build Coastguard Worker }
1149*33b1fccfSAndroid Build Coastguard Worker 
inline_xattr_iter_pre(struct xattr_iter * it,struct erofs_inode * vi)1150*33b1fccfSAndroid Build Coastguard Worker static int inline_xattr_iter_pre(struct xattr_iter *it,
1151*33b1fccfSAndroid Build Coastguard Worker 				   struct erofs_inode *vi)
1152*33b1fccfSAndroid Build Coastguard Worker {
1153*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = vi->sbi;
1154*33b1fccfSAndroid Build Coastguard Worker 	unsigned int xattr_header_sz, inline_xattr_ofs;
1155*33b1fccfSAndroid Build Coastguard Worker 	int ret;
1156*33b1fccfSAndroid Build Coastguard Worker 
1157*33b1fccfSAndroid Build Coastguard Worker 	xattr_header_sz = inlinexattr_header_size(vi);
1158*33b1fccfSAndroid Build Coastguard Worker 	if (xattr_header_sz >= vi->xattr_isize) {
1159*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(xattr_header_sz > vi->xattr_isize);
1160*33b1fccfSAndroid Build Coastguard Worker 		return -ENOATTR;
1161*33b1fccfSAndroid Build Coastguard Worker 	}
1162*33b1fccfSAndroid Build Coastguard Worker 
1163*33b1fccfSAndroid Build Coastguard Worker 	inline_xattr_ofs = vi->inode_isize + xattr_header_sz;
1164*33b1fccfSAndroid Build Coastguard Worker 
1165*33b1fccfSAndroid Build Coastguard Worker 	it->blkaddr = erofs_blknr(sbi, erofs_iloc(vi) + inline_xattr_ofs);
1166*33b1fccfSAndroid Build Coastguard Worker 	it->ofs = erofs_blkoff(sbi, erofs_iloc(vi) + inline_xattr_ofs);
1167*33b1fccfSAndroid Build Coastguard Worker 
1168*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_blk_read(sbi, 0, it->page, it->blkaddr, 1);
1169*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
1170*33b1fccfSAndroid Build Coastguard Worker 		return -EIO;
1171*33b1fccfSAndroid Build Coastguard Worker 
1172*33b1fccfSAndroid Build Coastguard Worker 	it->kaddr = it->page;
1173*33b1fccfSAndroid Build Coastguard Worker 	return vi->xattr_isize - xattr_header_sz;
1174*33b1fccfSAndroid Build Coastguard Worker }
1175*33b1fccfSAndroid Build Coastguard Worker 
1176*33b1fccfSAndroid Build Coastguard Worker /*
1177*33b1fccfSAndroid Build Coastguard Worker  * Regardless of success or failure, `xattr_foreach' will end up with
1178*33b1fccfSAndroid Build Coastguard Worker  * `ofs' pointing to the next xattr item rather than an arbitrary position.
1179*33b1fccfSAndroid Build Coastguard Worker  */
xattr_foreach(struct xattr_iter * it,const struct xattr_iter_handlers * op,unsigned int * tlimit)1180*33b1fccfSAndroid Build Coastguard Worker static int xattr_foreach(struct xattr_iter *it,
1181*33b1fccfSAndroid Build Coastguard Worker 			 const struct xattr_iter_handlers *op,
1182*33b1fccfSAndroid Build Coastguard Worker 			 unsigned int *tlimit)
1183*33b1fccfSAndroid Build Coastguard Worker {
1184*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = it->sbi;
1185*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_xattr_entry entry;
1186*33b1fccfSAndroid Build Coastguard Worker 	unsigned int value_sz, processed, slice;
1187*33b1fccfSAndroid Build Coastguard Worker 	int err;
1188*33b1fccfSAndroid Build Coastguard Worker 
1189*33b1fccfSAndroid Build Coastguard Worker 	/* 0. fixup blkaddr, ofs, ipage */
1190*33b1fccfSAndroid Build Coastguard Worker 	err = xattr_iter_fixup(it);
1191*33b1fccfSAndroid Build Coastguard Worker 	if (err)
1192*33b1fccfSAndroid Build Coastguard Worker 		return err;
1193*33b1fccfSAndroid Build Coastguard Worker 
1194*33b1fccfSAndroid Build Coastguard Worker 	/*
1195*33b1fccfSAndroid Build Coastguard Worker 	 * 1. read xattr entry to the memory,
1196*33b1fccfSAndroid Build Coastguard Worker 	 *    since we do EROFS_XATTR_ALIGN
1197*33b1fccfSAndroid Build Coastguard Worker 	 *    therefore entry should be in the page
1198*33b1fccfSAndroid Build Coastguard Worker 	 */
1199*33b1fccfSAndroid Build Coastguard Worker 	entry = *(struct erofs_xattr_entry *)(it->kaddr + it->ofs);
1200*33b1fccfSAndroid Build Coastguard Worker 	if (tlimit) {
1201*33b1fccfSAndroid Build Coastguard Worker 		unsigned int entry_sz = erofs_xattr_entry_size(&entry);
1202*33b1fccfSAndroid Build Coastguard Worker 
1203*33b1fccfSAndroid Build Coastguard Worker 		/* xattr on-disk corruption: xattr entry beyond xattr_isize */
1204*33b1fccfSAndroid Build Coastguard Worker 		if (*tlimit < entry_sz) {
1205*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(1);
1206*33b1fccfSAndroid Build Coastguard Worker 			return -EFSCORRUPTED;
1207*33b1fccfSAndroid Build Coastguard Worker 		}
1208*33b1fccfSAndroid Build Coastguard Worker 		*tlimit -= entry_sz;
1209*33b1fccfSAndroid Build Coastguard Worker 	}
1210*33b1fccfSAndroid Build Coastguard Worker 
1211*33b1fccfSAndroid Build Coastguard Worker 	it->ofs += sizeof(struct erofs_xattr_entry);
1212*33b1fccfSAndroid Build Coastguard Worker 	value_sz = le16_to_cpu(entry.e_value_size);
1213*33b1fccfSAndroid Build Coastguard Worker 
1214*33b1fccfSAndroid Build Coastguard Worker 	/* handle entry */
1215*33b1fccfSAndroid Build Coastguard Worker 	err = op->entry(it, &entry);
1216*33b1fccfSAndroid Build Coastguard Worker 	if (err) {
1217*33b1fccfSAndroid Build Coastguard Worker 		it->ofs += entry.e_name_len + value_sz;
1218*33b1fccfSAndroid Build Coastguard Worker 		goto out;
1219*33b1fccfSAndroid Build Coastguard Worker 	}
1220*33b1fccfSAndroid Build Coastguard Worker 
1221*33b1fccfSAndroid Build Coastguard Worker 	/* 2. handle xattr name (ofs will finally be at the end of name) */
1222*33b1fccfSAndroid Build Coastguard Worker 	processed = 0;
1223*33b1fccfSAndroid Build Coastguard Worker 
1224*33b1fccfSAndroid Build Coastguard Worker 	while (processed < entry.e_name_len) {
1225*33b1fccfSAndroid Build Coastguard Worker 		if (it->ofs >= erofs_blksiz(sbi)) {
1226*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(it->ofs > erofs_blksiz(sbi));
1227*33b1fccfSAndroid Build Coastguard Worker 
1228*33b1fccfSAndroid Build Coastguard Worker 			err = xattr_iter_fixup(it);
1229*33b1fccfSAndroid Build Coastguard Worker 			if (err)
1230*33b1fccfSAndroid Build Coastguard Worker 				goto out;
1231*33b1fccfSAndroid Build Coastguard Worker 			it->ofs = 0;
1232*33b1fccfSAndroid Build Coastguard Worker 		}
1233*33b1fccfSAndroid Build Coastguard Worker 
1234*33b1fccfSAndroid Build Coastguard Worker 		slice = min_t(unsigned int, erofs_blksiz(sbi) - it->ofs,
1235*33b1fccfSAndroid Build Coastguard Worker 			      entry.e_name_len - processed);
1236*33b1fccfSAndroid Build Coastguard Worker 
1237*33b1fccfSAndroid Build Coastguard Worker 		/* handle name */
1238*33b1fccfSAndroid Build Coastguard Worker 		err = op->name(it, processed, it->kaddr + it->ofs, slice);
1239*33b1fccfSAndroid Build Coastguard Worker 		if (err) {
1240*33b1fccfSAndroid Build Coastguard Worker 			it->ofs += entry.e_name_len - processed + value_sz;
1241*33b1fccfSAndroid Build Coastguard Worker 			goto out;
1242*33b1fccfSAndroid Build Coastguard Worker 		}
1243*33b1fccfSAndroid Build Coastguard Worker 
1244*33b1fccfSAndroid Build Coastguard Worker 		it->ofs += slice;
1245*33b1fccfSAndroid Build Coastguard Worker 		processed += slice;
1246*33b1fccfSAndroid Build Coastguard Worker 	}
1247*33b1fccfSAndroid Build Coastguard Worker 
1248*33b1fccfSAndroid Build Coastguard Worker 	/* 3. handle xattr value */
1249*33b1fccfSAndroid Build Coastguard Worker 	processed = 0;
1250*33b1fccfSAndroid Build Coastguard Worker 
1251*33b1fccfSAndroid Build Coastguard Worker 	if (op->alloc_buffer) {
1252*33b1fccfSAndroid Build Coastguard Worker 		err = op->alloc_buffer(it, value_sz);
1253*33b1fccfSAndroid Build Coastguard Worker 		if (err) {
1254*33b1fccfSAndroid Build Coastguard Worker 			it->ofs += value_sz;
1255*33b1fccfSAndroid Build Coastguard Worker 			goto out;
1256*33b1fccfSAndroid Build Coastguard Worker 		}
1257*33b1fccfSAndroid Build Coastguard Worker 	}
1258*33b1fccfSAndroid Build Coastguard Worker 
1259*33b1fccfSAndroid Build Coastguard Worker 	while (processed < value_sz) {
1260*33b1fccfSAndroid Build Coastguard Worker 		if (it->ofs >= erofs_blksiz(sbi)) {
1261*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(it->ofs > erofs_blksiz(sbi));
1262*33b1fccfSAndroid Build Coastguard Worker 
1263*33b1fccfSAndroid Build Coastguard Worker 			err = xattr_iter_fixup(it);
1264*33b1fccfSAndroid Build Coastguard Worker 			if (err)
1265*33b1fccfSAndroid Build Coastguard Worker 				goto out;
1266*33b1fccfSAndroid Build Coastguard Worker 			it->ofs = 0;
1267*33b1fccfSAndroid Build Coastguard Worker 		}
1268*33b1fccfSAndroid Build Coastguard Worker 
1269*33b1fccfSAndroid Build Coastguard Worker 		slice = min_t(unsigned int, erofs_blksiz(sbi) - it->ofs,
1270*33b1fccfSAndroid Build Coastguard Worker 			      value_sz - processed);
1271*33b1fccfSAndroid Build Coastguard Worker 		op->value(it, processed, it->kaddr + it->ofs, slice);
1272*33b1fccfSAndroid Build Coastguard Worker 		it->ofs += slice;
1273*33b1fccfSAndroid Build Coastguard Worker 		processed += slice;
1274*33b1fccfSAndroid Build Coastguard Worker 	}
1275*33b1fccfSAndroid Build Coastguard Worker 
1276*33b1fccfSAndroid Build Coastguard Worker out:
1277*33b1fccfSAndroid Build Coastguard Worker 	/* xattrs should be 4-byte aligned (on-disk constraint) */
1278*33b1fccfSAndroid Build Coastguard Worker 	it->ofs = EROFS_XATTR_ALIGN(it->ofs);
1279*33b1fccfSAndroid Build Coastguard Worker 	return err < 0 ? err : 0;
1280*33b1fccfSAndroid Build Coastguard Worker }
1281*33b1fccfSAndroid Build Coastguard Worker 
1282*33b1fccfSAndroid Build Coastguard Worker struct getxattr_iter {
1283*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_iter it;
1284*33b1fccfSAndroid Build Coastguard Worker 
1285*33b1fccfSAndroid Build Coastguard Worker 	int buffer_size, index, infix_len;
1286*33b1fccfSAndroid Build Coastguard Worker 	char *buffer;
1287*33b1fccfSAndroid Build Coastguard Worker 	const char *name;
1288*33b1fccfSAndroid Build Coastguard Worker 	size_t len;
1289*33b1fccfSAndroid Build Coastguard Worker };
1290*33b1fccfSAndroid Build Coastguard Worker 
erofs_xattr_long_entrymatch(struct getxattr_iter * it,struct erofs_xattr_entry * entry)1291*33b1fccfSAndroid Build Coastguard Worker static int erofs_xattr_long_entrymatch(struct getxattr_iter *it,
1292*33b1fccfSAndroid Build Coastguard Worker 				       struct erofs_xattr_entry *entry)
1293*33b1fccfSAndroid Build Coastguard Worker {
1294*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = it->it.sbi;
1295*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_xattr_prefix_item *pf = sbi->xattr_prefixes +
1296*33b1fccfSAndroid Build Coastguard Worker 		(entry->e_name_index & EROFS_XATTR_LONG_PREFIX_MASK);
1297*33b1fccfSAndroid Build Coastguard Worker 
1298*33b1fccfSAndroid Build Coastguard Worker 	if (pf >= sbi->xattr_prefixes + sbi->xattr_prefix_count)
1299*33b1fccfSAndroid Build Coastguard Worker 		return -ENOATTR;
1300*33b1fccfSAndroid Build Coastguard Worker 
1301*33b1fccfSAndroid Build Coastguard Worker 	if (it->index != pf->prefix->base_index ||
1302*33b1fccfSAndroid Build Coastguard Worker 	    it->len != entry->e_name_len + pf->infix_len)
1303*33b1fccfSAndroid Build Coastguard Worker 		return -ENOATTR;
1304*33b1fccfSAndroid Build Coastguard Worker 
1305*33b1fccfSAndroid Build Coastguard Worker 	if (memcmp(it->name, pf->prefix->infix, pf->infix_len))
1306*33b1fccfSAndroid Build Coastguard Worker 		return -ENOATTR;
1307*33b1fccfSAndroid Build Coastguard Worker 
1308*33b1fccfSAndroid Build Coastguard Worker 	it->infix_len = pf->infix_len;
1309*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1310*33b1fccfSAndroid Build Coastguard Worker }
1311*33b1fccfSAndroid Build Coastguard Worker 
xattr_entrymatch(struct xattr_iter * _it,struct erofs_xattr_entry * entry)1312*33b1fccfSAndroid Build Coastguard Worker static int xattr_entrymatch(struct xattr_iter *_it,
1313*33b1fccfSAndroid Build Coastguard Worker 			    struct erofs_xattr_entry *entry)
1314*33b1fccfSAndroid Build Coastguard Worker {
1315*33b1fccfSAndroid Build Coastguard Worker 	struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
1316*33b1fccfSAndroid Build Coastguard Worker 
1317*33b1fccfSAndroid Build Coastguard Worker 	/* should also match the infix for long name prefixes */
1318*33b1fccfSAndroid Build Coastguard Worker 	if (entry->e_name_index & EROFS_XATTR_LONG_PREFIX)
1319*33b1fccfSAndroid Build Coastguard Worker 		return erofs_xattr_long_entrymatch(it, entry);
1320*33b1fccfSAndroid Build Coastguard Worker 
1321*33b1fccfSAndroid Build Coastguard Worker 	if (it->index != entry->e_name_index ||
1322*33b1fccfSAndroid Build Coastguard Worker 	    it->len != entry->e_name_len)
1323*33b1fccfSAndroid Build Coastguard Worker 		return -ENOATTR;
1324*33b1fccfSAndroid Build Coastguard Worker 	it->infix_len = 0;
1325*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1326*33b1fccfSAndroid Build Coastguard Worker }
1327*33b1fccfSAndroid Build Coastguard Worker 
xattr_namematch(struct xattr_iter * _it,unsigned int processed,char * buf,unsigned int len)1328*33b1fccfSAndroid Build Coastguard Worker static int xattr_namematch(struct xattr_iter *_it,
1329*33b1fccfSAndroid Build Coastguard Worker 			   unsigned int processed, char *buf, unsigned int len)
1330*33b1fccfSAndroid Build Coastguard Worker {
1331*33b1fccfSAndroid Build Coastguard Worker 	struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
1332*33b1fccfSAndroid Build Coastguard Worker 
1333*33b1fccfSAndroid Build Coastguard Worker 	if (memcmp(buf, it->name + it->infix_len + processed, len))
1334*33b1fccfSAndroid Build Coastguard Worker 		return -ENOATTR;
1335*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1336*33b1fccfSAndroid Build Coastguard Worker }
1337*33b1fccfSAndroid Build Coastguard Worker 
xattr_checkbuffer(struct xattr_iter * _it,unsigned int value_sz)1338*33b1fccfSAndroid Build Coastguard Worker static int xattr_checkbuffer(struct xattr_iter *_it,
1339*33b1fccfSAndroid Build Coastguard Worker 			     unsigned int value_sz)
1340*33b1fccfSAndroid Build Coastguard Worker {
1341*33b1fccfSAndroid Build Coastguard Worker 	struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
1342*33b1fccfSAndroid Build Coastguard Worker 	int err = it->buffer_size < value_sz ? -ERANGE : 0;
1343*33b1fccfSAndroid Build Coastguard Worker 
1344*33b1fccfSAndroid Build Coastguard Worker 	it->buffer_size = value_sz;
1345*33b1fccfSAndroid Build Coastguard Worker 	return !it->buffer ? 1 : err;
1346*33b1fccfSAndroid Build Coastguard Worker }
1347*33b1fccfSAndroid Build Coastguard Worker 
xattr_copyvalue(struct xattr_iter * _it,unsigned int processed,char * buf,unsigned int len)1348*33b1fccfSAndroid Build Coastguard Worker static void xattr_copyvalue(struct xattr_iter *_it,
1349*33b1fccfSAndroid Build Coastguard Worker 			    unsigned int processed,
1350*33b1fccfSAndroid Build Coastguard Worker 			    char *buf, unsigned int len)
1351*33b1fccfSAndroid Build Coastguard Worker {
1352*33b1fccfSAndroid Build Coastguard Worker 	struct getxattr_iter *it = container_of(_it, struct getxattr_iter, it);
1353*33b1fccfSAndroid Build Coastguard Worker 
1354*33b1fccfSAndroid Build Coastguard Worker 	memcpy(it->buffer + processed, buf, len);
1355*33b1fccfSAndroid Build Coastguard Worker }
1356*33b1fccfSAndroid Build Coastguard Worker 
1357*33b1fccfSAndroid Build Coastguard Worker static const struct xattr_iter_handlers find_xattr_handlers = {
1358*33b1fccfSAndroid Build Coastguard Worker 	.entry = xattr_entrymatch,
1359*33b1fccfSAndroid Build Coastguard Worker 	.name = xattr_namematch,
1360*33b1fccfSAndroid Build Coastguard Worker 	.alloc_buffer = xattr_checkbuffer,
1361*33b1fccfSAndroid Build Coastguard Worker 	.value = xattr_copyvalue
1362*33b1fccfSAndroid Build Coastguard Worker };
1363*33b1fccfSAndroid Build Coastguard Worker 
inline_getxattr(struct erofs_inode * vi,struct getxattr_iter * it)1364*33b1fccfSAndroid Build Coastguard Worker static int inline_getxattr(struct erofs_inode *vi, struct getxattr_iter *it)
1365*33b1fccfSAndroid Build Coastguard Worker {
1366*33b1fccfSAndroid Build Coastguard Worker 	int ret;
1367*33b1fccfSAndroid Build Coastguard Worker 	unsigned int remaining;
1368*33b1fccfSAndroid Build Coastguard Worker 
1369*33b1fccfSAndroid Build Coastguard Worker 	ret = inline_xattr_iter_pre(&it->it, vi);
1370*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
1371*33b1fccfSAndroid Build Coastguard Worker 		return ret;
1372*33b1fccfSAndroid Build Coastguard Worker 
1373*33b1fccfSAndroid Build Coastguard Worker 	remaining = ret;
1374*33b1fccfSAndroid Build Coastguard Worker 	while (remaining) {
1375*33b1fccfSAndroid Build Coastguard Worker 		ret = xattr_foreach(&it->it, &find_xattr_handlers, &remaining);
1376*33b1fccfSAndroid Build Coastguard Worker 		if (ret != -ENOATTR)
1377*33b1fccfSAndroid Build Coastguard Worker 			break;
1378*33b1fccfSAndroid Build Coastguard Worker 	}
1379*33b1fccfSAndroid Build Coastguard Worker 
1380*33b1fccfSAndroid Build Coastguard Worker 	return ret ? ret : it->buffer_size;
1381*33b1fccfSAndroid Build Coastguard Worker }
1382*33b1fccfSAndroid Build Coastguard Worker 
shared_getxattr(struct erofs_inode * vi,struct getxattr_iter * it)1383*33b1fccfSAndroid Build Coastguard Worker static int shared_getxattr(struct erofs_inode *vi, struct getxattr_iter *it)
1384*33b1fccfSAndroid Build Coastguard Worker {
1385*33b1fccfSAndroid Build Coastguard Worker 	unsigned int i;
1386*33b1fccfSAndroid Build Coastguard Worker 	int ret = -ENOATTR;
1387*33b1fccfSAndroid Build Coastguard Worker 
1388*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < vi->xattr_shared_count; ++i) {
1389*33b1fccfSAndroid Build Coastguard Worker 		erofs_blk_t blkaddr =
1390*33b1fccfSAndroid Build Coastguard Worker 			xattrblock_addr(vi, vi->xattr_shared_xattrs[i]);
1391*33b1fccfSAndroid Build Coastguard Worker 
1392*33b1fccfSAndroid Build Coastguard Worker 		it->it.ofs = xattrblock_offset(vi, vi->xattr_shared_xattrs[i]);
1393*33b1fccfSAndroid Build Coastguard Worker 
1394*33b1fccfSAndroid Build Coastguard Worker 		if (!i || blkaddr != it->it.blkaddr) {
1395*33b1fccfSAndroid Build Coastguard Worker 			ret = erofs_blk_read(vi->sbi, 0, it->it.page, blkaddr, 1);
1396*33b1fccfSAndroid Build Coastguard Worker 			if (ret < 0)
1397*33b1fccfSAndroid Build Coastguard Worker 				return -EIO;
1398*33b1fccfSAndroid Build Coastguard Worker 
1399*33b1fccfSAndroid Build Coastguard Worker 			it->it.kaddr = it->it.page;
1400*33b1fccfSAndroid Build Coastguard Worker 			it->it.blkaddr = blkaddr;
1401*33b1fccfSAndroid Build Coastguard Worker 		}
1402*33b1fccfSAndroid Build Coastguard Worker 
1403*33b1fccfSAndroid Build Coastguard Worker 		ret = xattr_foreach(&it->it, &find_xattr_handlers, NULL);
1404*33b1fccfSAndroid Build Coastguard Worker 		if (ret != -ENOATTR)
1405*33b1fccfSAndroid Build Coastguard Worker 			break;
1406*33b1fccfSAndroid Build Coastguard Worker 	}
1407*33b1fccfSAndroid Build Coastguard Worker 
1408*33b1fccfSAndroid Build Coastguard Worker 	return ret ? ret : it->buffer_size;
1409*33b1fccfSAndroid Build Coastguard Worker }
1410*33b1fccfSAndroid Build Coastguard Worker 
erofs_getxattr(struct erofs_inode * vi,const char * name,char * buffer,size_t buffer_size)1411*33b1fccfSAndroid Build Coastguard Worker int erofs_getxattr(struct erofs_inode *vi, const char *name, char *buffer,
1412*33b1fccfSAndroid Build Coastguard Worker 		   size_t buffer_size)
1413*33b1fccfSAndroid Build Coastguard Worker {
1414*33b1fccfSAndroid Build Coastguard Worker 	int ret;
1415*33b1fccfSAndroid Build Coastguard Worker 	unsigned int prefix, prefixlen;
1416*33b1fccfSAndroid Build Coastguard Worker 	struct getxattr_iter it;
1417*33b1fccfSAndroid Build Coastguard Worker 
1418*33b1fccfSAndroid Build Coastguard Worker 	if (!name)
1419*33b1fccfSAndroid Build Coastguard Worker 		return -EINVAL;
1420*33b1fccfSAndroid Build Coastguard Worker 
1421*33b1fccfSAndroid Build Coastguard Worker 	ret = init_inode_xattrs(vi);
1422*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
1423*33b1fccfSAndroid Build Coastguard Worker 		return ret;
1424*33b1fccfSAndroid Build Coastguard Worker 
1425*33b1fccfSAndroid Build Coastguard Worker 	if (!match_prefix(name, &prefix, &prefixlen))
1426*33b1fccfSAndroid Build Coastguard Worker 		return -ENODATA;
1427*33b1fccfSAndroid Build Coastguard Worker 
1428*33b1fccfSAndroid Build Coastguard Worker 	it.it.sbi = vi->sbi;
1429*33b1fccfSAndroid Build Coastguard Worker 	it.index = prefix;
1430*33b1fccfSAndroid Build Coastguard Worker 	it.name = name + prefixlen;
1431*33b1fccfSAndroid Build Coastguard Worker 	it.len = strlen(it.name);
1432*33b1fccfSAndroid Build Coastguard Worker 	if (it.len > EROFS_NAME_LEN)
1433*33b1fccfSAndroid Build Coastguard Worker 		return -ERANGE;
1434*33b1fccfSAndroid Build Coastguard Worker 
1435*33b1fccfSAndroid Build Coastguard Worker 	it.buffer = buffer;
1436*33b1fccfSAndroid Build Coastguard Worker 	it.buffer_size = buffer_size;
1437*33b1fccfSAndroid Build Coastguard Worker 
1438*33b1fccfSAndroid Build Coastguard Worker 	ret = inline_getxattr(vi, &it);
1439*33b1fccfSAndroid Build Coastguard Worker 	if (ret == -ENOATTR)
1440*33b1fccfSAndroid Build Coastguard Worker 		ret = shared_getxattr(vi, &it);
1441*33b1fccfSAndroid Build Coastguard Worker 	return ret;
1442*33b1fccfSAndroid Build Coastguard Worker }
1443*33b1fccfSAndroid Build Coastguard Worker 
1444*33b1fccfSAndroid Build Coastguard Worker struct listxattr_iter {
1445*33b1fccfSAndroid Build Coastguard Worker 	struct xattr_iter it;
1446*33b1fccfSAndroid Build Coastguard Worker 
1447*33b1fccfSAndroid Build Coastguard Worker 	char *buffer;
1448*33b1fccfSAndroid Build Coastguard Worker 	int buffer_size, buffer_ofs;
1449*33b1fccfSAndroid Build Coastguard Worker };
1450*33b1fccfSAndroid Build Coastguard Worker 
xattr_entrylist(struct xattr_iter * _it,struct erofs_xattr_entry * entry)1451*33b1fccfSAndroid Build Coastguard Worker static int xattr_entrylist(struct xattr_iter *_it,
1452*33b1fccfSAndroid Build Coastguard Worker 			   struct erofs_xattr_entry *entry)
1453*33b1fccfSAndroid Build Coastguard Worker {
1454*33b1fccfSAndroid Build Coastguard Worker 	struct listxattr_iter *it =
1455*33b1fccfSAndroid Build Coastguard Worker 		container_of(_it, struct listxattr_iter, it);
1456*33b1fccfSAndroid Build Coastguard Worker 	unsigned int base_index = entry->e_name_index;
1457*33b1fccfSAndroid Build Coastguard Worker 	unsigned int prefix_len, infix_len = 0;
1458*33b1fccfSAndroid Build Coastguard Worker 	const char *prefix, *infix = NULL;
1459*33b1fccfSAndroid Build Coastguard Worker 
1460*33b1fccfSAndroid Build Coastguard Worker 	if (entry->e_name_index & EROFS_XATTR_LONG_PREFIX) {
1461*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_sb_info *sbi = _it->sbi;
1462*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_xattr_prefix_item *pf = sbi->xattr_prefixes +
1463*33b1fccfSAndroid Build Coastguard Worker 			(entry->e_name_index & EROFS_XATTR_LONG_PREFIX_MASK);
1464*33b1fccfSAndroid Build Coastguard Worker 
1465*33b1fccfSAndroid Build Coastguard Worker 		if (pf >= sbi->xattr_prefixes + sbi->xattr_prefix_count)
1466*33b1fccfSAndroid Build Coastguard Worker 			return 1;
1467*33b1fccfSAndroid Build Coastguard Worker 		infix = pf->prefix->infix;
1468*33b1fccfSAndroid Build Coastguard Worker 		infix_len = pf->infix_len;
1469*33b1fccfSAndroid Build Coastguard Worker 		base_index = pf->prefix->base_index;
1470*33b1fccfSAndroid Build Coastguard Worker 	}
1471*33b1fccfSAndroid Build Coastguard Worker 
1472*33b1fccfSAndroid Build Coastguard Worker 	if (!base_index || base_index >= ARRAY_SIZE(xattr_types))
1473*33b1fccfSAndroid Build Coastguard Worker 		return 1;
1474*33b1fccfSAndroid Build Coastguard Worker 	prefix = xattr_types[base_index].prefix;
1475*33b1fccfSAndroid Build Coastguard Worker 	prefix_len = xattr_types[base_index].prefix_len;
1476*33b1fccfSAndroid Build Coastguard Worker 
1477*33b1fccfSAndroid Build Coastguard Worker 	if (!it->buffer) {
1478*33b1fccfSAndroid Build Coastguard Worker 		it->buffer_ofs += prefix_len + infix_len +
1479*33b1fccfSAndroid Build Coastguard Worker 					entry->e_name_len + 1;
1480*33b1fccfSAndroid Build Coastguard Worker 		return 1;
1481*33b1fccfSAndroid Build Coastguard Worker 	}
1482*33b1fccfSAndroid Build Coastguard Worker 
1483*33b1fccfSAndroid Build Coastguard Worker 	if (it->buffer_ofs + prefix_len + infix_len
1484*33b1fccfSAndroid Build Coastguard Worker 		+ entry->e_name_len + 1 > it->buffer_size)
1485*33b1fccfSAndroid Build Coastguard Worker 		return -ERANGE;
1486*33b1fccfSAndroid Build Coastguard Worker 
1487*33b1fccfSAndroid Build Coastguard Worker 	memcpy(it->buffer + it->buffer_ofs, prefix, prefix_len);
1488*33b1fccfSAndroid Build Coastguard Worker 	memcpy(it->buffer + it->buffer_ofs + prefix_len, infix, infix_len);
1489*33b1fccfSAndroid Build Coastguard Worker 	it->buffer_ofs += prefix_len + infix_len;
1490*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1491*33b1fccfSAndroid Build Coastguard Worker }
1492*33b1fccfSAndroid Build Coastguard Worker 
xattr_namelist(struct xattr_iter * _it,unsigned int processed,char * buf,unsigned int len)1493*33b1fccfSAndroid Build Coastguard Worker static int xattr_namelist(struct xattr_iter *_it,
1494*33b1fccfSAndroid Build Coastguard Worker 			  unsigned int processed, char *buf, unsigned int len)
1495*33b1fccfSAndroid Build Coastguard Worker {
1496*33b1fccfSAndroid Build Coastguard Worker 	struct listxattr_iter *it =
1497*33b1fccfSAndroid Build Coastguard Worker 		container_of(_it, struct listxattr_iter, it);
1498*33b1fccfSAndroid Build Coastguard Worker 
1499*33b1fccfSAndroid Build Coastguard Worker 	memcpy(it->buffer + it->buffer_ofs, buf, len);
1500*33b1fccfSAndroid Build Coastguard Worker 	it->buffer_ofs += len;
1501*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1502*33b1fccfSAndroid Build Coastguard Worker }
1503*33b1fccfSAndroid Build Coastguard Worker 
xattr_skipvalue(struct xattr_iter * _it,unsigned int value_sz)1504*33b1fccfSAndroid Build Coastguard Worker static int xattr_skipvalue(struct xattr_iter *_it,
1505*33b1fccfSAndroid Build Coastguard Worker 			   unsigned int value_sz)
1506*33b1fccfSAndroid Build Coastguard Worker {
1507*33b1fccfSAndroid Build Coastguard Worker 	struct listxattr_iter *it =
1508*33b1fccfSAndroid Build Coastguard Worker 		container_of(_it, struct listxattr_iter, it);
1509*33b1fccfSAndroid Build Coastguard Worker 
1510*33b1fccfSAndroid Build Coastguard Worker 	it->buffer[it->buffer_ofs++] = '\0';
1511*33b1fccfSAndroid Build Coastguard Worker 	return 1;
1512*33b1fccfSAndroid Build Coastguard Worker }
1513*33b1fccfSAndroid Build Coastguard Worker 
1514*33b1fccfSAndroid Build Coastguard Worker static const struct xattr_iter_handlers list_xattr_handlers = {
1515*33b1fccfSAndroid Build Coastguard Worker 	.entry = xattr_entrylist,
1516*33b1fccfSAndroid Build Coastguard Worker 	.name = xattr_namelist,
1517*33b1fccfSAndroid Build Coastguard Worker 	.alloc_buffer = xattr_skipvalue,
1518*33b1fccfSAndroid Build Coastguard Worker 	.value = NULL
1519*33b1fccfSAndroid Build Coastguard Worker };
1520*33b1fccfSAndroid Build Coastguard Worker 
inline_listxattr(struct erofs_inode * vi,struct listxattr_iter * it)1521*33b1fccfSAndroid Build Coastguard Worker static int inline_listxattr(struct erofs_inode *vi, struct listxattr_iter *it)
1522*33b1fccfSAndroid Build Coastguard Worker {
1523*33b1fccfSAndroid Build Coastguard Worker 	int ret;
1524*33b1fccfSAndroid Build Coastguard Worker 	unsigned int remaining;
1525*33b1fccfSAndroid Build Coastguard Worker 
1526*33b1fccfSAndroid Build Coastguard Worker 	ret = inline_xattr_iter_pre(&it->it, vi);
1527*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
1528*33b1fccfSAndroid Build Coastguard Worker 		return ret;
1529*33b1fccfSAndroid Build Coastguard Worker 
1530*33b1fccfSAndroid Build Coastguard Worker 	remaining = ret;
1531*33b1fccfSAndroid Build Coastguard Worker 	while (remaining) {
1532*33b1fccfSAndroid Build Coastguard Worker 		ret = xattr_foreach(&it->it, &list_xattr_handlers, &remaining);
1533*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
1534*33b1fccfSAndroid Build Coastguard Worker 			break;
1535*33b1fccfSAndroid Build Coastguard Worker 	}
1536*33b1fccfSAndroid Build Coastguard Worker 
1537*33b1fccfSAndroid Build Coastguard Worker 	return ret ? ret : it->buffer_ofs;
1538*33b1fccfSAndroid Build Coastguard Worker }
1539*33b1fccfSAndroid Build Coastguard Worker 
shared_listxattr(struct erofs_inode * vi,struct listxattr_iter * it)1540*33b1fccfSAndroid Build Coastguard Worker static int shared_listxattr(struct erofs_inode *vi, struct listxattr_iter *it)
1541*33b1fccfSAndroid Build Coastguard Worker {
1542*33b1fccfSAndroid Build Coastguard Worker 	unsigned int i;
1543*33b1fccfSAndroid Build Coastguard Worker 	int ret = 0;
1544*33b1fccfSAndroid Build Coastguard Worker 
1545*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < vi->xattr_shared_count; ++i) {
1546*33b1fccfSAndroid Build Coastguard Worker 		erofs_blk_t blkaddr =
1547*33b1fccfSAndroid Build Coastguard Worker 			xattrblock_addr(vi, vi->xattr_shared_xattrs[i]);
1548*33b1fccfSAndroid Build Coastguard Worker 
1549*33b1fccfSAndroid Build Coastguard Worker 		it->it.ofs = xattrblock_offset(vi, vi->xattr_shared_xattrs[i]);
1550*33b1fccfSAndroid Build Coastguard Worker 		if (!i || blkaddr != it->it.blkaddr) {
1551*33b1fccfSAndroid Build Coastguard Worker 			ret = erofs_blk_read(vi->sbi, 0, it->it.page, blkaddr, 1);
1552*33b1fccfSAndroid Build Coastguard Worker 			if (ret < 0)
1553*33b1fccfSAndroid Build Coastguard Worker 				return -EIO;
1554*33b1fccfSAndroid Build Coastguard Worker 
1555*33b1fccfSAndroid Build Coastguard Worker 			it->it.kaddr = it->it.page;
1556*33b1fccfSAndroid Build Coastguard Worker 			it->it.blkaddr = blkaddr;
1557*33b1fccfSAndroid Build Coastguard Worker 		}
1558*33b1fccfSAndroid Build Coastguard Worker 
1559*33b1fccfSAndroid Build Coastguard Worker 		ret = xattr_foreach(&it->it, &list_xattr_handlers, NULL);
1560*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
1561*33b1fccfSAndroid Build Coastguard Worker 			break;
1562*33b1fccfSAndroid Build Coastguard Worker 	}
1563*33b1fccfSAndroid Build Coastguard Worker 
1564*33b1fccfSAndroid Build Coastguard Worker 	return ret ? ret : it->buffer_ofs;
1565*33b1fccfSAndroid Build Coastguard Worker }
1566*33b1fccfSAndroid Build Coastguard Worker 
erofs_listxattr(struct erofs_inode * vi,char * buffer,size_t buffer_size)1567*33b1fccfSAndroid Build Coastguard Worker int erofs_listxattr(struct erofs_inode *vi, char *buffer, size_t buffer_size)
1568*33b1fccfSAndroid Build Coastguard Worker {
1569*33b1fccfSAndroid Build Coastguard Worker 	int ret;
1570*33b1fccfSAndroid Build Coastguard Worker 	struct listxattr_iter it;
1571*33b1fccfSAndroid Build Coastguard Worker 
1572*33b1fccfSAndroid Build Coastguard Worker 	ret = init_inode_xattrs(vi);
1573*33b1fccfSAndroid Build Coastguard Worker 	if (ret == -ENOATTR)
1574*33b1fccfSAndroid Build Coastguard Worker 		return 0;
1575*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
1576*33b1fccfSAndroid Build Coastguard Worker 		return ret;
1577*33b1fccfSAndroid Build Coastguard Worker 
1578*33b1fccfSAndroid Build Coastguard Worker 	it.it.sbi = vi->sbi;
1579*33b1fccfSAndroid Build Coastguard Worker 	it.buffer = buffer;
1580*33b1fccfSAndroid Build Coastguard Worker 	it.buffer_size = buffer_size;
1581*33b1fccfSAndroid Build Coastguard Worker 	it.buffer_ofs = 0;
1582*33b1fccfSAndroid Build Coastguard Worker 
1583*33b1fccfSAndroid Build Coastguard Worker 	ret = inline_listxattr(vi, &it);
1584*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0 && ret != -ENOATTR)
1585*33b1fccfSAndroid Build Coastguard Worker 		return ret;
1586*33b1fccfSAndroid Build Coastguard Worker 	return shared_listxattr(vi, &it);
1587*33b1fccfSAndroid Build Coastguard Worker }
1588*33b1fccfSAndroid Build Coastguard Worker 
erofs_xattr_insert_name_prefix(const char * prefix)1589*33b1fccfSAndroid Build Coastguard Worker int erofs_xattr_insert_name_prefix(const char *prefix)
1590*33b1fccfSAndroid Build Coastguard Worker {
1591*33b1fccfSAndroid Build Coastguard Worker 	struct ea_type_node *tnode;
1592*33b1fccfSAndroid Build Coastguard Worker 
1593*33b1fccfSAndroid Build Coastguard Worker 	if (ea_prefix_count >= 0x80 || strlen(prefix) > UINT8_MAX)
1594*33b1fccfSAndroid Build Coastguard Worker 		return -EOVERFLOW;
1595*33b1fccfSAndroid Build Coastguard Worker 
1596*33b1fccfSAndroid Build Coastguard Worker 	tnode = calloc(1, sizeof(*tnode));
1597*33b1fccfSAndroid Build Coastguard Worker 	if (!tnode)
1598*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
1599*33b1fccfSAndroid Build Coastguard Worker 
1600*33b1fccfSAndroid Build Coastguard Worker 	if (!match_prefix(prefix, &tnode->base_index, &tnode->base_len)) {
1601*33b1fccfSAndroid Build Coastguard Worker 		free(tnode);
1602*33b1fccfSAndroid Build Coastguard Worker 		return -ENODATA;
1603*33b1fccfSAndroid Build Coastguard Worker 	}
1604*33b1fccfSAndroid Build Coastguard Worker 
1605*33b1fccfSAndroid Build Coastguard Worker 	tnode->type.prefix_len = strlen(prefix);
1606*33b1fccfSAndroid Build Coastguard Worker 	tnode->type.prefix = strdup(prefix);
1607*33b1fccfSAndroid Build Coastguard Worker 	if (!tnode->type.prefix) {
1608*33b1fccfSAndroid Build Coastguard Worker 		free(tnode);
1609*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
1610*33b1fccfSAndroid Build Coastguard Worker 	}
1611*33b1fccfSAndroid Build Coastguard Worker 
1612*33b1fccfSAndroid Build Coastguard Worker 	tnode->index = EROFS_XATTR_LONG_PREFIX | ea_prefix_count;
1613*33b1fccfSAndroid Build Coastguard Worker 	ea_prefix_count++;
1614*33b1fccfSAndroid Build Coastguard Worker 	init_list_head(&tnode->list);
1615*33b1fccfSAndroid Build Coastguard Worker 	list_add_tail(&tnode->list, &ea_name_prefixes);
1616*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1617*33b1fccfSAndroid Build Coastguard Worker }
1618*33b1fccfSAndroid Build Coastguard Worker 
erofs_xattr_cleanup_name_prefixes(void)1619*33b1fccfSAndroid Build Coastguard Worker void erofs_xattr_cleanup_name_prefixes(void)
1620*33b1fccfSAndroid Build Coastguard Worker {
1621*33b1fccfSAndroid Build Coastguard Worker 	struct ea_type_node *tnode, *n;
1622*33b1fccfSAndroid Build Coastguard Worker 
1623*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry_safe(tnode, n, &ea_name_prefixes, list) {
1624*33b1fccfSAndroid Build Coastguard Worker 		list_del(&tnode->list);
1625*33b1fccfSAndroid Build Coastguard Worker 		free((void *)tnode->type.prefix);
1626*33b1fccfSAndroid Build Coastguard Worker 		free(tnode);
1627*33b1fccfSAndroid Build Coastguard Worker 	}
1628*33b1fccfSAndroid Build Coastguard Worker }
1629*33b1fccfSAndroid Build Coastguard Worker 
erofs_xattr_prefixes_cleanup(struct erofs_sb_info * sbi)1630*33b1fccfSAndroid Build Coastguard Worker void erofs_xattr_prefixes_cleanup(struct erofs_sb_info *sbi)
1631*33b1fccfSAndroid Build Coastguard Worker {
1632*33b1fccfSAndroid Build Coastguard Worker 	int i;
1633*33b1fccfSAndroid Build Coastguard Worker 
1634*33b1fccfSAndroid Build Coastguard Worker 	if (sbi->xattr_prefixes) {
1635*33b1fccfSAndroid Build Coastguard Worker 		for (i = 0; i < sbi->xattr_prefix_count; i++)
1636*33b1fccfSAndroid Build Coastguard Worker 			free(sbi->xattr_prefixes[i].prefix);
1637*33b1fccfSAndroid Build Coastguard Worker 		free(sbi->xattr_prefixes);
1638*33b1fccfSAndroid Build Coastguard Worker 		sbi->xattr_prefixes = NULL;
1639*33b1fccfSAndroid Build Coastguard Worker 	}
1640*33b1fccfSAndroid Build Coastguard Worker }
1641*33b1fccfSAndroid Build Coastguard Worker 
erofs_xattr_prefixes_init(struct erofs_sb_info * sbi)1642*33b1fccfSAndroid Build Coastguard Worker int erofs_xattr_prefixes_init(struct erofs_sb_info *sbi)
1643*33b1fccfSAndroid Build Coastguard Worker {
1644*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t pos = (erofs_off_t)sbi->xattr_prefix_start << 2;
1645*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_xattr_prefix_item *pfs;
1646*33b1fccfSAndroid Build Coastguard Worker 	erofs_nid_t nid = 0;
1647*33b1fccfSAndroid Build Coastguard Worker 	int ret = 0, i, len;
1648*33b1fccfSAndroid Build Coastguard Worker 	void *buf;
1649*33b1fccfSAndroid Build Coastguard Worker 
1650*33b1fccfSAndroid Build Coastguard Worker 	if (!sbi->xattr_prefix_count)
1651*33b1fccfSAndroid Build Coastguard Worker 		return 0;
1652*33b1fccfSAndroid Build Coastguard Worker 
1653*33b1fccfSAndroid Build Coastguard Worker 	if (sbi->packed_nid)
1654*33b1fccfSAndroid Build Coastguard Worker 		nid = sbi->packed_nid;
1655*33b1fccfSAndroid Build Coastguard Worker 
1656*33b1fccfSAndroid Build Coastguard Worker 	pfs = calloc(sbi->xattr_prefix_count, sizeof(*pfs));
1657*33b1fccfSAndroid Build Coastguard Worker 	if (!pfs)
1658*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
1659*33b1fccfSAndroid Build Coastguard Worker 
1660*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < sbi->xattr_prefix_count; i++) {
1661*33b1fccfSAndroid Build Coastguard Worker 		buf = erofs_read_metadata(sbi, nid, &pos, &len);
1662*33b1fccfSAndroid Build Coastguard Worker 		if (IS_ERR(buf)) {
1663*33b1fccfSAndroid Build Coastguard Worker 			ret = PTR_ERR(buf);
1664*33b1fccfSAndroid Build Coastguard Worker 			goto out;
1665*33b1fccfSAndroid Build Coastguard Worker 		}
1666*33b1fccfSAndroid Build Coastguard Worker 		if (len < sizeof(*pfs->prefix) ||
1667*33b1fccfSAndroid Build Coastguard Worker 		    len > EROFS_NAME_LEN + sizeof(*pfs->prefix)) {
1668*33b1fccfSAndroid Build Coastguard Worker 			free(buf);
1669*33b1fccfSAndroid Build Coastguard Worker 			ret = -EFSCORRUPTED;
1670*33b1fccfSAndroid Build Coastguard Worker 			goto out;
1671*33b1fccfSAndroid Build Coastguard Worker 		}
1672*33b1fccfSAndroid Build Coastguard Worker 		pfs[i].prefix = buf;
1673*33b1fccfSAndroid Build Coastguard Worker 		pfs[i].infix_len = len - sizeof(struct erofs_xattr_long_prefix);
1674*33b1fccfSAndroid Build Coastguard Worker 	}
1675*33b1fccfSAndroid Build Coastguard Worker out:
1676*33b1fccfSAndroid Build Coastguard Worker 	sbi->xattr_prefixes = pfs;
1677*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
1678*33b1fccfSAndroid Build Coastguard Worker 		erofs_xattr_prefixes_cleanup(sbi);
1679*33b1fccfSAndroid Build Coastguard Worker 	return ret;
1680*33b1fccfSAndroid Build Coastguard Worker }
1681