xref: /aosp_15_r20/external/e2fsprogs/lib/ext2fs/ext_attr.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker  * ext_attr.c --- extended attribute blocks
3*6a54128fSAndroid Build Coastguard Worker  *
4*6a54128fSAndroid Build Coastguard Worker  * Copyright (C) 2001 Andreas Gruenbacher, <[email protected]>
5*6a54128fSAndroid Build Coastguard Worker  *
6*6a54128fSAndroid Build Coastguard Worker  * Copyright (C) 2002 Theodore Ts'o.
7*6a54128fSAndroid Build Coastguard Worker  *
8*6a54128fSAndroid Build Coastguard Worker  * %Begin-Header%
9*6a54128fSAndroid Build Coastguard Worker  * This file may be redistributed under the terms of the GNU Library
10*6a54128fSAndroid Build Coastguard Worker  * General Public License, version 2.
11*6a54128fSAndroid Build Coastguard Worker  * %End-Header%
12*6a54128fSAndroid Build Coastguard Worker  */
13*6a54128fSAndroid Build Coastguard Worker 
14*6a54128fSAndroid Build Coastguard Worker #include "config.h"
15*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
16*6a54128fSAndroid Build Coastguard Worker #if HAVE_UNISTD_H
17*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
18*6a54128fSAndroid Build Coastguard Worker #endif
19*6a54128fSAndroid Build Coastguard Worker #include <string.h>
20*6a54128fSAndroid Build Coastguard Worker #include <time.h>
21*6a54128fSAndroid Build Coastguard Worker 
22*6a54128fSAndroid Build Coastguard Worker #include "ext2_fs.h"
23*6a54128fSAndroid Build Coastguard Worker #include "ext2_ext_attr.h"
24*6a54128fSAndroid Build Coastguard Worker #include "ext4_acl.h"
25*6a54128fSAndroid Build Coastguard Worker 
26*6a54128fSAndroid Build Coastguard Worker #include "ext2fs.h"
27*6a54128fSAndroid Build Coastguard Worker 
read_ea_inode_hash(ext2_filsys fs,ext2_ino_t ino,__u32 * hash)28*6a54128fSAndroid Build Coastguard Worker static errcode_t read_ea_inode_hash(ext2_filsys fs, ext2_ino_t ino, __u32 *hash)
29*6a54128fSAndroid Build Coastguard Worker {
30*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode inode;
31*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval;
32*6a54128fSAndroid Build Coastguard Worker 
33*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_read_inode(fs, ino, &inode);
34*6a54128fSAndroid Build Coastguard Worker 	if (retval)
35*6a54128fSAndroid Build Coastguard Worker 		return retval;
36*6a54128fSAndroid Build Coastguard Worker 	*hash = ext2fs_get_ea_inode_hash(&inode);
37*6a54128fSAndroid Build Coastguard Worker 	return 0;
38*6a54128fSAndroid Build Coastguard Worker }
39*6a54128fSAndroid Build Coastguard Worker 
40*6a54128fSAndroid Build Coastguard Worker #define NAME_HASH_SHIFT 5
41*6a54128fSAndroid Build Coastguard Worker #define VALUE_HASH_SHIFT 16
42*6a54128fSAndroid Build Coastguard Worker 
43*6a54128fSAndroid Build Coastguard Worker /*
44*6a54128fSAndroid Build Coastguard Worker  * ext2_xattr_hash_entry()
45*6a54128fSAndroid Build Coastguard Worker  *
46*6a54128fSAndroid Build Coastguard Worker  * Compute the hash of an extended attribute.
47*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry * entry,void * data)48*6a54128fSAndroid Build Coastguard Worker __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
49*6a54128fSAndroid Build Coastguard Worker {
50*6a54128fSAndroid Build Coastguard Worker 	__u32 hash = 0;
51*6a54128fSAndroid Build Coastguard Worker 	unsigned char *name = (((unsigned char *) entry) +
52*6a54128fSAndroid Build Coastguard Worker 			       sizeof(struct ext2_ext_attr_entry));
53*6a54128fSAndroid Build Coastguard Worker 	int n;
54*6a54128fSAndroid Build Coastguard Worker 
55*6a54128fSAndroid Build Coastguard Worker 	for (n = 0; n < entry->e_name_len; n++) {
56*6a54128fSAndroid Build Coastguard Worker 		hash = (hash << NAME_HASH_SHIFT) ^
57*6a54128fSAndroid Build Coastguard Worker 		       (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
58*6a54128fSAndroid Build Coastguard Worker 		       *name++;
59*6a54128fSAndroid Build Coastguard Worker 	}
60*6a54128fSAndroid Build Coastguard Worker 
61*6a54128fSAndroid Build Coastguard Worker 	/* The hash needs to be calculated on the data in little-endian. */
62*6a54128fSAndroid Build Coastguard Worker 	if (entry->e_value_inum == 0 && entry->e_value_size != 0) {
63*6a54128fSAndroid Build Coastguard Worker 		__u32 *value = (__u32 *)data;
64*6a54128fSAndroid Build Coastguard Worker 		for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >>
65*6a54128fSAndroid Build Coastguard Worker 			 EXT2_EXT_ATTR_PAD_BITS; n; n--) {
66*6a54128fSAndroid Build Coastguard Worker 			hash = (hash << VALUE_HASH_SHIFT) ^
67*6a54128fSAndroid Build Coastguard Worker 			       (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
68*6a54128fSAndroid Build Coastguard Worker 			       ext2fs_le32_to_cpu(*value++);
69*6a54128fSAndroid Build Coastguard Worker 		}
70*6a54128fSAndroid Build Coastguard Worker 	}
71*6a54128fSAndroid Build Coastguard Worker 
72*6a54128fSAndroid Build Coastguard Worker 	return hash;
73*6a54128fSAndroid Build Coastguard Worker }
74*6a54128fSAndroid Build Coastguard Worker 
ext2fs_ext_attr_hash_entry_signed(struct ext2_ext_attr_entry * entry,void * data)75*6a54128fSAndroid Build Coastguard Worker __u32 ext2fs_ext_attr_hash_entry_signed(struct ext2_ext_attr_entry *entry,
76*6a54128fSAndroid Build Coastguard Worker 					void *data)
77*6a54128fSAndroid Build Coastguard Worker {
78*6a54128fSAndroid Build Coastguard Worker 	__u32 hash = 0;
79*6a54128fSAndroid Build Coastguard Worker 	signed char *name = (((signed char *) entry) +
80*6a54128fSAndroid Build Coastguard Worker 			     sizeof(struct ext2_ext_attr_entry));
81*6a54128fSAndroid Build Coastguard Worker 	int n;
82*6a54128fSAndroid Build Coastguard Worker 
83*6a54128fSAndroid Build Coastguard Worker 	for (n = 0; n < entry->e_name_len; n++) {
84*6a54128fSAndroid Build Coastguard Worker 		hash = (hash << NAME_HASH_SHIFT) ^
85*6a54128fSAndroid Build Coastguard Worker 		       (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
86*6a54128fSAndroid Build Coastguard Worker 		       *name++;
87*6a54128fSAndroid Build Coastguard Worker 	}
88*6a54128fSAndroid Build Coastguard Worker 
89*6a54128fSAndroid Build Coastguard Worker 	/* The hash needs to be calculated on the data in little-endian. */
90*6a54128fSAndroid Build Coastguard Worker 	if (entry->e_value_inum == 0 && entry->e_value_size != 0) {
91*6a54128fSAndroid Build Coastguard Worker 		__u32 *value = (__u32 *)data;
92*6a54128fSAndroid Build Coastguard Worker 		for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >>
93*6a54128fSAndroid Build Coastguard Worker 			 EXT2_EXT_ATTR_PAD_BITS; n; n--) {
94*6a54128fSAndroid Build Coastguard Worker 			hash = (hash << VALUE_HASH_SHIFT) ^
95*6a54128fSAndroid Build Coastguard Worker 			       (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
96*6a54128fSAndroid Build Coastguard Worker 			       ext2fs_le32_to_cpu(*value++);
97*6a54128fSAndroid Build Coastguard Worker 		}
98*6a54128fSAndroid Build Coastguard Worker 	}
99*6a54128fSAndroid Build Coastguard Worker 
100*6a54128fSAndroid Build Coastguard Worker 	return hash;
101*6a54128fSAndroid Build Coastguard Worker }
102*6a54128fSAndroid Build Coastguard Worker 
103*6a54128fSAndroid Build Coastguard Worker 
104*6a54128fSAndroid Build Coastguard Worker /*
105*6a54128fSAndroid Build Coastguard Worker  * ext2fs_ext_attr_hash_entry3()
106*6a54128fSAndroid Build Coastguard Worker  *
107*6a54128fSAndroid Build Coastguard Worker  * Compute the hash of an extended attribute.  This version of the
108*6a54128fSAndroid Build Coastguard Worker  * function supports hashing entries that reference external inodes
109*6a54128fSAndroid Build Coastguard Worker  * (ea_inode feature) as well as calculating the old legacy signed
110*6a54128fSAndroid Build Coastguard Worker  * hash variant.
111*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_ext_attr_hash_entry3(ext2_filsys fs,struct ext2_ext_attr_entry * entry,void * data,__u32 * hash,__u32 * signed_hash)112*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_ext_attr_hash_entry3(ext2_filsys fs,
113*6a54128fSAndroid Build Coastguard Worker 				      struct ext2_ext_attr_entry *entry,
114*6a54128fSAndroid Build Coastguard Worker 				      void *data, __u32 *hash,
115*6a54128fSAndroid Build Coastguard Worker 				      __u32 *signed_hash)
116*6a54128fSAndroid Build Coastguard Worker {
117*6a54128fSAndroid Build Coastguard Worker 	*hash = ext2fs_ext_attr_hash_entry(entry, data);
118*6a54128fSAndroid Build Coastguard Worker 	if (signed_hash)
119*6a54128fSAndroid Build Coastguard Worker 		*signed_hash = ext2fs_ext_attr_hash_entry_signed(entry, data);
120*6a54128fSAndroid Build Coastguard Worker 
121*6a54128fSAndroid Build Coastguard Worker 	if (entry->e_value_inum) {
122*6a54128fSAndroid Build Coastguard Worker 		__u32 ea_inode_hash;
123*6a54128fSAndroid Build Coastguard Worker 		errcode_t retval;
124*6a54128fSAndroid Build Coastguard Worker 
125*6a54128fSAndroid Build Coastguard Worker 		retval = read_ea_inode_hash(fs, entry->e_value_inum,
126*6a54128fSAndroid Build Coastguard Worker 					    &ea_inode_hash);
127*6a54128fSAndroid Build Coastguard Worker 		if (retval)
128*6a54128fSAndroid Build Coastguard Worker 			return retval;
129*6a54128fSAndroid Build Coastguard Worker 
130*6a54128fSAndroid Build Coastguard Worker 		*hash = (*hash << VALUE_HASH_SHIFT) ^
131*6a54128fSAndroid Build Coastguard Worker 			(*hash >> (8*sizeof(*hash) - VALUE_HASH_SHIFT)) ^
132*6a54128fSAndroid Build Coastguard Worker 			ea_inode_hash;
133*6a54128fSAndroid Build Coastguard Worker 		if (signed_hash)
134*6a54128fSAndroid Build Coastguard Worker 			*signed_hash = (*signed_hash << VALUE_HASH_SHIFT) ^
135*6a54128fSAndroid Build Coastguard Worker 				(*signed_hash >> (8*sizeof(*hash) -
136*6a54128fSAndroid Build Coastguard Worker 						  VALUE_HASH_SHIFT)) ^
137*6a54128fSAndroid Build Coastguard Worker 				ea_inode_hash;
138*6a54128fSAndroid Build Coastguard Worker 	}
139*6a54128fSAndroid Build Coastguard Worker 	return 0;
140*6a54128fSAndroid Build Coastguard Worker }
141*6a54128fSAndroid Build Coastguard Worker 
142*6a54128fSAndroid Build Coastguard Worker /*
143*6a54128fSAndroid Build Coastguard Worker  * ext2fs_ext_attr_hash_entry2()
144*6a54128fSAndroid Build Coastguard Worker  *
145*6a54128fSAndroid Build Coastguard Worker  * Compute the hash of an extended attribute.
146*6a54128fSAndroid Build Coastguard Worker  * This version of the function supports hashing entries that reference
147*6a54128fSAndroid Build Coastguard Worker  * external inodes (ea_inode feature).
148*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_ext_attr_hash_entry2(ext2_filsys fs,struct ext2_ext_attr_entry * entry,void * data,__u32 * hash)149*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_ext_attr_hash_entry2(ext2_filsys fs,
150*6a54128fSAndroid Build Coastguard Worker 				      struct ext2_ext_attr_entry *entry,
151*6a54128fSAndroid Build Coastguard Worker 				      void *data, __u32 *hash)
152*6a54128fSAndroid Build Coastguard Worker {
153*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_ext_attr_hash_entry3(fs, entry, data, hash, NULL);
154*6a54128fSAndroid Build Coastguard Worker }
155*6a54128fSAndroid Build Coastguard Worker 
156*6a54128fSAndroid Build Coastguard Worker #undef NAME_HASH_SHIFT
157*6a54128fSAndroid Build Coastguard Worker #undef VALUE_HASH_SHIFT
158*6a54128fSAndroid Build Coastguard Worker 
159*6a54128fSAndroid Build Coastguard Worker #define BLOCK_HASH_SHIFT 16
160*6a54128fSAndroid Build Coastguard Worker 
161*6a54128fSAndroid Build Coastguard Worker /* Mirrors ext4_xattr_rehash() implementation in kernel. */
ext2fs_ext_attr_block_rehash(struct ext2_ext_attr_header * header,struct ext2_ext_attr_entry * end)162*6a54128fSAndroid Build Coastguard Worker void ext2fs_ext_attr_block_rehash(struct ext2_ext_attr_header *header,
163*6a54128fSAndroid Build Coastguard Worker 				  struct ext2_ext_attr_entry *end)
164*6a54128fSAndroid Build Coastguard Worker {
165*6a54128fSAndroid Build Coastguard Worker 	struct ext2_ext_attr_entry *here;
166*6a54128fSAndroid Build Coastguard Worker 	__u32 hash = 0;
167*6a54128fSAndroid Build Coastguard Worker 
168*6a54128fSAndroid Build Coastguard Worker 	here = (struct ext2_ext_attr_entry *)(header+1);
169*6a54128fSAndroid Build Coastguard Worker 	while (here < end && !EXT2_EXT_IS_LAST_ENTRY(here)) {
170*6a54128fSAndroid Build Coastguard Worker 		if (!here->e_hash) {
171*6a54128fSAndroid Build Coastguard Worker 			/* Block is not shared if an entry's hash value == 0 */
172*6a54128fSAndroid Build Coastguard Worker 			hash = 0;
173*6a54128fSAndroid Build Coastguard Worker 			break;
174*6a54128fSAndroid Build Coastguard Worker 		}
175*6a54128fSAndroid Build Coastguard Worker 		hash = (hash << BLOCK_HASH_SHIFT) ^
176*6a54128fSAndroid Build Coastguard Worker 		       (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^
177*6a54128fSAndroid Build Coastguard Worker 		       here->e_hash;
178*6a54128fSAndroid Build Coastguard Worker 		here = EXT2_EXT_ATTR_NEXT(here);
179*6a54128fSAndroid Build Coastguard Worker 	}
180*6a54128fSAndroid Build Coastguard Worker 	header->h_hash = hash;
181*6a54128fSAndroid Build Coastguard Worker }
182*6a54128fSAndroid Build Coastguard Worker 
183*6a54128fSAndroid Build Coastguard Worker #undef BLOCK_HASH_SHIFT
184*6a54128fSAndroid Build Coastguard Worker 
ext2fs_get_ea_inode_hash(struct ext2_inode * inode)185*6a54128fSAndroid Build Coastguard Worker __u32 ext2fs_get_ea_inode_hash(struct ext2_inode *inode)
186*6a54128fSAndroid Build Coastguard Worker {
187*6a54128fSAndroid Build Coastguard Worker 	return inode->i_atime;
188*6a54128fSAndroid Build Coastguard Worker }
189*6a54128fSAndroid Build Coastguard Worker 
ext2fs_set_ea_inode_hash(struct ext2_inode * inode,__u32 hash)190*6a54128fSAndroid Build Coastguard Worker void ext2fs_set_ea_inode_hash(struct ext2_inode *inode, __u32 hash)
191*6a54128fSAndroid Build Coastguard Worker {
192*6a54128fSAndroid Build Coastguard Worker 	inode->i_atime = hash;
193*6a54128fSAndroid Build Coastguard Worker }
194*6a54128fSAndroid Build Coastguard Worker 
ext2fs_get_ea_inode_ref(struct ext2_inode * inode)195*6a54128fSAndroid Build Coastguard Worker __u64 ext2fs_get_ea_inode_ref(struct ext2_inode *inode)
196*6a54128fSAndroid Build Coastguard Worker {
197*6a54128fSAndroid Build Coastguard Worker 	return ((__u64)inode->i_ctime << 32) | inode->osd1.linux1.l_i_version;
198*6a54128fSAndroid Build Coastguard Worker }
199*6a54128fSAndroid Build Coastguard Worker 
ext2fs_set_ea_inode_ref(struct ext2_inode * inode,__u64 ref_count)200*6a54128fSAndroid Build Coastguard Worker void ext2fs_set_ea_inode_ref(struct ext2_inode *inode, __u64 ref_count)
201*6a54128fSAndroid Build Coastguard Worker {
202*6a54128fSAndroid Build Coastguard Worker 	inode->i_ctime = (__u32)(ref_count >> 32);
203*6a54128fSAndroid Build Coastguard Worker 	inode->osd1.linux1.l_i_version = (__u32)ref_count;
204*6a54128fSAndroid Build Coastguard Worker }
205*6a54128fSAndroid Build Coastguard Worker 
check_ext_attr_header(struct ext2_ext_attr_header * header)206*6a54128fSAndroid Build Coastguard Worker static errcode_t check_ext_attr_header(struct ext2_ext_attr_header *header)
207*6a54128fSAndroid Build Coastguard Worker {
208*6a54128fSAndroid Build Coastguard Worker 	if ((header->h_magic != EXT2_EXT_ATTR_MAGIC_v1 &&
209*6a54128fSAndroid Build Coastguard Worker 	     header->h_magic != EXT2_EXT_ATTR_MAGIC) ||
210*6a54128fSAndroid Build Coastguard Worker 	    header->h_blocks != 1)
211*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_BAD_EA_HEADER;
212*6a54128fSAndroid Build Coastguard Worker 
213*6a54128fSAndroid Build Coastguard Worker 	return 0;
214*6a54128fSAndroid Build Coastguard Worker }
215*6a54128fSAndroid Build Coastguard Worker 
ext2fs_read_ext_attr3(ext2_filsys fs,blk64_t block,void * buf,ext2_ino_t inum)216*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_read_ext_attr3(ext2_filsys fs, blk64_t block, void *buf,
217*6a54128fSAndroid Build Coastguard Worker 				ext2_ino_t inum)
218*6a54128fSAndroid Build Coastguard Worker {
219*6a54128fSAndroid Build Coastguard Worker 	int		csum_failed = 0;
220*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
221*6a54128fSAndroid Build Coastguard Worker 
222*6a54128fSAndroid Build Coastguard Worker 	retval = io_channel_read_blk64(fs->io, block, 1, buf);
223*6a54128fSAndroid Build Coastguard Worker 	if (retval)
224*6a54128fSAndroid Build Coastguard Worker 		return retval;
225*6a54128fSAndroid Build Coastguard Worker 
226*6a54128fSAndroid Build Coastguard Worker 	if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
227*6a54128fSAndroid Build Coastguard Worker 	    !ext2fs_ext_attr_block_csum_verify(fs, inum, block, buf))
228*6a54128fSAndroid Build Coastguard Worker 		csum_failed = 1;
229*6a54128fSAndroid Build Coastguard Worker 
230*6a54128fSAndroid Build Coastguard Worker #ifdef WORDS_BIGENDIAN
231*6a54128fSAndroid Build Coastguard Worker 	ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
232*6a54128fSAndroid Build Coastguard Worker #endif
233*6a54128fSAndroid Build Coastguard Worker 
234*6a54128fSAndroid Build Coastguard Worker 	retval = check_ext_attr_header(buf);
235*6a54128fSAndroid Build Coastguard Worker 	if (retval == 0 && csum_failed)
236*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_EXT_ATTR_CSUM_INVALID;
237*6a54128fSAndroid Build Coastguard Worker 
238*6a54128fSAndroid Build Coastguard Worker 	return retval;
239*6a54128fSAndroid Build Coastguard Worker }
240*6a54128fSAndroid Build Coastguard Worker 
ext2fs_read_ext_attr2(ext2_filsys fs,blk64_t block,void * buf)241*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, void *buf)
242*6a54128fSAndroid Build Coastguard Worker {
243*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_read_ext_attr3(fs, block, buf, 0);
244*6a54128fSAndroid Build Coastguard Worker }
245*6a54128fSAndroid Build Coastguard Worker 
ext2fs_read_ext_attr(ext2_filsys fs,blk_t block,void * buf)246*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
247*6a54128fSAndroid Build Coastguard Worker {
248*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_read_ext_attr2(fs, block, buf);
249*6a54128fSAndroid Build Coastguard Worker }
250*6a54128fSAndroid Build Coastguard Worker 
ext2fs_write_ext_attr3(ext2_filsys fs,blk64_t block,void * inbuf,ext2_ino_t inum)251*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_write_ext_attr3(ext2_filsys fs, blk64_t block, void *inbuf,
252*6a54128fSAndroid Build Coastguard Worker 				 ext2_ino_t inum)
253*6a54128fSAndroid Build Coastguard Worker {
254*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
255*6a54128fSAndroid Build Coastguard Worker 	char		*write_buf;
256*6a54128fSAndroid Build Coastguard Worker 
257*6a54128fSAndroid Build Coastguard Worker #ifdef WORDS_BIGENDIAN
258*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_get_mem(fs->blocksize, &write_buf);
259*6a54128fSAndroid Build Coastguard Worker 	if (retval)
260*6a54128fSAndroid Build Coastguard Worker 		return retval;
261*6a54128fSAndroid Build Coastguard Worker 	ext2fs_swap_ext_attr(write_buf, inbuf, fs->blocksize, 1);
262*6a54128fSAndroid Build Coastguard Worker #else
263*6a54128fSAndroid Build Coastguard Worker 	write_buf = (char *) inbuf;
264*6a54128fSAndroid Build Coastguard Worker #endif
265*6a54128fSAndroid Build Coastguard Worker 
266*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_ext_attr_block_csum_set(fs, inum, block,
267*6a54128fSAndroid Build Coastguard Worker 			(struct ext2_ext_attr_header *)write_buf);
268*6a54128fSAndroid Build Coastguard Worker 	if (retval)
269*6a54128fSAndroid Build Coastguard Worker 		return retval;
270*6a54128fSAndroid Build Coastguard Worker 
271*6a54128fSAndroid Build Coastguard Worker 	retval = io_channel_write_blk64(fs->io, block, 1, write_buf);
272*6a54128fSAndroid Build Coastguard Worker #ifdef WORDS_BIGENDIAN
273*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&write_buf);
274*6a54128fSAndroid Build Coastguard Worker #endif
275*6a54128fSAndroid Build Coastguard Worker 	if (!retval)
276*6a54128fSAndroid Build Coastguard Worker 		ext2fs_mark_changed(fs);
277*6a54128fSAndroid Build Coastguard Worker 	return retval;
278*6a54128fSAndroid Build Coastguard Worker }
279*6a54128fSAndroid Build Coastguard Worker 
ext2fs_write_ext_attr2(ext2_filsys fs,blk64_t block,void * inbuf)280*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, void *inbuf)
281*6a54128fSAndroid Build Coastguard Worker {
282*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_write_ext_attr3(fs, block, inbuf, 0);
283*6a54128fSAndroid Build Coastguard Worker }
284*6a54128fSAndroid Build Coastguard Worker 
ext2fs_write_ext_attr(ext2_filsys fs,blk_t block,void * inbuf)285*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
286*6a54128fSAndroid Build Coastguard Worker {
287*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_write_ext_attr2(fs, block, inbuf);
288*6a54128fSAndroid Build Coastguard Worker }
289*6a54128fSAndroid Build Coastguard Worker 
290*6a54128fSAndroid Build Coastguard Worker /*
291*6a54128fSAndroid Build Coastguard Worker  * This function adjusts the reference count of the EA block.
292*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_adjust_ea_refcount3(ext2_filsys fs,blk64_t blk,char * block_buf,int adjust,__u32 * newcount,ext2_ino_t inum)293*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk,
294*6a54128fSAndroid Build Coastguard Worker 				    char *block_buf, int adjust,
295*6a54128fSAndroid Build Coastguard Worker 				    __u32 *newcount, ext2_ino_t inum)
296*6a54128fSAndroid Build Coastguard Worker {
297*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
298*6a54128fSAndroid Build Coastguard Worker 	struct ext2_ext_attr_header *header;
299*6a54128fSAndroid Build Coastguard Worker 	char	*buf = 0;
300*6a54128fSAndroid Build Coastguard Worker 
301*6a54128fSAndroid Build Coastguard Worker 	if ((blk >= ext2fs_blocks_count(fs->super)) ||
302*6a54128fSAndroid Build Coastguard Worker 	    (blk < fs->super->s_first_data_block))
303*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_BAD_EA_BLOCK_NUM;
304*6a54128fSAndroid Build Coastguard Worker 
305*6a54128fSAndroid Build Coastguard Worker 	if (!block_buf) {
306*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_get_mem(fs->blocksize, &buf);
307*6a54128fSAndroid Build Coastguard Worker 		if (retval)
308*6a54128fSAndroid Build Coastguard Worker 			return retval;
309*6a54128fSAndroid Build Coastguard Worker 		block_buf = buf;
310*6a54128fSAndroid Build Coastguard Worker 	}
311*6a54128fSAndroid Build Coastguard Worker 
312*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_read_ext_attr3(fs, blk, block_buf, inum);
313*6a54128fSAndroid Build Coastguard Worker 	if (retval)
314*6a54128fSAndroid Build Coastguard Worker 		goto errout;
315*6a54128fSAndroid Build Coastguard Worker 
316*6a54128fSAndroid Build Coastguard Worker 	header = (struct ext2_ext_attr_header *) block_buf;
317*6a54128fSAndroid Build Coastguard Worker 	header->h_refcount += adjust;
318*6a54128fSAndroid Build Coastguard Worker 	if (newcount)
319*6a54128fSAndroid Build Coastguard Worker 		*newcount = header->h_refcount;
320*6a54128fSAndroid Build Coastguard Worker 
321*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_write_ext_attr3(fs, blk, block_buf, inum);
322*6a54128fSAndroid Build Coastguard Worker 	if (retval)
323*6a54128fSAndroid Build Coastguard Worker 		goto errout;
324*6a54128fSAndroid Build Coastguard Worker 
325*6a54128fSAndroid Build Coastguard Worker errout:
326*6a54128fSAndroid Build Coastguard Worker 	if (buf)
327*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&buf);
328*6a54128fSAndroid Build Coastguard Worker 	return retval;
329*6a54128fSAndroid Build Coastguard Worker }
330*6a54128fSAndroid Build Coastguard Worker 
ext2fs_adjust_ea_refcount2(ext2_filsys fs,blk64_t blk,char * block_buf,int adjust,__u32 * newcount)331*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
332*6a54128fSAndroid Build Coastguard Worker 				    char *block_buf, int adjust,
333*6a54128fSAndroid Build Coastguard Worker 				    __u32 *newcount)
334*6a54128fSAndroid Build Coastguard Worker {
335*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_adjust_ea_refcount3(fs, blk, block_buf, adjust,
336*6a54128fSAndroid Build Coastguard Worker 					  newcount, 0);
337*6a54128fSAndroid Build Coastguard Worker }
338*6a54128fSAndroid Build Coastguard Worker 
ext2fs_adjust_ea_refcount(ext2_filsys fs,blk_t blk,char * block_buf,int adjust,__u32 * newcount)339*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
340*6a54128fSAndroid Build Coastguard Worker 					char *block_buf, int adjust,
341*6a54128fSAndroid Build Coastguard Worker 					__u32 *newcount)
342*6a54128fSAndroid Build Coastguard Worker {
343*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
344*6a54128fSAndroid Build Coastguard Worker 					  newcount);
345*6a54128fSAndroid Build Coastguard Worker }
346*6a54128fSAndroid Build Coastguard Worker 
347*6a54128fSAndroid Build Coastguard Worker /* Manipulate the contents of extended attribute regions */
348*6a54128fSAndroid Build Coastguard Worker struct ext2_xattr {
349*6a54128fSAndroid Build Coastguard Worker 	int name_index;
350*6a54128fSAndroid Build Coastguard Worker 	char *name;
351*6a54128fSAndroid Build Coastguard Worker 	char *short_name;
352*6a54128fSAndroid Build Coastguard Worker 	void *value;
353*6a54128fSAndroid Build Coastguard Worker 	unsigned int value_len;
354*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t ea_ino;
355*6a54128fSAndroid Build Coastguard Worker };
356*6a54128fSAndroid Build Coastguard Worker 
357*6a54128fSAndroid Build Coastguard Worker struct ext2_xattr_handle {
358*6a54128fSAndroid Build Coastguard Worker 	errcode_t magic;
359*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys fs;
360*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *attrs;
361*6a54128fSAndroid Build Coastguard Worker 	int capacity;
362*6a54128fSAndroid Build Coastguard Worker 	int count;
363*6a54128fSAndroid Build Coastguard Worker 	int ibody_count;
364*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t ino;
365*6a54128fSAndroid Build Coastguard Worker 	unsigned int flags;
366*6a54128fSAndroid Build Coastguard Worker };
367*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattrs_expand(struct ext2_xattr_handle * h,unsigned int expandby)368*6a54128fSAndroid Build Coastguard Worker static errcode_t ext2fs_xattrs_expand(struct ext2_xattr_handle *h,
369*6a54128fSAndroid Build Coastguard Worker 				      unsigned int expandby)
370*6a54128fSAndroid Build Coastguard Worker {
371*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *new_attrs;
372*6a54128fSAndroid Build Coastguard Worker 	errcode_t err;
373*6a54128fSAndroid Build Coastguard Worker 
374*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_get_arrayzero(h->capacity + expandby,
375*6a54128fSAndroid Build Coastguard Worker 				   sizeof(struct ext2_xattr), &new_attrs);
376*6a54128fSAndroid Build Coastguard Worker 	if (err)
377*6a54128fSAndroid Build Coastguard Worker 		return err;
378*6a54128fSAndroid Build Coastguard Worker 
379*6a54128fSAndroid Build Coastguard Worker 	memcpy(new_attrs, h->attrs, h->capacity * sizeof(struct ext2_xattr));
380*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&h->attrs);
381*6a54128fSAndroid Build Coastguard Worker 	h->capacity += expandby;
382*6a54128fSAndroid Build Coastguard Worker 	h->attrs = new_attrs;
383*6a54128fSAndroid Build Coastguard Worker 
384*6a54128fSAndroid Build Coastguard Worker 	return 0;
385*6a54128fSAndroid Build Coastguard Worker }
386*6a54128fSAndroid Build Coastguard Worker 
387*6a54128fSAndroid Build Coastguard Worker struct ea_name_index {
388*6a54128fSAndroid Build Coastguard Worker 	int index;
389*6a54128fSAndroid Build Coastguard Worker 	const char *name;
390*6a54128fSAndroid Build Coastguard Worker };
391*6a54128fSAndroid Build Coastguard Worker 
392*6a54128fSAndroid Build Coastguard Worker /* Keep these names sorted in order of decreasing specificity. */
393*6a54128fSAndroid Build Coastguard Worker static struct ea_name_index ea_names[] = {
394*6a54128fSAndroid Build Coastguard Worker 	{10, "gnu."},
395*6a54128fSAndroid Build Coastguard Worker 	{3, "system.posix_acl_default"},
396*6a54128fSAndroid Build Coastguard Worker 	{2, "system.posix_acl_access"},
397*6a54128fSAndroid Build Coastguard Worker 	{8, "system.richacl"},
398*6a54128fSAndroid Build Coastguard Worker 	{6, "security."},
399*6a54128fSAndroid Build Coastguard Worker 	{4, "trusted."},
400*6a54128fSAndroid Build Coastguard Worker 	{7, "system."},
401*6a54128fSAndroid Build Coastguard Worker 	{1, "user."},
402*6a54128fSAndroid Build Coastguard Worker 	{0, NULL},
403*6a54128fSAndroid Build Coastguard Worker };
404*6a54128fSAndroid Build Coastguard Worker 
find_ea_prefix(int index)405*6a54128fSAndroid Build Coastguard Worker static const char *find_ea_prefix(int index)
406*6a54128fSAndroid Build Coastguard Worker {
407*6a54128fSAndroid Build Coastguard Worker 	struct ea_name_index *e;
408*6a54128fSAndroid Build Coastguard Worker 
409*6a54128fSAndroid Build Coastguard Worker 	for (e = ea_names; e->name; e++)
410*6a54128fSAndroid Build Coastguard Worker 		if (e->index == index)
411*6a54128fSAndroid Build Coastguard Worker 			return e->name;
412*6a54128fSAndroid Build Coastguard Worker 
413*6a54128fSAndroid Build Coastguard Worker 	return NULL;
414*6a54128fSAndroid Build Coastguard Worker }
415*6a54128fSAndroid Build Coastguard Worker 
find_ea_index(const char * fullname,const char ** name,int * index)416*6a54128fSAndroid Build Coastguard Worker static int find_ea_index(const char *fullname, const char **name, int *index)
417*6a54128fSAndroid Build Coastguard Worker {
418*6a54128fSAndroid Build Coastguard Worker 	struct ea_name_index *e;
419*6a54128fSAndroid Build Coastguard Worker 
420*6a54128fSAndroid Build Coastguard Worker 	for (e = ea_names; e->name; e++) {
421*6a54128fSAndroid Build Coastguard Worker 		if (strncmp(fullname, e->name, strlen(e->name)) == 0) {
422*6a54128fSAndroid Build Coastguard Worker 			*name = fullname + strlen(e->name);
423*6a54128fSAndroid Build Coastguard Worker 			*index = e->index;
424*6a54128fSAndroid Build Coastguard Worker 			return 1;
425*6a54128fSAndroid Build Coastguard Worker 		}
426*6a54128fSAndroid Build Coastguard Worker 	}
427*6a54128fSAndroid Build Coastguard Worker 	return 0;
428*6a54128fSAndroid Build Coastguard Worker }
429*6a54128fSAndroid Build Coastguard Worker 
ext2fs_free_ext_attr(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode_large * inode)430*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino,
431*6a54128fSAndroid Build Coastguard Worker 			       struct ext2_inode_large *inode)
432*6a54128fSAndroid Build Coastguard Worker {
433*6a54128fSAndroid Build Coastguard Worker 	struct ext2_ext_attr_header *header;
434*6a54128fSAndroid Build Coastguard Worker 	void *block_buf = NULL;
435*6a54128fSAndroid Build Coastguard Worker 	blk64_t blk;
436*6a54128fSAndroid Build Coastguard Worker 	errcode_t err;
437*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode_large i;
438*6a54128fSAndroid Build Coastguard Worker 
439*6a54128fSAndroid Build Coastguard Worker 	/* Read inode? */
440*6a54128fSAndroid Build Coastguard Worker 	if (inode == NULL) {
441*6a54128fSAndroid Build Coastguard Worker 		err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&i,
442*6a54128fSAndroid Build Coastguard Worker 					     sizeof(struct ext2_inode_large));
443*6a54128fSAndroid Build Coastguard Worker 		if (err)
444*6a54128fSAndroid Build Coastguard Worker 			return err;
445*6a54128fSAndroid Build Coastguard Worker 		inode = &i;
446*6a54128fSAndroid Build Coastguard Worker 	}
447*6a54128fSAndroid Build Coastguard Worker 
448*6a54128fSAndroid Build Coastguard Worker 	/* Do we already have an EA block? */
449*6a54128fSAndroid Build Coastguard Worker 	blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
450*6a54128fSAndroid Build Coastguard Worker 	if (blk == 0)
451*6a54128fSAndroid Build Coastguard Worker 		return 0;
452*6a54128fSAndroid Build Coastguard Worker 
453*6a54128fSAndroid Build Coastguard Worker 	/* Find block, zero it, write back */
454*6a54128fSAndroid Build Coastguard Worker 	if ((blk < fs->super->s_first_data_block) ||
455*6a54128fSAndroid Build Coastguard Worker 	    (blk >= ext2fs_blocks_count(fs->super))) {
456*6a54128fSAndroid Build Coastguard Worker 		err = EXT2_ET_BAD_EA_BLOCK_NUM;
457*6a54128fSAndroid Build Coastguard Worker 		goto out;
458*6a54128fSAndroid Build Coastguard Worker 	}
459*6a54128fSAndroid Build Coastguard Worker 
460*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_get_mem(fs->blocksize, &block_buf);
461*6a54128fSAndroid Build Coastguard Worker 	if (err)
462*6a54128fSAndroid Build Coastguard Worker 		goto out;
463*6a54128fSAndroid Build Coastguard Worker 
464*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino);
465*6a54128fSAndroid Build Coastguard Worker 	if (err)
466*6a54128fSAndroid Build Coastguard Worker 		goto out2;
467*6a54128fSAndroid Build Coastguard Worker 
468*6a54128fSAndroid Build Coastguard Worker 	/* We only know how to deal with v2 EA blocks */
469*6a54128fSAndroid Build Coastguard Worker 	header = (struct ext2_ext_attr_header *) block_buf;
470*6a54128fSAndroid Build Coastguard Worker 	if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
471*6a54128fSAndroid Build Coastguard Worker 		err = EXT2_ET_BAD_EA_HEADER;
472*6a54128fSAndroid Build Coastguard Worker 		goto out2;
473*6a54128fSAndroid Build Coastguard Worker 	}
474*6a54128fSAndroid Build Coastguard Worker 
475*6a54128fSAndroid Build Coastguard Worker 	header->h_refcount--;
476*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino);
477*6a54128fSAndroid Build Coastguard Worker 	if (err)
478*6a54128fSAndroid Build Coastguard Worker 		goto out2;
479*6a54128fSAndroid Build Coastguard Worker 
480*6a54128fSAndroid Build Coastguard Worker 	/* Erase link to block */
481*6a54128fSAndroid Build Coastguard Worker 	ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, 0);
482*6a54128fSAndroid Build Coastguard Worker 	if (header->h_refcount == 0)
483*6a54128fSAndroid Build Coastguard Worker 		ext2fs_block_alloc_stats2(fs, blk, -1);
484*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_iblk_sub_blocks(fs, (struct ext2_inode *)inode, 1);
485*6a54128fSAndroid Build Coastguard Worker 	if (err)
486*6a54128fSAndroid Build Coastguard Worker 		goto out2;
487*6a54128fSAndroid Build Coastguard Worker 
488*6a54128fSAndroid Build Coastguard Worker 	/* Write inode? */
489*6a54128fSAndroid Build Coastguard Worker 	if (inode == &i) {
490*6a54128fSAndroid Build Coastguard Worker 		err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&i,
491*6a54128fSAndroid Build Coastguard Worker 					      sizeof(struct ext2_inode_large));
492*6a54128fSAndroid Build Coastguard Worker 		if (err)
493*6a54128fSAndroid Build Coastguard Worker 			goto out2;
494*6a54128fSAndroid Build Coastguard Worker 	}
495*6a54128fSAndroid Build Coastguard Worker 
496*6a54128fSAndroid Build Coastguard Worker out2:
497*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&block_buf);
498*6a54128fSAndroid Build Coastguard Worker out:
499*6a54128fSAndroid Build Coastguard Worker 	return err;
500*6a54128fSAndroid Build Coastguard Worker }
501*6a54128fSAndroid Build Coastguard Worker 
prep_ea_block_for_write(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode_large * inode)502*6a54128fSAndroid Build Coastguard Worker static errcode_t prep_ea_block_for_write(ext2_filsys fs, ext2_ino_t ino,
503*6a54128fSAndroid Build Coastguard Worker 					 struct ext2_inode_large *inode)
504*6a54128fSAndroid Build Coastguard Worker {
505*6a54128fSAndroid Build Coastguard Worker 	struct ext2_ext_attr_header *header;
506*6a54128fSAndroid Build Coastguard Worker 	void *block_buf = NULL;
507*6a54128fSAndroid Build Coastguard Worker 	blk64_t blk, goal;
508*6a54128fSAndroid Build Coastguard Worker 	errcode_t err;
509*6a54128fSAndroid Build Coastguard Worker 
510*6a54128fSAndroid Build Coastguard Worker 	/* Do we already have an EA block? */
511*6a54128fSAndroid Build Coastguard Worker 	blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
512*6a54128fSAndroid Build Coastguard Worker 	if (blk != 0) {
513*6a54128fSAndroid Build Coastguard Worker 		if ((blk < fs->super->s_first_data_block) ||
514*6a54128fSAndroid Build Coastguard Worker 		    (blk >= ext2fs_blocks_count(fs->super))) {
515*6a54128fSAndroid Build Coastguard Worker 			err = EXT2_ET_BAD_EA_BLOCK_NUM;
516*6a54128fSAndroid Build Coastguard Worker 			goto out;
517*6a54128fSAndroid Build Coastguard Worker 		}
518*6a54128fSAndroid Build Coastguard Worker 
519*6a54128fSAndroid Build Coastguard Worker 		err = ext2fs_get_mem(fs->blocksize, &block_buf);
520*6a54128fSAndroid Build Coastguard Worker 		if (err)
521*6a54128fSAndroid Build Coastguard Worker 			goto out;
522*6a54128fSAndroid Build Coastguard Worker 
523*6a54128fSAndroid Build Coastguard Worker 		err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino);
524*6a54128fSAndroid Build Coastguard Worker 		if (err)
525*6a54128fSAndroid Build Coastguard Worker 			goto out2;
526*6a54128fSAndroid Build Coastguard Worker 
527*6a54128fSAndroid Build Coastguard Worker 		/* We only know how to deal with v2 EA blocks */
528*6a54128fSAndroid Build Coastguard Worker 		header = (struct ext2_ext_attr_header *) block_buf;
529*6a54128fSAndroid Build Coastguard Worker 		if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
530*6a54128fSAndroid Build Coastguard Worker 			err = EXT2_ET_BAD_EA_HEADER;
531*6a54128fSAndroid Build Coastguard Worker 			goto out2;
532*6a54128fSAndroid Build Coastguard Worker 		}
533*6a54128fSAndroid Build Coastguard Worker 
534*6a54128fSAndroid Build Coastguard Worker 		/* Single-user block.  We're done here. */
535*6a54128fSAndroid Build Coastguard Worker 		if (header->h_refcount == 1)
536*6a54128fSAndroid Build Coastguard Worker 			goto out2;
537*6a54128fSAndroid Build Coastguard Worker 
538*6a54128fSAndroid Build Coastguard Worker 		/* We need to CoW the block. */
539*6a54128fSAndroid Build Coastguard Worker 		header->h_refcount--;
540*6a54128fSAndroid Build Coastguard Worker 		err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino);
541*6a54128fSAndroid Build Coastguard Worker 		if (err)
542*6a54128fSAndroid Build Coastguard Worker 			goto out2;
543*6a54128fSAndroid Build Coastguard Worker 	} else {
544*6a54128fSAndroid Build Coastguard Worker 		/* No block, we must increment i_blocks */
545*6a54128fSAndroid Build Coastguard Worker 		err = ext2fs_iblk_add_blocks(fs, (struct ext2_inode *)inode,
546*6a54128fSAndroid Build Coastguard Worker 					     1);
547*6a54128fSAndroid Build Coastguard Worker 		if (err)
548*6a54128fSAndroid Build Coastguard Worker 			goto out;
549*6a54128fSAndroid Build Coastguard Worker 	}
550*6a54128fSAndroid Build Coastguard Worker 
551*6a54128fSAndroid Build Coastguard Worker 	/* Allocate a block */
552*6a54128fSAndroid Build Coastguard Worker 	goal = ext2fs_find_inode_goal(fs, ino, (struct ext2_inode *)inode, 0);
553*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_alloc_block2(fs, goal, NULL, &blk);
554*6a54128fSAndroid Build Coastguard Worker 	if (err)
555*6a54128fSAndroid Build Coastguard Worker 		goto out2;
556*6a54128fSAndroid Build Coastguard Worker 	ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, blk);
557*6a54128fSAndroid Build Coastguard Worker out2:
558*6a54128fSAndroid Build Coastguard Worker 	if (block_buf)
559*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&block_buf);
560*6a54128fSAndroid Build Coastguard Worker out:
561*6a54128fSAndroid Build Coastguard Worker 	return err;
562*6a54128fSAndroid Build Coastguard Worker }
563*6a54128fSAndroid Build Coastguard Worker 
564*6a54128fSAndroid Build Coastguard Worker 
565*6a54128fSAndroid Build Coastguard Worker static inline int
posix_acl_xattr_count(size_t size)566*6a54128fSAndroid Build Coastguard Worker posix_acl_xattr_count(size_t size)
567*6a54128fSAndroid Build Coastguard Worker {
568*6a54128fSAndroid Build Coastguard Worker         if (size < sizeof(posix_acl_xattr_header))
569*6a54128fSAndroid Build Coastguard Worker                 return -1;
570*6a54128fSAndroid Build Coastguard Worker         size -= sizeof(posix_acl_xattr_header);
571*6a54128fSAndroid Build Coastguard Worker         if (size % sizeof(posix_acl_xattr_entry))
572*6a54128fSAndroid Build Coastguard Worker                 return -1;
573*6a54128fSAndroid Build Coastguard Worker         return size / sizeof(posix_acl_xattr_entry);
574*6a54128fSAndroid Build Coastguard Worker }
575*6a54128fSAndroid Build Coastguard Worker 
576*6a54128fSAndroid Build Coastguard Worker /*
577*6a54128fSAndroid Build Coastguard Worker  * The lgetxattr function returns data formatted in the POSIX extended
578*6a54128fSAndroid Build Coastguard Worker  * attribute format.  The on-disk format uses a more compact encoding.
579*6a54128fSAndroid Build Coastguard Worker  * See the ext4_acl_to_disk in fs/ext4/acl.c.
580*6a54128fSAndroid Build Coastguard Worker  */
convert_posix_acl_to_disk_buffer(const void * value,size_t size,void * out_buf,size_t * size_out)581*6a54128fSAndroid Build Coastguard Worker static errcode_t convert_posix_acl_to_disk_buffer(const void *value, size_t size,
582*6a54128fSAndroid Build Coastguard Worker 						  void *out_buf, size_t *size_out)
583*6a54128fSAndroid Build Coastguard Worker {
584*6a54128fSAndroid Build Coastguard Worker 	const posix_acl_xattr_header *header =
585*6a54128fSAndroid Build Coastguard Worker 		(const posix_acl_xattr_header*) value;
586*6a54128fSAndroid Build Coastguard Worker 	const posix_acl_xattr_entry *end, *entry =
587*6a54128fSAndroid Build Coastguard Worker 		(const posix_acl_xattr_entry *)(header+1);
588*6a54128fSAndroid Build Coastguard Worker 	ext4_acl_header *ext_acl;
589*6a54128fSAndroid Build Coastguard Worker 	size_t s;
590*6a54128fSAndroid Build Coastguard Worker 	char *e;
591*6a54128fSAndroid Build Coastguard Worker 
592*6a54128fSAndroid Build Coastguard Worker 	int count;
593*6a54128fSAndroid Build Coastguard Worker 
594*6a54128fSAndroid Build Coastguard Worker 	if (!value)
595*6a54128fSAndroid Build Coastguard Worker 		return EINVAL;
596*6a54128fSAndroid Build Coastguard Worker 	if (size < sizeof(posix_acl_xattr_header))
597*6a54128fSAndroid Build Coastguard Worker 		return ENOMEM;
598*6a54128fSAndroid Build Coastguard Worker 	if (header->a_version != ext2fs_cpu_to_le32(POSIX_ACL_XATTR_VERSION))
599*6a54128fSAndroid Build Coastguard Worker 		return EINVAL;
600*6a54128fSAndroid Build Coastguard Worker 
601*6a54128fSAndroid Build Coastguard Worker 	count = posix_acl_xattr_count(size);
602*6a54128fSAndroid Build Coastguard Worker 	ext_acl = out_buf;
603*6a54128fSAndroid Build Coastguard Worker 	ext_acl->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION);
604*6a54128fSAndroid Build Coastguard Worker 
605*6a54128fSAndroid Build Coastguard Worker 	if (count <= 0)
606*6a54128fSAndroid Build Coastguard Worker 		return EINVAL;
607*6a54128fSAndroid Build Coastguard Worker 
608*6a54128fSAndroid Build Coastguard Worker 	e = (char *) out_buf + sizeof(ext4_acl_header);
609*6a54128fSAndroid Build Coastguard Worker 	s = sizeof(ext4_acl_header);
610*6a54128fSAndroid Build Coastguard Worker 	for (end = entry + count; entry != end;entry++) {
611*6a54128fSAndroid Build Coastguard Worker 		ext4_acl_entry *disk_entry = (ext4_acl_entry*) e;
612*6a54128fSAndroid Build Coastguard Worker 		disk_entry->e_tag = entry->e_tag;
613*6a54128fSAndroid Build Coastguard Worker 		disk_entry->e_perm = entry->e_perm;
614*6a54128fSAndroid Build Coastguard Worker 
615*6a54128fSAndroid Build Coastguard Worker 		switch(ext2fs_le16_to_cpu(entry->e_tag)) {
616*6a54128fSAndroid Build Coastguard Worker 			case ACL_USER_OBJ:
617*6a54128fSAndroid Build Coastguard Worker 			case ACL_GROUP_OBJ:
618*6a54128fSAndroid Build Coastguard Worker 			case ACL_MASK:
619*6a54128fSAndroid Build Coastguard Worker 			case ACL_OTHER:
620*6a54128fSAndroid Build Coastguard Worker 				e += sizeof(ext4_acl_entry_short);
621*6a54128fSAndroid Build Coastguard Worker 				s += sizeof(ext4_acl_entry_short);
622*6a54128fSAndroid Build Coastguard Worker 				break;
623*6a54128fSAndroid Build Coastguard Worker 			case ACL_USER:
624*6a54128fSAndroid Build Coastguard Worker 			case ACL_GROUP:
625*6a54128fSAndroid Build Coastguard Worker 				disk_entry->e_id = entry->e_id;
626*6a54128fSAndroid Build Coastguard Worker 				e += sizeof(ext4_acl_entry);
627*6a54128fSAndroid Build Coastguard Worker 				s += sizeof(ext4_acl_entry);
628*6a54128fSAndroid Build Coastguard Worker 				break;
629*6a54128fSAndroid Build Coastguard Worker 			default:
630*6a54128fSAndroid Build Coastguard Worker 				return EINVAL;
631*6a54128fSAndroid Build Coastguard Worker 		}
632*6a54128fSAndroid Build Coastguard Worker 	}
633*6a54128fSAndroid Build Coastguard Worker 	*size_out = s;
634*6a54128fSAndroid Build Coastguard Worker 	return 0;
635*6a54128fSAndroid Build Coastguard Worker }
636*6a54128fSAndroid Build Coastguard Worker 
convert_disk_buffer_to_posix_acl(const void * value,size_t size,void ** out_buf,size_t * size_out)637*6a54128fSAndroid Build Coastguard Worker static errcode_t convert_disk_buffer_to_posix_acl(const void *value, size_t size,
638*6a54128fSAndroid Build Coastguard Worker 						  void **out_buf, size_t *size_out)
639*6a54128fSAndroid Build Coastguard Worker {
640*6a54128fSAndroid Build Coastguard Worker 	posix_acl_xattr_header *header;
641*6a54128fSAndroid Build Coastguard Worker 	posix_acl_xattr_entry *entry;
642*6a54128fSAndroid Build Coastguard Worker 	const ext4_acl_header *ext_acl = (const ext4_acl_header *) value;
643*6a54128fSAndroid Build Coastguard Worker 	errcode_t err;
644*6a54128fSAndroid Build Coastguard Worker 	const char *cp;
645*6a54128fSAndroid Build Coastguard Worker 	char *out;
646*6a54128fSAndroid Build Coastguard Worker 
647*6a54128fSAndroid Build Coastguard Worker 	if ((!value) ||
648*6a54128fSAndroid Build Coastguard Worker 	    (size < sizeof(ext4_acl_header)) ||
649*6a54128fSAndroid Build Coastguard Worker 	    (ext_acl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION)))
650*6a54128fSAndroid Build Coastguard Worker 		return EINVAL;
651*6a54128fSAndroid Build Coastguard Worker 
652*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_get_mem(size * 2, &out);
653*6a54128fSAndroid Build Coastguard Worker 	if (err)
654*6a54128fSAndroid Build Coastguard Worker 		return err;
655*6a54128fSAndroid Build Coastguard Worker 
656*6a54128fSAndroid Build Coastguard Worker 	header = (posix_acl_xattr_header *) out;
657*6a54128fSAndroid Build Coastguard Worker 	header->a_version = ext2fs_cpu_to_le32(POSIX_ACL_XATTR_VERSION);
658*6a54128fSAndroid Build Coastguard Worker 	entry = (posix_acl_xattr_entry *) (out + sizeof(posix_acl_xattr_header));
659*6a54128fSAndroid Build Coastguard Worker 
660*6a54128fSAndroid Build Coastguard Worker 	cp = (const char *) value + sizeof(ext4_acl_header);
661*6a54128fSAndroid Build Coastguard Worker 	size -= sizeof(ext4_acl_header);
662*6a54128fSAndroid Build Coastguard Worker 
663*6a54128fSAndroid Build Coastguard Worker 	while (size > 0) {
664*6a54128fSAndroid Build Coastguard Worker 		const ext4_acl_entry *disk_entry = (const ext4_acl_entry *) cp;
665*6a54128fSAndroid Build Coastguard Worker 
666*6a54128fSAndroid Build Coastguard Worker 		entry->e_tag = disk_entry->e_tag;
667*6a54128fSAndroid Build Coastguard Worker 		entry->e_perm = disk_entry->e_perm;
668*6a54128fSAndroid Build Coastguard Worker 
669*6a54128fSAndroid Build Coastguard Worker 		switch(ext2fs_le16_to_cpu(entry->e_tag)) {
670*6a54128fSAndroid Build Coastguard Worker 			case ACL_USER_OBJ:
671*6a54128fSAndroid Build Coastguard Worker 			case ACL_GROUP_OBJ:
672*6a54128fSAndroid Build Coastguard Worker 			case ACL_MASK:
673*6a54128fSAndroid Build Coastguard Worker 			case ACL_OTHER:
674*6a54128fSAndroid Build Coastguard Worker 				entry->e_id = 0;
675*6a54128fSAndroid Build Coastguard Worker 				cp += sizeof(ext4_acl_entry_short);
676*6a54128fSAndroid Build Coastguard Worker 				size -= sizeof(ext4_acl_entry_short);
677*6a54128fSAndroid Build Coastguard Worker 				break;
678*6a54128fSAndroid Build Coastguard Worker 			case ACL_USER:
679*6a54128fSAndroid Build Coastguard Worker 			case ACL_GROUP:
680*6a54128fSAndroid Build Coastguard Worker 				entry->e_id = disk_entry->e_id;
681*6a54128fSAndroid Build Coastguard Worker 				cp += sizeof(ext4_acl_entry);
682*6a54128fSAndroid Build Coastguard Worker 				size -= sizeof(ext4_acl_entry);
683*6a54128fSAndroid Build Coastguard Worker 				break;
684*6a54128fSAndroid Build Coastguard Worker 			default:
685*6a54128fSAndroid Build Coastguard Worker 				ext2fs_free_mem(&out);
686*6a54128fSAndroid Build Coastguard Worker 				return EINVAL;
687*6a54128fSAndroid Build Coastguard Worker 		}
688*6a54128fSAndroid Build Coastguard Worker 		entry++;
689*6a54128fSAndroid Build Coastguard Worker 	}
690*6a54128fSAndroid Build Coastguard Worker 	*out_buf = out;
691*6a54128fSAndroid Build Coastguard Worker 	*size_out = ((char *) entry - out);
692*6a54128fSAndroid Build Coastguard Worker 	return 0;
693*6a54128fSAndroid Build Coastguard Worker }
694*6a54128fSAndroid Build Coastguard Worker 
695*6a54128fSAndroid Build Coastguard Worker static errcode_t
write_xattrs_to_buffer(ext2_filsys fs,struct ext2_xattr * attrs,int count,void * entries_start,unsigned int storage_size,unsigned int value_offset_correction,int write_hash)696*6a54128fSAndroid Build Coastguard Worker write_xattrs_to_buffer(ext2_filsys fs, struct ext2_xattr *attrs, int count,
697*6a54128fSAndroid Build Coastguard Worker 		       void *entries_start, unsigned int storage_size,
698*6a54128fSAndroid Build Coastguard Worker 		       unsigned int value_offset_correction, int write_hash)
699*6a54128fSAndroid Build Coastguard Worker {
700*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *x;
701*6a54128fSAndroid Build Coastguard Worker 	struct ext2_ext_attr_entry *e = entries_start;
702*6a54128fSAndroid Build Coastguard Worker 	char *end = (char *) entries_start + storage_size;
703*6a54128fSAndroid Build Coastguard Worker 	unsigned int value_size;
704*6a54128fSAndroid Build Coastguard Worker 	errcode_t err;
705*6a54128fSAndroid Build Coastguard Worker 
706*6a54128fSAndroid Build Coastguard Worker 	memset(entries_start, 0, storage_size);
707*6a54128fSAndroid Build Coastguard Worker 	for (x = attrs; x < attrs + count; x++) {
708*6a54128fSAndroid Build Coastguard Worker 		value_size = ((x->value_len + EXT2_EXT_ATTR_PAD - 1) /
709*6a54128fSAndroid Build Coastguard Worker 			      EXT2_EXT_ATTR_PAD) * EXT2_EXT_ATTR_PAD;
710*6a54128fSAndroid Build Coastguard Worker 
711*6a54128fSAndroid Build Coastguard Worker 		/* Fill out e appropriately */
712*6a54128fSAndroid Build Coastguard Worker 		e->e_name_len = strlen(x->short_name);
713*6a54128fSAndroid Build Coastguard Worker 		e->e_name_index = x->name_index;
714*6a54128fSAndroid Build Coastguard Worker 
715*6a54128fSAndroid Build Coastguard Worker 		e->e_value_size = x->value_len;
716*6a54128fSAndroid Build Coastguard Worker 		e->e_value_inum = x->ea_ino;
717*6a54128fSAndroid Build Coastguard Worker 
718*6a54128fSAndroid Build Coastguard Worker 		/* Store name */
719*6a54128fSAndroid Build Coastguard Worker 		memcpy((char *)e + sizeof(*e), x->short_name, e->e_name_len);
720*6a54128fSAndroid Build Coastguard Worker 		if (x->ea_ino) {
721*6a54128fSAndroid Build Coastguard Worker 			e->e_value_offs = 0;
722*6a54128fSAndroid Build Coastguard Worker 		} else {
723*6a54128fSAndroid Build Coastguard Worker 			end -= value_size;
724*6a54128fSAndroid Build Coastguard Worker 			e->e_value_offs = end - (char *) entries_start +
725*6a54128fSAndroid Build Coastguard Worker 						value_offset_correction;
726*6a54128fSAndroid Build Coastguard Worker 			memcpy(end, x->value, e->e_value_size);
727*6a54128fSAndroid Build Coastguard Worker 		}
728*6a54128fSAndroid Build Coastguard Worker 
729*6a54128fSAndroid Build Coastguard Worker 		if (write_hash || x->ea_ino) {
730*6a54128fSAndroid Build Coastguard Worker 			err = ext2fs_ext_attr_hash_entry2(fs, e,
731*6a54128fSAndroid Build Coastguard Worker 							  x->ea_ino ? 0 : end,
732*6a54128fSAndroid Build Coastguard Worker 							  &e->e_hash);
733*6a54128fSAndroid Build Coastguard Worker 			if (err)
734*6a54128fSAndroid Build Coastguard Worker 				return err;
735*6a54128fSAndroid Build Coastguard Worker 		} else
736*6a54128fSAndroid Build Coastguard Worker 			e->e_hash = 0;
737*6a54128fSAndroid Build Coastguard Worker 
738*6a54128fSAndroid Build Coastguard Worker 		e = EXT2_EXT_ATTR_NEXT(e);
739*6a54128fSAndroid Build Coastguard Worker 		*(__u32 *)e = 0;
740*6a54128fSAndroid Build Coastguard Worker 	}
741*6a54128fSAndroid Build Coastguard Worker 	return 0;
742*6a54128fSAndroid Build Coastguard Worker }
743*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattrs_write(struct ext2_xattr_handle * handle)744*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle)
745*6a54128fSAndroid Build Coastguard Worker {
746*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys fs = handle->fs;
747*6a54128fSAndroid Build Coastguard Worker 	const unsigned int inode_size = EXT2_INODE_SIZE(fs->super);
748*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode_large *inode;
749*6a54128fSAndroid Build Coastguard Worker 	char *start, *block_buf = NULL;
750*6a54128fSAndroid Build Coastguard Worker 	struct ext2_ext_attr_header *header;
751*6a54128fSAndroid Build Coastguard Worker 	__u32 ea_inode_magic;
752*6a54128fSAndroid Build Coastguard Worker 	blk64_t blk;
753*6a54128fSAndroid Build Coastguard Worker 	unsigned int storage_size;
754*6a54128fSAndroid Build Coastguard Worker 	unsigned int i;
755*6a54128fSAndroid Build Coastguard Worker 	errcode_t err;
756*6a54128fSAndroid Build Coastguard Worker 
757*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
758*6a54128fSAndroid Build Coastguard Worker 	i = inode_size;
759*6a54128fSAndroid Build Coastguard Worker 	if (i < sizeof(*inode))
760*6a54128fSAndroid Build Coastguard Worker 		i = sizeof(*inode);
761*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_get_memzero(i, &inode);
762*6a54128fSAndroid Build Coastguard Worker 	if (err)
763*6a54128fSAndroid Build Coastguard Worker 		return err;
764*6a54128fSAndroid Build Coastguard Worker 
765*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_read_inode_full(fs, handle->ino, EXT2_INODE(inode),
766*6a54128fSAndroid Build Coastguard Worker 				     inode_size);
767*6a54128fSAndroid Build Coastguard Worker 	if (err)
768*6a54128fSAndroid Build Coastguard Worker 		goto out;
769*6a54128fSAndroid Build Coastguard Worker 
770*6a54128fSAndroid Build Coastguard Worker 	/* If extra_isize isn't set, we need to set it now */
771*6a54128fSAndroid Build Coastguard Worker 	if (inode->i_extra_isize == 0 &&
772*6a54128fSAndroid Build Coastguard Worker 	    inode_size > EXT2_GOOD_OLD_INODE_SIZE) {
773*6a54128fSAndroid Build Coastguard Worker 		char *p = (char *)inode;
774*6a54128fSAndroid Build Coastguard Worker 		size_t extra = fs->super->s_want_extra_isize;
775*6a54128fSAndroid Build Coastguard Worker 
776*6a54128fSAndroid Build Coastguard Worker 		if (extra == 0)
777*6a54128fSAndroid Build Coastguard Worker 			extra = sizeof(__u32);
778*6a54128fSAndroid Build Coastguard Worker 		memset(p + EXT2_GOOD_OLD_INODE_SIZE, 0, extra);
779*6a54128fSAndroid Build Coastguard Worker 		inode->i_extra_isize = extra;
780*6a54128fSAndroid Build Coastguard Worker 	}
781*6a54128fSAndroid Build Coastguard Worker 	if (inode->i_extra_isize & 3) {
782*6a54128fSAndroid Build Coastguard Worker 		err = EXT2_ET_INODE_CORRUPTED;
783*6a54128fSAndroid Build Coastguard Worker 		goto out;
784*6a54128fSAndroid Build Coastguard Worker 	}
785*6a54128fSAndroid Build Coastguard Worker 
786*6a54128fSAndroid Build Coastguard Worker 	/* Does the inode have space for EA? */
787*6a54128fSAndroid Build Coastguard Worker 	if (inode->i_extra_isize < sizeof(inode->i_extra_isize) ||
788*6a54128fSAndroid Build Coastguard Worker 	    inode_size <= EXT2_GOOD_OLD_INODE_SIZE + inode->i_extra_isize +
789*6a54128fSAndroid Build Coastguard Worker 								sizeof(__u32))
790*6a54128fSAndroid Build Coastguard Worker 		goto write_ea_block;
791*6a54128fSAndroid Build Coastguard Worker 
792*6a54128fSAndroid Build Coastguard Worker 	/* Write the inode EA */
793*6a54128fSAndroid Build Coastguard Worker 	ea_inode_magic = EXT2_EXT_ATTR_MAGIC;
794*6a54128fSAndroid Build Coastguard Worker 	memcpy(((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
795*6a54128fSAndroid Build Coastguard Worker 	       inode->i_extra_isize, &ea_inode_magic, sizeof(__u32));
796*6a54128fSAndroid Build Coastguard Worker 	storage_size = inode_size - EXT2_GOOD_OLD_INODE_SIZE -
797*6a54128fSAndroid Build Coastguard Worker 				inode->i_extra_isize - sizeof(__u32);
798*6a54128fSAndroid Build Coastguard Worker 	start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
799*6a54128fSAndroid Build Coastguard Worker 				inode->i_extra_isize + sizeof(__u32);
800*6a54128fSAndroid Build Coastguard Worker 
801*6a54128fSAndroid Build Coastguard Worker 	err = write_xattrs_to_buffer(fs, handle->attrs, handle->ibody_count,
802*6a54128fSAndroid Build Coastguard Worker 				     start, storage_size, 0, 0);
803*6a54128fSAndroid Build Coastguard Worker 	if (err)
804*6a54128fSAndroid Build Coastguard Worker 		goto out;
805*6a54128fSAndroid Build Coastguard Worker write_ea_block:
806*6a54128fSAndroid Build Coastguard Worker 	/* Are we done? */
807*6a54128fSAndroid Build Coastguard Worker 	if (handle->ibody_count == handle->count &&
808*6a54128fSAndroid Build Coastguard Worker 	    !ext2fs_file_acl_block(fs, EXT2_INODE(inode)))
809*6a54128fSAndroid Build Coastguard Worker 		goto skip_ea_block;
810*6a54128fSAndroid Build Coastguard Worker 
811*6a54128fSAndroid Build Coastguard Worker 	/* Write the EA block */
812*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_get_memzero(fs->blocksize, &block_buf);
813*6a54128fSAndroid Build Coastguard Worker 	if (err)
814*6a54128fSAndroid Build Coastguard Worker 		goto out;
815*6a54128fSAndroid Build Coastguard Worker 
816*6a54128fSAndroid Build Coastguard Worker 	storage_size = fs->blocksize - sizeof(struct ext2_ext_attr_header);
817*6a54128fSAndroid Build Coastguard Worker 	start = block_buf + sizeof(struct ext2_ext_attr_header);
818*6a54128fSAndroid Build Coastguard Worker 
819*6a54128fSAndroid Build Coastguard Worker 	err = write_xattrs_to_buffer(fs, handle->attrs + handle->ibody_count,
820*6a54128fSAndroid Build Coastguard Worker 				     handle->count - handle->ibody_count, start,
821*6a54128fSAndroid Build Coastguard Worker 				     storage_size, start - block_buf, 1);
822*6a54128fSAndroid Build Coastguard Worker 	if (err)
823*6a54128fSAndroid Build Coastguard Worker 		goto out2;
824*6a54128fSAndroid Build Coastguard Worker 
825*6a54128fSAndroid Build Coastguard Worker 	/* Write a header on the EA block */
826*6a54128fSAndroid Build Coastguard Worker 	header = (struct ext2_ext_attr_header *) block_buf;
827*6a54128fSAndroid Build Coastguard Worker 	header->h_magic = EXT2_EXT_ATTR_MAGIC;
828*6a54128fSAndroid Build Coastguard Worker 	header->h_refcount = 1;
829*6a54128fSAndroid Build Coastguard Worker 	header->h_blocks = 1;
830*6a54128fSAndroid Build Coastguard Worker 
831*6a54128fSAndroid Build Coastguard Worker 	/* Get a new block for writing */
832*6a54128fSAndroid Build Coastguard Worker 	err = prep_ea_block_for_write(fs, handle->ino, inode);
833*6a54128fSAndroid Build Coastguard Worker 	if (err)
834*6a54128fSAndroid Build Coastguard Worker 		goto out2;
835*6a54128fSAndroid Build Coastguard Worker 
836*6a54128fSAndroid Build Coastguard Worker 	/* Finally, write the new EA block */
837*6a54128fSAndroid Build Coastguard Worker 	blk = ext2fs_file_acl_block(fs, EXT2_INODE(inode));
838*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_write_ext_attr3(fs, blk, block_buf, handle->ino);
839*6a54128fSAndroid Build Coastguard Worker 	if (err)
840*6a54128fSAndroid Build Coastguard Worker 		goto out2;
841*6a54128fSAndroid Build Coastguard Worker 
842*6a54128fSAndroid Build Coastguard Worker skip_ea_block:
843*6a54128fSAndroid Build Coastguard Worker 	blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
844*6a54128fSAndroid Build Coastguard Worker 	if (!block_buf && blk) {
845*6a54128fSAndroid Build Coastguard Worker 		/* xattrs shrunk, free the block */
846*6a54128fSAndroid Build Coastguard Worker 		err = ext2fs_free_ext_attr(fs, handle->ino, inode);
847*6a54128fSAndroid Build Coastguard Worker 		if (err)
848*6a54128fSAndroid Build Coastguard Worker 			goto out;
849*6a54128fSAndroid Build Coastguard Worker 	}
850*6a54128fSAndroid Build Coastguard Worker 
851*6a54128fSAndroid Build Coastguard Worker 	/* Write the inode */
852*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_write_inode_full(fs, handle->ino, EXT2_INODE(inode),
853*6a54128fSAndroid Build Coastguard Worker 				      inode_size);
854*6a54128fSAndroid Build Coastguard Worker 	if (err)
855*6a54128fSAndroid Build Coastguard Worker 		goto out2;
856*6a54128fSAndroid Build Coastguard Worker 
857*6a54128fSAndroid Build Coastguard Worker out2:
858*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&block_buf);
859*6a54128fSAndroid Build Coastguard Worker out:
860*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&inode);
861*6a54128fSAndroid Build Coastguard Worker 	return err;
862*6a54128fSAndroid Build Coastguard Worker }
863*6a54128fSAndroid Build Coastguard Worker 
read_xattrs_from_buffer(struct ext2_xattr_handle * handle,struct ext2_inode_large * inode,struct ext2_ext_attr_entry * entries,unsigned int storage_size,char * value_start)864*6a54128fSAndroid Build Coastguard Worker static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
865*6a54128fSAndroid Build Coastguard Worker 					 struct ext2_inode_large *inode,
866*6a54128fSAndroid Build Coastguard Worker 					 struct ext2_ext_attr_entry *entries,
867*6a54128fSAndroid Build Coastguard Worker 					 unsigned int storage_size,
868*6a54128fSAndroid Build Coastguard Worker 					 char *value_start)
869*6a54128fSAndroid Build Coastguard Worker {
870*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *x;
871*6a54128fSAndroid Build Coastguard Worker 	struct ext2_ext_attr_entry *entry, *end;
872*6a54128fSAndroid Build Coastguard Worker 	const char *prefix;
873*6a54128fSAndroid Build Coastguard Worker 	unsigned int remain, prefix_len;
874*6a54128fSAndroid Build Coastguard Worker 	errcode_t err;
875*6a54128fSAndroid Build Coastguard Worker 	unsigned int values_size = storage_size +
876*6a54128fSAndroid Build Coastguard Worker 			((char *)entries - value_start);
877*6a54128fSAndroid Build Coastguard Worker 
878*6a54128fSAndroid Build Coastguard Worker 	/* find the end */
879*6a54128fSAndroid Build Coastguard Worker 	end = entries;
880*6a54128fSAndroid Build Coastguard Worker 	remain = storage_size;
881*6a54128fSAndroid Build Coastguard Worker 	while (remain >= sizeof(struct ext2_ext_attr_entry) &&
882*6a54128fSAndroid Build Coastguard Worker 	       !EXT2_EXT_IS_LAST_ENTRY(end)) {
883*6a54128fSAndroid Build Coastguard Worker 
884*6a54128fSAndroid Build Coastguard Worker 		/* header eats this space */
885*6a54128fSAndroid Build Coastguard Worker 		remain -= sizeof(struct ext2_ext_attr_entry);
886*6a54128fSAndroid Build Coastguard Worker 
887*6a54128fSAndroid Build Coastguard Worker 		/* is attribute name valid? */
888*6a54128fSAndroid Build Coastguard Worker 		if (EXT2_EXT_ATTR_SIZE(end->e_name_len) > remain)
889*6a54128fSAndroid Build Coastguard Worker 			return EXT2_ET_EA_BAD_NAME_LEN;
890*6a54128fSAndroid Build Coastguard Worker 
891*6a54128fSAndroid Build Coastguard Worker 		/* attribute len eats this space */
892*6a54128fSAndroid Build Coastguard Worker 		remain -= EXT2_EXT_ATTR_SIZE(end->e_name_len);
893*6a54128fSAndroid Build Coastguard Worker 		end = EXT2_EXT_ATTR_NEXT(end);
894*6a54128fSAndroid Build Coastguard Worker 	}
895*6a54128fSAndroid Build Coastguard Worker 
896*6a54128fSAndroid Build Coastguard Worker 	entry = entries;
897*6a54128fSAndroid Build Coastguard Worker 	remain = storage_size;
898*6a54128fSAndroid Build Coastguard Worker 	while (remain >= sizeof(struct ext2_ext_attr_entry) &&
899*6a54128fSAndroid Build Coastguard Worker 	       !EXT2_EXT_IS_LAST_ENTRY(entry)) {
900*6a54128fSAndroid Build Coastguard Worker 
901*6a54128fSAndroid Build Coastguard Worker 		/* Allocate space for more attrs? */
902*6a54128fSAndroid Build Coastguard Worker 		if (handle->count == handle->capacity) {
903*6a54128fSAndroid Build Coastguard Worker 			err = ext2fs_xattrs_expand(handle, 4);
904*6a54128fSAndroid Build Coastguard Worker 			if (err)
905*6a54128fSAndroid Build Coastguard Worker 				return err;
906*6a54128fSAndroid Build Coastguard Worker 		}
907*6a54128fSAndroid Build Coastguard Worker 
908*6a54128fSAndroid Build Coastguard Worker 		x = handle->attrs + handle->count;
909*6a54128fSAndroid Build Coastguard Worker 
910*6a54128fSAndroid Build Coastguard Worker 		/* header eats this space */
911*6a54128fSAndroid Build Coastguard Worker 		remain -= sizeof(struct ext2_ext_attr_entry);
912*6a54128fSAndroid Build Coastguard Worker 
913*6a54128fSAndroid Build Coastguard Worker 		/* attribute len eats this space */
914*6a54128fSAndroid Build Coastguard Worker 		remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
915*6a54128fSAndroid Build Coastguard Worker 
916*6a54128fSAndroid Build Coastguard Worker 		/* Extract name */
917*6a54128fSAndroid Build Coastguard Worker 		prefix = find_ea_prefix(entry->e_name_index);
918*6a54128fSAndroid Build Coastguard Worker 		prefix_len = (prefix ? strlen(prefix) : 0);
919*6a54128fSAndroid Build Coastguard Worker 		err = ext2fs_get_memzero(entry->e_name_len + prefix_len + 1,
920*6a54128fSAndroid Build Coastguard Worker 					 &x->name);
921*6a54128fSAndroid Build Coastguard Worker 		if (err)
922*6a54128fSAndroid Build Coastguard Worker 			return err;
923*6a54128fSAndroid Build Coastguard Worker 		if (prefix)
924*6a54128fSAndroid Build Coastguard Worker 			memcpy(x->name, prefix, prefix_len);
925*6a54128fSAndroid Build Coastguard Worker 		if (entry->e_name_len)
926*6a54128fSAndroid Build Coastguard Worker 			memcpy(x->name + prefix_len,
927*6a54128fSAndroid Build Coastguard Worker 			       (char *)entry + sizeof(*entry),
928*6a54128fSAndroid Build Coastguard Worker 			       entry->e_name_len);
929*6a54128fSAndroid Build Coastguard Worker 		x->short_name = x->name + prefix_len;
930*6a54128fSAndroid Build Coastguard Worker 		x->name_index = entry->e_name_index;
931*6a54128fSAndroid Build Coastguard Worker 
932*6a54128fSAndroid Build Coastguard Worker 		/* Check & copy value */
933*6a54128fSAndroid Build Coastguard Worker 		if (!ext2fs_has_feature_ea_inode(handle->fs->super) &&
934*6a54128fSAndroid Build Coastguard Worker 		    entry->e_value_inum != 0)
935*6a54128fSAndroid Build Coastguard Worker 			return EXT2_ET_BAD_EA_BLOCK_NUM;
936*6a54128fSAndroid Build Coastguard Worker 
937*6a54128fSAndroid Build Coastguard Worker 		if (entry->e_value_inum == 0) {
938*6a54128fSAndroid Build Coastguard Worker 			if (entry->e_value_size > remain)
939*6a54128fSAndroid Build Coastguard Worker 				return EXT2_ET_EA_BAD_VALUE_SIZE;
940*6a54128fSAndroid Build Coastguard Worker 
941*6a54128fSAndroid Build Coastguard Worker 			if (entry->e_value_offs + entry->e_value_size > values_size)
942*6a54128fSAndroid Build Coastguard Worker 				return EXT2_ET_EA_BAD_VALUE_OFFSET;
943*6a54128fSAndroid Build Coastguard Worker 
944*6a54128fSAndroid Build Coastguard Worker 			if (entry->e_value_size > 0 &&
945*6a54128fSAndroid Build Coastguard Worker 			    value_start + entry->e_value_offs <
946*6a54128fSAndroid Build Coastguard Worker 			    (char *)end + sizeof(__u32))
947*6a54128fSAndroid Build Coastguard Worker 				return EXT2_ET_EA_BAD_VALUE_OFFSET;
948*6a54128fSAndroid Build Coastguard Worker 
949*6a54128fSAndroid Build Coastguard Worker 			remain -= entry->e_value_size;
950*6a54128fSAndroid Build Coastguard Worker 
951*6a54128fSAndroid Build Coastguard Worker 			err = ext2fs_get_mem(entry->e_value_size, &x->value);
952*6a54128fSAndroid Build Coastguard Worker 			if (err)
953*6a54128fSAndroid Build Coastguard Worker 				return err;
954*6a54128fSAndroid Build Coastguard Worker 			memcpy(x->value, value_start + entry->e_value_offs,
955*6a54128fSAndroid Build Coastguard Worker 			       entry->e_value_size);
956*6a54128fSAndroid Build Coastguard Worker 		} else {
957*6a54128fSAndroid Build Coastguard Worker 			struct ext2_inode *ea_inode;
958*6a54128fSAndroid Build Coastguard Worker 			ext2_file_t ea_file;
959*6a54128fSAndroid Build Coastguard Worker 
960*6a54128fSAndroid Build Coastguard Worker 			if (entry->e_value_offs != 0)
961*6a54128fSAndroid Build Coastguard Worker 				return EXT2_ET_EA_BAD_VALUE_OFFSET;
962*6a54128fSAndroid Build Coastguard Worker 
963*6a54128fSAndroid Build Coastguard Worker 			if (entry->e_value_size > (64 * 1024))
964*6a54128fSAndroid Build Coastguard Worker 				return EXT2_ET_EA_BAD_VALUE_SIZE;
965*6a54128fSAndroid Build Coastguard Worker 
966*6a54128fSAndroid Build Coastguard Worker 			err = ext2fs_get_mem(entry->e_value_size, &x->value);
967*6a54128fSAndroid Build Coastguard Worker 			if (err)
968*6a54128fSAndroid Build Coastguard Worker 				return err;
969*6a54128fSAndroid Build Coastguard Worker 
970*6a54128fSAndroid Build Coastguard Worker 			err = ext2fs_file_open(handle->fs, entry->e_value_inum,
971*6a54128fSAndroid Build Coastguard Worker 					       0, &ea_file);
972*6a54128fSAndroid Build Coastguard Worker 			if (err)
973*6a54128fSAndroid Build Coastguard Worker 				return err;
974*6a54128fSAndroid Build Coastguard Worker 
975*6a54128fSAndroid Build Coastguard Worker 			ea_inode = ext2fs_file_get_inode(ea_file);
976*6a54128fSAndroid Build Coastguard Worker 			if ((ea_inode->i_flags & EXT4_INLINE_DATA_FL) ||
977*6a54128fSAndroid Build Coastguard Worker 			    !(ea_inode->i_flags & EXT4_EA_INODE_FL) ||
978*6a54128fSAndroid Build Coastguard Worker 			    ea_inode->i_links_count == 0)
979*6a54128fSAndroid Build Coastguard Worker 				err = EXT2_ET_EA_INODE_CORRUPTED;
980*6a54128fSAndroid Build Coastguard Worker 			else if ((__u64) ext2fs_file_get_size(ea_file) !=
981*6a54128fSAndroid Build Coastguard Worker 				 entry->e_value_size)
982*6a54128fSAndroid Build Coastguard Worker 				err = EXT2_ET_EA_BAD_VALUE_SIZE;
983*6a54128fSAndroid Build Coastguard Worker 			else
984*6a54128fSAndroid Build Coastguard Worker 				err = ext2fs_file_read(ea_file, x->value,
985*6a54128fSAndroid Build Coastguard Worker 						       entry->e_value_size, 0);
986*6a54128fSAndroid Build Coastguard Worker 			ext2fs_file_close(ea_file);
987*6a54128fSAndroid Build Coastguard Worker 			if (err)
988*6a54128fSAndroid Build Coastguard Worker 				return err;
989*6a54128fSAndroid Build Coastguard Worker 		}
990*6a54128fSAndroid Build Coastguard Worker 
991*6a54128fSAndroid Build Coastguard Worker 		x->ea_ino = entry->e_value_inum;
992*6a54128fSAndroid Build Coastguard Worker 		x->value_len = entry->e_value_size;
993*6a54128fSAndroid Build Coastguard Worker 
994*6a54128fSAndroid Build Coastguard Worker 		/* e_hash may be 0 in older inode's ea */
995*6a54128fSAndroid Build Coastguard Worker 		if (entry->e_hash != 0) {
996*6a54128fSAndroid Build Coastguard Worker 			__u32 hash, signed_hash;
997*6a54128fSAndroid Build Coastguard Worker 
998*6a54128fSAndroid Build Coastguard Worker 			void *data = (entry->e_value_inum != 0) ?
999*6a54128fSAndroid Build Coastguard Worker 					0 : value_start + entry->e_value_offs;
1000*6a54128fSAndroid Build Coastguard Worker 
1001*6a54128fSAndroid Build Coastguard Worker 			err = ext2fs_ext_attr_hash_entry3(handle->fs, entry,
1002*6a54128fSAndroid Build Coastguard Worker 							  data, &hash,
1003*6a54128fSAndroid Build Coastguard Worker 							  &signed_hash);
1004*6a54128fSAndroid Build Coastguard Worker 			if (err)
1005*6a54128fSAndroid Build Coastguard Worker 				return err;
1006*6a54128fSAndroid Build Coastguard Worker 			if ((entry->e_hash != hash) &&
1007*6a54128fSAndroid Build Coastguard Worker 			    (entry->e_hash != signed_hash)) {
1008*6a54128fSAndroid Build Coastguard Worker 				struct ext2_inode child;
1009*6a54128fSAndroid Build Coastguard Worker 
1010*6a54128fSAndroid Build Coastguard Worker 				/* Check whether this is an old Lustre-style
1011*6a54128fSAndroid Build Coastguard Worker 				 * ea_inode reference.
1012*6a54128fSAndroid Build Coastguard Worker 				 */
1013*6a54128fSAndroid Build Coastguard Worker 				err = ext2fs_read_inode(handle->fs,
1014*6a54128fSAndroid Build Coastguard Worker 							entry->e_value_inum,
1015*6a54128fSAndroid Build Coastguard Worker 							&child);
1016*6a54128fSAndroid Build Coastguard Worker 				if (err)
1017*6a54128fSAndroid Build Coastguard Worker 					return err;
1018*6a54128fSAndroid Build Coastguard Worker 				if (child.i_mtime != handle->ino ||
1019*6a54128fSAndroid Build Coastguard Worker 				    child.i_generation != inode->i_generation)
1020*6a54128fSAndroid Build Coastguard Worker 					return EXT2_ET_BAD_EA_HASH;
1021*6a54128fSAndroid Build Coastguard Worker 			}
1022*6a54128fSAndroid Build Coastguard Worker 		}
1023*6a54128fSAndroid Build Coastguard Worker 
1024*6a54128fSAndroid Build Coastguard Worker 		handle->count++;
1025*6a54128fSAndroid Build Coastguard Worker 		entry = EXT2_EXT_ATTR_NEXT(entry);
1026*6a54128fSAndroid Build Coastguard Worker 	}
1027*6a54128fSAndroid Build Coastguard Worker 
1028*6a54128fSAndroid Build Coastguard Worker 	return 0;
1029*6a54128fSAndroid Build Coastguard Worker }
1030*6a54128fSAndroid Build Coastguard Worker 
xattrs_free_keys(struct ext2_xattr_handle * h)1031*6a54128fSAndroid Build Coastguard Worker static void xattrs_free_keys(struct ext2_xattr_handle *h)
1032*6a54128fSAndroid Build Coastguard Worker {
1033*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *a = h->attrs;
1034*6a54128fSAndroid Build Coastguard Worker 	int i;
1035*6a54128fSAndroid Build Coastguard Worker 
1036*6a54128fSAndroid Build Coastguard Worker 	for (i = 0; i < h->capacity; i++) {
1037*6a54128fSAndroid Build Coastguard Worker 		if (a[i].name)
1038*6a54128fSAndroid Build Coastguard Worker 			ext2fs_free_mem(&a[i].name);
1039*6a54128fSAndroid Build Coastguard Worker 		if (a[i].value)
1040*6a54128fSAndroid Build Coastguard Worker 			ext2fs_free_mem(&a[i].value);
1041*6a54128fSAndroid Build Coastguard Worker 	}
1042*6a54128fSAndroid Build Coastguard Worker 	h->count = 0;
1043*6a54128fSAndroid Build Coastguard Worker 	h->ibody_count = 0;
1044*6a54128fSAndroid Build Coastguard Worker }
1045*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattrs_read(struct ext2_xattr_handle * handle)1046*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle)
1047*6a54128fSAndroid Build Coastguard Worker {
1048*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode_large *inode;
1049*6a54128fSAndroid Build Coastguard Worker 	struct ext2_ext_attr_header *header;
1050*6a54128fSAndroid Build Coastguard Worker 	__u32 ea_inode_magic;
1051*6a54128fSAndroid Build Coastguard Worker 	unsigned int storage_size;
1052*6a54128fSAndroid Build Coastguard Worker 	char *start, *block_buf = NULL;
1053*6a54128fSAndroid Build Coastguard Worker 	blk64_t blk;
1054*6a54128fSAndroid Build Coastguard Worker 	size_t i;
1055*6a54128fSAndroid Build Coastguard Worker 	errcode_t err;
1056*6a54128fSAndroid Build Coastguard Worker 
1057*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
1058*6a54128fSAndroid Build Coastguard Worker 	i = EXT2_INODE_SIZE(handle->fs->super);
1059*6a54128fSAndroid Build Coastguard Worker 	if (i < sizeof(*inode))
1060*6a54128fSAndroid Build Coastguard Worker 		i = sizeof(*inode);
1061*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_get_memzero(i, &inode);
1062*6a54128fSAndroid Build Coastguard Worker 	if (err)
1063*6a54128fSAndroid Build Coastguard Worker 		return err;
1064*6a54128fSAndroid Build Coastguard Worker 
1065*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_read_inode_full(handle->fs, handle->ino,
1066*6a54128fSAndroid Build Coastguard Worker 				     (struct ext2_inode *)inode,
1067*6a54128fSAndroid Build Coastguard Worker 				     EXT2_INODE_SIZE(handle->fs->super));
1068*6a54128fSAndroid Build Coastguard Worker 	if (err)
1069*6a54128fSAndroid Build Coastguard Worker 		goto out;
1070*6a54128fSAndroid Build Coastguard Worker 
1071*6a54128fSAndroid Build Coastguard Worker 	xattrs_free_keys(handle);
1072*6a54128fSAndroid Build Coastguard Worker 
1073*6a54128fSAndroid Build Coastguard Worker 	/* Does the inode have space for EA? */
1074*6a54128fSAndroid Build Coastguard Worker 	if (inode->i_extra_isize < sizeof(inode->i_extra_isize) ||
1075*6a54128fSAndroid Build Coastguard Worker 	    EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
1076*6a54128fSAndroid Build Coastguard Worker 						  inode->i_extra_isize +
1077*6a54128fSAndroid Build Coastguard Worker 						  sizeof(__u32))
1078*6a54128fSAndroid Build Coastguard Worker 		goto read_ea_block;
1079*6a54128fSAndroid Build Coastguard Worker 	if (inode->i_extra_isize & 3) {
1080*6a54128fSAndroid Build Coastguard Worker 		err = EXT2_ET_INODE_CORRUPTED;
1081*6a54128fSAndroid Build Coastguard Worker 		goto out;
1082*6a54128fSAndroid Build Coastguard Worker 	}
1083*6a54128fSAndroid Build Coastguard Worker 
1084*6a54128fSAndroid Build Coastguard Worker 	/* Look for EA in the inode */
1085*6a54128fSAndroid Build Coastguard Worker 	memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
1086*6a54128fSAndroid Build Coastguard Worker 	       inode->i_extra_isize, sizeof(__u32));
1087*6a54128fSAndroid Build Coastguard Worker 	if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) {
1088*6a54128fSAndroid Build Coastguard Worker 		storage_size = EXT2_INODE_SIZE(handle->fs->super) -
1089*6a54128fSAndroid Build Coastguard Worker 			EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize -
1090*6a54128fSAndroid Build Coastguard Worker 			sizeof(__u32);
1091*6a54128fSAndroid Build Coastguard Worker 		start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
1092*6a54128fSAndroid Build Coastguard Worker 			inode->i_extra_isize + sizeof(__u32);
1093*6a54128fSAndroid Build Coastguard Worker 
1094*6a54128fSAndroid Build Coastguard Worker 		err = read_xattrs_from_buffer(handle, inode,
1095*6a54128fSAndroid Build Coastguard Worker 					(struct ext2_ext_attr_entry *) start,
1096*6a54128fSAndroid Build Coastguard Worker 					storage_size, start);
1097*6a54128fSAndroid Build Coastguard Worker 		if (err)
1098*6a54128fSAndroid Build Coastguard Worker 			goto out;
1099*6a54128fSAndroid Build Coastguard Worker 
1100*6a54128fSAndroid Build Coastguard Worker 		handle->ibody_count = handle->count;
1101*6a54128fSAndroid Build Coastguard Worker 	}
1102*6a54128fSAndroid Build Coastguard Worker 
1103*6a54128fSAndroid Build Coastguard Worker read_ea_block:
1104*6a54128fSAndroid Build Coastguard Worker 	/* Look for EA in a separate EA block */
1105*6a54128fSAndroid Build Coastguard Worker 	blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode);
1106*6a54128fSAndroid Build Coastguard Worker 	if (blk != 0) {
1107*6a54128fSAndroid Build Coastguard Worker 		if ((blk < handle->fs->super->s_first_data_block) ||
1108*6a54128fSAndroid Build Coastguard Worker 		    (blk >= ext2fs_blocks_count(handle->fs->super))) {
1109*6a54128fSAndroid Build Coastguard Worker 			err = EXT2_ET_BAD_EA_BLOCK_NUM;
1110*6a54128fSAndroid Build Coastguard Worker 			goto out;
1111*6a54128fSAndroid Build Coastguard Worker 		}
1112*6a54128fSAndroid Build Coastguard Worker 
1113*6a54128fSAndroid Build Coastguard Worker 		err = ext2fs_get_mem(handle->fs->blocksize, &block_buf);
1114*6a54128fSAndroid Build Coastguard Worker 		if (err)
1115*6a54128fSAndroid Build Coastguard Worker 			goto out;
1116*6a54128fSAndroid Build Coastguard Worker 
1117*6a54128fSAndroid Build Coastguard Worker 		err = ext2fs_read_ext_attr3(handle->fs, blk, block_buf,
1118*6a54128fSAndroid Build Coastguard Worker 					    handle->ino);
1119*6a54128fSAndroid Build Coastguard Worker 		if (err)
1120*6a54128fSAndroid Build Coastguard Worker 			goto out3;
1121*6a54128fSAndroid Build Coastguard Worker 
1122*6a54128fSAndroid Build Coastguard Worker 		/* We only know how to deal with v2 EA blocks */
1123*6a54128fSAndroid Build Coastguard Worker 		header = (struct ext2_ext_attr_header *) block_buf;
1124*6a54128fSAndroid Build Coastguard Worker 		if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
1125*6a54128fSAndroid Build Coastguard Worker 			err = EXT2_ET_BAD_EA_HEADER;
1126*6a54128fSAndroid Build Coastguard Worker 			goto out3;
1127*6a54128fSAndroid Build Coastguard Worker 		}
1128*6a54128fSAndroid Build Coastguard Worker 
1129*6a54128fSAndroid Build Coastguard Worker 		/* Read EAs */
1130*6a54128fSAndroid Build Coastguard Worker 		storage_size = handle->fs->blocksize -
1131*6a54128fSAndroid Build Coastguard Worker 			sizeof(struct ext2_ext_attr_header);
1132*6a54128fSAndroid Build Coastguard Worker 		start = block_buf + sizeof(struct ext2_ext_attr_header);
1133*6a54128fSAndroid Build Coastguard Worker 		err = read_xattrs_from_buffer(handle, inode,
1134*6a54128fSAndroid Build Coastguard Worker 					(struct ext2_ext_attr_entry *) start,
1135*6a54128fSAndroid Build Coastguard Worker 					storage_size, block_buf);
1136*6a54128fSAndroid Build Coastguard Worker 		if (err)
1137*6a54128fSAndroid Build Coastguard Worker 			goto out3;
1138*6a54128fSAndroid Build Coastguard Worker 
1139*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&block_buf);
1140*6a54128fSAndroid Build Coastguard Worker 	}
1141*6a54128fSAndroid Build Coastguard Worker 
1142*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&block_buf);
1143*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&inode);
1144*6a54128fSAndroid Build Coastguard Worker 	return 0;
1145*6a54128fSAndroid Build Coastguard Worker 
1146*6a54128fSAndroid Build Coastguard Worker out3:
1147*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&block_buf);
1148*6a54128fSAndroid Build Coastguard Worker out:
1149*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&inode);
1150*6a54128fSAndroid Build Coastguard Worker 	return err;
1151*6a54128fSAndroid Build Coastguard Worker }
1152*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattrs_iterate(struct ext2_xattr_handle * h,int (* func)(char * name,char * value,size_t value_len,void * data),void * data)1153*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
1154*6a54128fSAndroid Build Coastguard Worker 				int (*func)(char *name, char *value,
1155*6a54128fSAndroid Build Coastguard Worker 					    size_t value_len, void *data),
1156*6a54128fSAndroid Build Coastguard Worker 				void *data)
1157*6a54128fSAndroid Build Coastguard Worker {
1158*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *x;
1159*6a54128fSAndroid Build Coastguard Worker 	int dirty = 0;
1160*6a54128fSAndroid Build Coastguard Worker 	int ret;
1161*6a54128fSAndroid Build Coastguard Worker 
1162*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
1163*6a54128fSAndroid Build Coastguard Worker 	for (x = h->attrs; x < h->attrs + h->count; x++) {
1164*6a54128fSAndroid Build Coastguard Worker 		ret = func(x->name, x->value, x->value_len, data);
1165*6a54128fSAndroid Build Coastguard Worker 		if (ret & XATTR_CHANGED)
1166*6a54128fSAndroid Build Coastguard Worker 			dirty = 1;
1167*6a54128fSAndroid Build Coastguard Worker 		if (ret & XATTR_ABORT)
1168*6a54128fSAndroid Build Coastguard Worker 			break;
1169*6a54128fSAndroid Build Coastguard Worker 	}
1170*6a54128fSAndroid Build Coastguard Worker 
1171*6a54128fSAndroid Build Coastguard Worker 	if (dirty)
1172*6a54128fSAndroid Build Coastguard Worker 		return ext2fs_xattrs_write(h);
1173*6a54128fSAndroid Build Coastguard Worker 	return 0;
1174*6a54128fSAndroid Build Coastguard Worker }
1175*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattr_get(struct ext2_xattr_handle * h,const char * key,void ** value,size_t * value_len)1176*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
1177*6a54128fSAndroid Build Coastguard Worker 			   void **value, size_t *value_len)
1178*6a54128fSAndroid Build Coastguard Worker {
1179*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *x;
1180*6a54128fSAndroid Build Coastguard Worker 	char *val;
1181*6a54128fSAndroid Build Coastguard Worker 	errcode_t err;
1182*6a54128fSAndroid Build Coastguard Worker 
1183*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
1184*6a54128fSAndroid Build Coastguard Worker 	for (x = h->attrs; x < h->attrs + h->count; x++) {
1185*6a54128fSAndroid Build Coastguard Worker 		if (strcmp(x->name, key))
1186*6a54128fSAndroid Build Coastguard Worker 			continue;
1187*6a54128fSAndroid Build Coastguard Worker 
1188*6a54128fSAndroid Build Coastguard Worker 		if (!(h->flags & XATTR_HANDLE_FLAG_RAW) &&
1189*6a54128fSAndroid Build Coastguard Worker 		    ((strcmp(key, "system.posix_acl_default") == 0) ||
1190*6a54128fSAndroid Build Coastguard Worker 		     (strcmp(key, "system.posix_acl_access") == 0))) {
1191*6a54128fSAndroid Build Coastguard Worker 			err = convert_disk_buffer_to_posix_acl(x->value, x->value_len,
1192*6a54128fSAndroid Build Coastguard Worker 							       value, value_len);
1193*6a54128fSAndroid Build Coastguard Worker 			return err;
1194*6a54128fSAndroid Build Coastguard Worker 		} else {
1195*6a54128fSAndroid Build Coastguard Worker 			err = ext2fs_get_mem(x->value_len, &val);
1196*6a54128fSAndroid Build Coastguard Worker 			if (err)
1197*6a54128fSAndroid Build Coastguard Worker 				return err;
1198*6a54128fSAndroid Build Coastguard Worker 			memcpy(val, x->value, x->value_len);
1199*6a54128fSAndroid Build Coastguard Worker 			*value = val;
1200*6a54128fSAndroid Build Coastguard Worker 			*value_len = x->value_len;
1201*6a54128fSAndroid Build Coastguard Worker 			return 0;
1202*6a54128fSAndroid Build Coastguard Worker 		}
1203*6a54128fSAndroid Build Coastguard Worker 	}
1204*6a54128fSAndroid Build Coastguard Worker 
1205*6a54128fSAndroid Build Coastguard Worker 	return EXT2_ET_EA_KEY_NOT_FOUND;
1206*6a54128fSAndroid Build Coastguard Worker }
1207*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattr_inode_max_size(ext2_filsys fs,ext2_ino_t ino,size_t * size)1208*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino,
1209*6a54128fSAndroid Build Coastguard Worker 				      size_t *size)
1210*6a54128fSAndroid Build Coastguard Worker {
1211*6a54128fSAndroid Build Coastguard Worker 	struct ext2_ext_attr_entry *entry;
1212*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode_large *inode;
1213*6a54128fSAndroid Build Coastguard Worker 	__u32 ea_inode_magic;
1214*6a54128fSAndroid Build Coastguard Worker 	unsigned int minoff;
1215*6a54128fSAndroid Build Coastguard Worker 	char *start;
1216*6a54128fSAndroid Build Coastguard Worker 	size_t i;
1217*6a54128fSAndroid Build Coastguard Worker 	errcode_t err;
1218*6a54128fSAndroid Build Coastguard Worker 
1219*6a54128fSAndroid Build Coastguard Worker 	i = EXT2_INODE_SIZE(fs->super);
1220*6a54128fSAndroid Build Coastguard Worker 	if (i < sizeof(*inode))
1221*6a54128fSAndroid Build Coastguard Worker 		i = sizeof(*inode);
1222*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_get_memzero(i, &inode);
1223*6a54128fSAndroid Build Coastguard Worker 	if (err)
1224*6a54128fSAndroid Build Coastguard Worker 		return err;
1225*6a54128fSAndroid Build Coastguard Worker 
1226*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)inode,
1227*6a54128fSAndroid Build Coastguard Worker 				     EXT2_INODE_SIZE(fs->super));
1228*6a54128fSAndroid Build Coastguard Worker 	if (err)
1229*6a54128fSAndroid Build Coastguard Worker 		goto out;
1230*6a54128fSAndroid Build Coastguard Worker 
1231*6a54128fSAndroid Build Coastguard Worker 	/* Does the inode have size for EA? */
1232*6a54128fSAndroid Build Coastguard Worker 	if (EXT2_INODE_SIZE(fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
1233*6a54128fSAndroid Build Coastguard Worker 						  inode->i_extra_isize +
1234*6a54128fSAndroid Build Coastguard Worker 						  sizeof(__u32)) {
1235*6a54128fSAndroid Build Coastguard Worker 		err = EXT2_ET_INLINE_DATA_NO_SPACE;
1236*6a54128fSAndroid Build Coastguard Worker 		goto out;
1237*6a54128fSAndroid Build Coastguard Worker 	}
1238*6a54128fSAndroid Build Coastguard Worker 
1239*6a54128fSAndroid Build Coastguard Worker 	minoff = EXT2_INODE_SIZE(fs->super) - sizeof(*inode) - sizeof(__u32);
1240*6a54128fSAndroid Build Coastguard Worker 	memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
1241*6a54128fSAndroid Build Coastguard Worker 	       inode->i_extra_isize, sizeof(__u32));
1242*6a54128fSAndroid Build Coastguard Worker 	if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) {
1243*6a54128fSAndroid Build Coastguard Worker 		/* has xattrs.  calculate the size */
1244*6a54128fSAndroid Build Coastguard Worker 		start= ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
1245*6a54128fSAndroid Build Coastguard Worker 			inode->i_extra_isize + sizeof(__u32);
1246*6a54128fSAndroid Build Coastguard Worker 		entry = (struct ext2_ext_attr_entry *) start;
1247*6a54128fSAndroid Build Coastguard Worker 		while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
1248*6a54128fSAndroid Build Coastguard Worker 			if (!entry->e_value_inum && entry->e_value_size) {
1249*6a54128fSAndroid Build Coastguard Worker 				unsigned int offs = entry->e_value_offs;
1250*6a54128fSAndroid Build Coastguard Worker 				if (offs < minoff)
1251*6a54128fSAndroid Build Coastguard Worker 					minoff = offs;
1252*6a54128fSAndroid Build Coastguard Worker 			}
1253*6a54128fSAndroid Build Coastguard Worker 			entry = EXT2_EXT_ATTR_NEXT(entry);
1254*6a54128fSAndroid Build Coastguard Worker 		}
1255*6a54128fSAndroid Build Coastguard Worker 		*size = minoff - ((char *)entry - (char *)start) - sizeof(__u32);
1256*6a54128fSAndroid Build Coastguard Worker 	} else {
1257*6a54128fSAndroid Build Coastguard Worker 		/* no xattr.  return a maximum size */
1258*6a54128fSAndroid Build Coastguard Worker 		*size = EXT2_EXT_ATTR_SIZE(minoff -
1259*6a54128fSAndroid Build Coastguard Worker 					   EXT2_EXT_ATTR_LEN(strlen("data")) -
1260*6a54128fSAndroid Build Coastguard Worker 					   EXT2_EXT_ATTR_ROUND - sizeof(__u32));
1261*6a54128fSAndroid Build Coastguard Worker 	}
1262*6a54128fSAndroid Build Coastguard Worker 
1263*6a54128fSAndroid Build Coastguard Worker out:
1264*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&inode);
1265*6a54128fSAndroid Build Coastguard Worker 	return err;
1266*6a54128fSAndroid Build Coastguard Worker }
1267*6a54128fSAndroid Build Coastguard Worker 
xattr_create_ea_inode(ext2_filsys fs,const void * value,size_t value_len,ext2_ino_t * ea_ino)1268*6a54128fSAndroid Build Coastguard Worker static errcode_t xattr_create_ea_inode(ext2_filsys fs, const void *value,
1269*6a54128fSAndroid Build Coastguard Worker 				       size_t value_len, ext2_ino_t *ea_ino)
1270*6a54128fSAndroid Build Coastguard Worker {
1271*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode inode;
1272*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t ino;
1273*6a54128fSAndroid Build Coastguard Worker 	ext2_file_t file;
1274*6a54128fSAndroid Build Coastguard Worker 	__u32 hash;
1275*6a54128fSAndroid Build Coastguard Worker 	errcode_t ret;
1276*6a54128fSAndroid Build Coastguard Worker 
1277*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_new_inode(fs, 0, 0, 0, &ino);
1278*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1279*6a54128fSAndroid Build Coastguard Worker 		return ret;
1280*6a54128fSAndroid Build Coastguard Worker 
1281*6a54128fSAndroid Build Coastguard Worker 	memset(&inode, 0, sizeof(inode));
1282*6a54128fSAndroid Build Coastguard Worker 	inode.i_flags |= EXT4_EA_INODE_FL;
1283*6a54128fSAndroid Build Coastguard Worker 	if (ext2fs_has_feature_extents(fs->super))
1284*6a54128fSAndroid Build Coastguard Worker 		inode.i_flags |= EXT4_EXTENTS_FL;
1285*6a54128fSAndroid Build Coastguard Worker 	inode.i_size = 0;
1286*6a54128fSAndroid Build Coastguard Worker 	inode.i_mode = LINUX_S_IFREG | 0600;
1287*6a54128fSAndroid Build Coastguard Worker 	inode.i_links_count = 1;
1288*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_write_new_inode(fs, ino, &inode);
1289*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1290*6a54128fSAndroid Build Coastguard Worker 		return ret;
1291*6a54128fSAndroid Build Coastguard Worker 	/*
1292*6a54128fSAndroid Build Coastguard Worker 	 * ref_count and hash utilize inode's i_*time fields.
1293*6a54128fSAndroid Build Coastguard Worker 	 * ext2fs_write_new_inode() call above initializes these fields with
1294*6a54128fSAndroid Build Coastguard Worker 	 * current time. That's why ref count and hash updates are done
1295*6a54128fSAndroid Build Coastguard Worker 	 * separately below.
1296*6a54128fSAndroid Build Coastguard Worker 	 */
1297*6a54128fSAndroid Build Coastguard Worker 	ext2fs_set_ea_inode_ref(&inode, 1);
1298*6a54128fSAndroid Build Coastguard Worker 	hash = ext2fs_crc32c_le(fs->csum_seed, value, value_len);
1299*6a54128fSAndroid Build Coastguard Worker 	ext2fs_set_ea_inode_hash(&inode, hash);
1300*6a54128fSAndroid Build Coastguard Worker 
1301*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_write_inode(fs, ino, &inode);
1302*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1303*6a54128fSAndroid Build Coastguard Worker 		return ret;
1304*6a54128fSAndroid Build Coastguard Worker 
1305*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &file);
1306*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1307*6a54128fSAndroid Build Coastguard Worker 		return ret;
1308*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_file_write(file, value, value_len, NULL);
1309*6a54128fSAndroid Build Coastguard Worker 	ext2fs_file_close(file);
1310*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1311*6a54128fSAndroid Build Coastguard Worker 		return ret;
1312*6a54128fSAndroid Build Coastguard Worker 
1313*6a54128fSAndroid Build Coastguard Worker 	ext2fs_inode_alloc_stats2(fs, ino, 1 /* inuse */, 0 /* isdir */);
1314*6a54128fSAndroid Build Coastguard Worker 
1315*6a54128fSAndroid Build Coastguard Worker 	*ea_ino = ino;
1316*6a54128fSAndroid Build Coastguard Worker 	return 0;
1317*6a54128fSAndroid Build Coastguard Worker }
1318*6a54128fSAndroid Build Coastguard Worker 
xattr_inode_dec_ref(ext2_filsys fs,ext2_ino_t ino)1319*6a54128fSAndroid Build Coastguard Worker static errcode_t xattr_inode_dec_ref(ext2_filsys fs, ext2_ino_t ino)
1320*6a54128fSAndroid Build Coastguard Worker {
1321*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode_large inode;
1322*6a54128fSAndroid Build Coastguard Worker 	__u64 ref_count;
1323*6a54128fSAndroid Build Coastguard Worker 	errcode_t ret;
1324*6a54128fSAndroid Build Coastguard Worker 
1325*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1326*6a54128fSAndroid Build Coastguard Worker 				     sizeof(inode));
1327*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1328*6a54128fSAndroid Build Coastguard Worker 		goto out;
1329*6a54128fSAndroid Build Coastguard Worker 
1330*6a54128fSAndroid Build Coastguard Worker 	ref_count = ext2fs_get_ea_inode_ref(EXT2_INODE(&inode));
1331*6a54128fSAndroid Build Coastguard Worker 	ref_count--;
1332*6a54128fSAndroid Build Coastguard Worker 	ext2fs_set_ea_inode_ref(EXT2_INODE(&inode), ref_count);
1333*6a54128fSAndroid Build Coastguard Worker 
1334*6a54128fSAndroid Build Coastguard Worker 	if (ref_count)
1335*6a54128fSAndroid Build Coastguard Worker 		goto write_out;
1336*6a54128fSAndroid Build Coastguard Worker 
1337*6a54128fSAndroid Build Coastguard Worker 	inode.i_links_count = 0;
1338*6a54128fSAndroid Build Coastguard Worker 	inode.i_dtime = fs->now ? fs->now : time(0);
1339*6a54128fSAndroid Build Coastguard Worker 
1340*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_free_ext_attr(fs, ino, &inode);
1341*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1342*6a54128fSAndroid Build Coastguard Worker 		goto write_out;
1343*6a54128fSAndroid Build Coastguard Worker 
1344*6a54128fSAndroid Build Coastguard Worker 	if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) {
1345*6a54128fSAndroid Build Coastguard Worker 		ret = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL,
1346*6a54128fSAndroid Build Coastguard Worker 				   0, ~0ULL);
1347*6a54128fSAndroid Build Coastguard Worker 		if (ret)
1348*6a54128fSAndroid Build Coastguard Worker 			goto out;
1349*6a54128fSAndroid Build Coastguard Worker 	}
1350*6a54128fSAndroid Build Coastguard Worker 
1351*6a54128fSAndroid Build Coastguard Worker 	ext2fs_inode_alloc_stats2(fs, ino, -1 /* inuse */, 0 /* is_dir */);
1352*6a54128fSAndroid Build Coastguard Worker 
1353*6a54128fSAndroid Build Coastguard Worker write_out:
1354*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1355*6a54128fSAndroid Build Coastguard Worker 				      sizeof(inode));
1356*6a54128fSAndroid Build Coastguard Worker out:
1357*6a54128fSAndroid Build Coastguard Worker 	return ret;
1358*6a54128fSAndroid Build Coastguard Worker }
1359*6a54128fSAndroid Build Coastguard Worker 
xattr_update_entry(ext2_filsys fs,struct ext2_xattr * x,const char * name,const char * short_name,int index,const void * value,size_t value_len,int in_inode)1360*6a54128fSAndroid Build Coastguard Worker static errcode_t xattr_update_entry(ext2_filsys fs, struct ext2_xattr *x,
1361*6a54128fSAndroid Build Coastguard Worker 				    const char *name, const char *short_name,
1362*6a54128fSAndroid Build Coastguard Worker 				    int index, const void *value,
1363*6a54128fSAndroid Build Coastguard Worker 				    size_t value_len, int in_inode)
1364*6a54128fSAndroid Build Coastguard Worker {
1365*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t ea_ino = 0;
1366*6a54128fSAndroid Build Coastguard Worker 	void *new_value = NULL;
1367*6a54128fSAndroid Build Coastguard Worker 	char *new_name = NULL;
1368*6a54128fSAndroid Build Coastguard Worker 	int name_len;
1369*6a54128fSAndroid Build Coastguard Worker 	errcode_t ret;
1370*6a54128fSAndroid Build Coastguard Worker 
1371*6a54128fSAndroid Build Coastguard Worker 	if (!x->name) {
1372*6a54128fSAndroid Build Coastguard Worker 		name_len = strlen(name);
1373*6a54128fSAndroid Build Coastguard Worker 		ret = ext2fs_get_mem(name_len + 1, &new_name);
1374*6a54128fSAndroid Build Coastguard Worker 		if (ret)
1375*6a54128fSAndroid Build Coastguard Worker 			goto fail;
1376*6a54128fSAndroid Build Coastguard Worker 		memcpy(new_name, name, name_len + 1);
1377*6a54128fSAndroid Build Coastguard Worker 	}
1378*6a54128fSAndroid Build Coastguard Worker 
1379*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_get_mem(value_len, &new_value);
1380*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1381*6a54128fSAndroid Build Coastguard Worker 		goto fail;
1382*6a54128fSAndroid Build Coastguard Worker 	memcpy(new_value, value, value_len);
1383*6a54128fSAndroid Build Coastguard Worker 
1384*6a54128fSAndroid Build Coastguard Worker 	if (in_inode) {
1385*6a54128fSAndroid Build Coastguard Worker 		ret = xattr_create_ea_inode(fs, value, value_len, &ea_ino);
1386*6a54128fSAndroid Build Coastguard Worker 		if (ret)
1387*6a54128fSAndroid Build Coastguard Worker 			goto fail;
1388*6a54128fSAndroid Build Coastguard Worker 	}
1389*6a54128fSAndroid Build Coastguard Worker 
1390*6a54128fSAndroid Build Coastguard Worker 	if (x->ea_ino) {
1391*6a54128fSAndroid Build Coastguard Worker 		ret = xattr_inode_dec_ref(fs, x->ea_ino);
1392*6a54128fSAndroid Build Coastguard Worker 		if (ret)
1393*6a54128fSAndroid Build Coastguard Worker 			goto fail;
1394*6a54128fSAndroid Build Coastguard Worker 	}
1395*6a54128fSAndroid Build Coastguard Worker 
1396*6a54128fSAndroid Build Coastguard Worker 	if (!x->name) {
1397*6a54128fSAndroid Build Coastguard Worker 		x->name = new_name;
1398*6a54128fSAndroid Build Coastguard Worker 		x->short_name = new_name + (short_name  - name);
1399*6a54128fSAndroid Build Coastguard Worker 	}
1400*6a54128fSAndroid Build Coastguard Worker 	x->name_index = index;
1401*6a54128fSAndroid Build Coastguard Worker 
1402*6a54128fSAndroid Build Coastguard Worker 	if (x->value)
1403*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&x->value);
1404*6a54128fSAndroid Build Coastguard Worker 	x->value = new_value;
1405*6a54128fSAndroid Build Coastguard Worker 	x->value_len = value_len;
1406*6a54128fSAndroid Build Coastguard Worker 	x->ea_ino = ea_ino;
1407*6a54128fSAndroid Build Coastguard Worker 	return 0;
1408*6a54128fSAndroid Build Coastguard Worker fail:
1409*6a54128fSAndroid Build Coastguard Worker 	if (new_name)
1410*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&new_name);
1411*6a54128fSAndroid Build Coastguard Worker 	if (new_value)
1412*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&new_value);
1413*6a54128fSAndroid Build Coastguard Worker 	if (ea_ino)
1414*6a54128fSAndroid Build Coastguard Worker 		xattr_inode_dec_ref(fs, ea_ino);
1415*6a54128fSAndroid Build Coastguard Worker 	return ret;
1416*6a54128fSAndroid Build Coastguard Worker }
1417*6a54128fSAndroid Build Coastguard Worker 
xattr_find_position(struct ext2_xattr * attrs,int count,const char * shortname,int name_idx)1418*6a54128fSAndroid Build Coastguard Worker static int xattr_find_position(struct ext2_xattr *attrs, int count,
1419*6a54128fSAndroid Build Coastguard Worker 			       const char *shortname, int name_idx)
1420*6a54128fSAndroid Build Coastguard Worker {
1421*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *x;
1422*6a54128fSAndroid Build Coastguard Worker 	int i;
1423*6a54128fSAndroid Build Coastguard Worker 	int shortname_len, x_shortname_len;
1424*6a54128fSAndroid Build Coastguard Worker 
1425*6a54128fSAndroid Build Coastguard Worker 	shortname_len = strlen(shortname);
1426*6a54128fSAndroid Build Coastguard Worker 
1427*6a54128fSAndroid Build Coastguard Worker 	for (i = 0, x = attrs; i < count; i++, x++) {
1428*6a54128fSAndroid Build Coastguard Worker 		if (name_idx < x->name_index)
1429*6a54128fSAndroid Build Coastguard Worker 			break;
1430*6a54128fSAndroid Build Coastguard Worker 		if (name_idx > x->name_index)
1431*6a54128fSAndroid Build Coastguard Worker 			continue;
1432*6a54128fSAndroid Build Coastguard Worker 
1433*6a54128fSAndroid Build Coastguard Worker 		x_shortname_len = strlen(x->short_name);
1434*6a54128fSAndroid Build Coastguard Worker 		if (shortname_len < x_shortname_len)
1435*6a54128fSAndroid Build Coastguard Worker 			break;
1436*6a54128fSAndroid Build Coastguard Worker 		if (shortname_len > x_shortname_len)
1437*6a54128fSAndroid Build Coastguard Worker 			continue;
1438*6a54128fSAndroid Build Coastguard Worker 
1439*6a54128fSAndroid Build Coastguard Worker 		if (memcmp(shortname, x->short_name, shortname_len) <= 0)
1440*6a54128fSAndroid Build Coastguard Worker 			break;
1441*6a54128fSAndroid Build Coastguard Worker 	}
1442*6a54128fSAndroid Build Coastguard Worker 	return i;
1443*6a54128fSAndroid Build Coastguard Worker }
1444*6a54128fSAndroid Build Coastguard Worker 
xattr_array_update(struct ext2_xattr_handle * h,const char * name,const void * value,size_t value_len,int ibody_free,int block_free,int old_idx,int in_inode)1445*6a54128fSAndroid Build Coastguard Worker static errcode_t xattr_array_update(struct ext2_xattr_handle *h,
1446*6a54128fSAndroid Build Coastguard Worker 				    const char *name,
1447*6a54128fSAndroid Build Coastguard Worker 				    const void *value, size_t value_len,
1448*6a54128fSAndroid Build Coastguard Worker 				    int ibody_free, int block_free,
1449*6a54128fSAndroid Build Coastguard Worker 				    int old_idx, int in_inode)
1450*6a54128fSAndroid Build Coastguard Worker {
1451*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr tmp;
1452*6a54128fSAndroid Build Coastguard Worker 	int add_to_ibody;
1453*6a54128fSAndroid Build Coastguard Worker 	int needed;
1454*6a54128fSAndroid Build Coastguard Worker 	int name_len, name_idx = 0;
1455*6a54128fSAndroid Build Coastguard Worker 	const char *shortname = name;
1456*6a54128fSAndroid Build Coastguard Worker 	int new_idx;
1457*6a54128fSAndroid Build Coastguard Worker 	int ret;
1458*6a54128fSAndroid Build Coastguard Worker 
1459*6a54128fSAndroid Build Coastguard Worker 	find_ea_index(name, &shortname, &name_idx);
1460*6a54128fSAndroid Build Coastguard Worker 	name_len = strlen(shortname);
1461*6a54128fSAndroid Build Coastguard Worker 
1462*6a54128fSAndroid Build Coastguard Worker 	needed = EXT2_EXT_ATTR_LEN(name_len);
1463*6a54128fSAndroid Build Coastguard Worker 	if (!in_inode)
1464*6a54128fSAndroid Build Coastguard Worker 		needed += EXT2_EXT_ATTR_SIZE(value_len);
1465*6a54128fSAndroid Build Coastguard Worker 
1466*6a54128fSAndroid Build Coastguard Worker 	if (old_idx >= 0 && old_idx < h->ibody_count) {
1467*6a54128fSAndroid Build Coastguard Worker 		ibody_free += EXT2_EXT_ATTR_LEN(name_len);
1468*6a54128fSAndroid Build Coastguard Worker 		if (!h->attrs[old_idx].ea_ino)
1469*6a54128fSAndroid Build Coastguard Worker 			ibody_free += EXT2_EXT_ATTR_SIZE(
1470*6a54128fSAndroid Build Coastguard Worker 						h->attrs[old_idx].value_len);
1471*6a54128fSAndroid Build Coastguard Worker 	}
1472*6a54128fSAndroid Build Coastguard Worker 
1473*6a54128fSAndroid Build Coastguard Worker 	if (needed <= ibody_free) {
1474*6a54128fSAndroid Build Coastguard Worker 		if (old_idx < 0) {
1475*6a54128fSAndroid Build Coastguard Worker 			new_idx = h->ibody_count;
1476*6a54128fSAndroid Build Coastguard Worker 			add_to_ibody = 1;
1477*6a54128fSAndroid Build Coastguard Worker 			goto add_new;
1478*6a54128fSAndroid Build Coastguard Worker 		}
1479*6a54128fSAndroid Build Coastguard Worker 
1480*6a54128fSAndroid Build Coastguard Worker 		/* Update the existing entry. */
1481*6a54128fSAndroid Build Coastguard Worker 		ret = xattr_update_entry(h->fs, &h->attrs[old_idx], name,
1482*6a54128fSAndroid Build Coastguard Worker 					 shortname, name_idx, value,
1483*6a54128fSAndroid Build Coastguard Worker 					 value_len, in_inode);
1484*6a54128fSAndroid Build Coastguard Worker 		if (ret)
1485*6a54128fSAndroid Build Coastguard Worker 			return ret;
1486*6a54128fSAndroid Build Coastguard Worker 		if (h->ibody_count <= old_idx) {
1487*6a54128fSAndroid Build Coastguard Worker 			/* Move entry from block to the end of ibody. */
1488*6a54128fSAndroid Build Coastguard Worker 			tmp = h->attrs[old_idx];
1489*6a54128fSAndroid Build Coastguard Worker 			memmove(h->attrs + h->ibody_count + 1,
1490*6a54128fSAndroid Build Coastguard Worker 				h->attrs + h->ibody_count,
1491*6a54128fSAndroid Build Coastguard Worker 				(old_idx - h->ibody_count) * sizeof(*h->attrs));
1492*6a54128fSAndroid Build Coastguard Worker 			h->attrs[h->ibody_count] = tmp;
1493*6a54128fSAndroid Build Coastguard Worker 			h->ibody_count++;
1494*6a54128fSAndroid Build Coastguard Worker 		}
1495*6a54128fSAndroid Build Coastguard Worker 		return 0;
1496*6a54128fSAndroid Build Coastguard Worker 	}
1497*6a54128fSAndroid Build Coastguard Worker 
1498*6a54128fSAndroid Build Coastguard Worker 	if (h->ibody_count <= old_idx) {
1499*6a54128fSAndroid Build Coastguard Worker 		block_free += EXT2_EXT_ATTR_LEN(name_len);
1500*6a54128fSAndroid Build Coastguard Worker 		if (!h->attrs[old_idx].ea_ino)
1501*6a54128fSAndroid Build Coastguard Worker 			block_free +=
1502*6a54128fSAndroid Build Coastguard Worker 				EXT2_EXT_ATTR_SIZE(h->attrs[old_idx].value_len);
1503*6a54128fSAndroid Build Coastguard Worker 	}
1504*6a54128fSAndroid Build Coastguard Worker 
1505*6a54128fSAndroid Build Coastguard Worker 	if (needed > block_free)
1506*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_EA_NO_SPACE;
1507*6a54128fSAndroid Build Coastguard Worker 
1508*6a54128fSAndroid Build Coastguard Worker 	if (old_idx >= 0) {
1509*6a54128fSAndroid Build Coastguard Worker 		/* Update the existing entry. */
1510*6a54128fSAndroid Build Coastguard Worker 		ret = xattr_update_entry(h->fs, &h->attrs[old_idx], name,
1511*6a54128fSAndroid Build Coastguard Worker 					 shortname, name_idx, value,
1512*6a54128fSAndroid Build Coastguard Worker 					 value_len, in_inode);
1513*6a54128fSAndroid Build Coastguard Worker 		if (ret)
1514*6a54128fSAndroid Build Coastguard Worker 			return ret;
1515*6a54128fSAndroid Build Coastguard Worker 		if (old_idx < h->ibody_count) {
1516*6a54128fSAndroid Build Coastguard Worker 			/*
1517*6a54128fSAndroid Build Coastguard Worker 			 * Move entry from ibody to the block. Note that
1518*6a54128fSAndroid Build Coastguard Worker 			 * entries in the block are sorted.
1519*6a54128fSAndroid Build Coastguard Worker 			 */
1520*6a54128fSAndroid Build Coastguard Worker 			new_idx = xattr_find_position(h->attrs + h->ibody_count,
1521*6a54128fSAndroid Build Coastguard Worker 						      h->count - h->ibody_count,
1522*6a54128fSAndroid Build Coastguard Worker 						      shortname, name_idx);
1523*6a54128fSAndroid Build Coastguard Worker 			new_idx += h->ibody_count - 1;
1524*6a54128fSAndroid Build Coastguard Worker 			tmp = h->attrs[old_idx];
1525*6a54128fSAndroid Build Coastguard Worker 			memmove(h->attrs + old_idx, h->attrs + old_idx + 1,
1526*6a54128fSAndroid Build Coastguard Worker 				(new_idx - old_idx) * sizeof(*h->attrs));
1527*6a54128fSAndroid Build Coastguard Worker 			h->attrs[new_idx] = tmp;
1528*6a54128fSAndroid Build Coastguard Worker 			h->ibody_count--;
1529*6a54128fSAndroid Build Coastguard Worker 		}
1530*6a54128fSAndroid Build Coastguard Worker 		return 0;
1531*6a54128fSAndroid Build Coastguard Worker 	}
1532*6a54128fSAndroid Build Coastguard Worker 
1533*6a54128fSAndroid Build Coastguard Worker 	new_idx = xattr_find_position(h->attrs + h->ibody_count,
1534*6a54128fSAndroid Build Coastguard Worker 				      h->count - h->ibody_count,
1535*6a54128fSAndroid Build Coastguard Worker 				      shortname, name_idx);
1536*6a54128fSAndroid Build Coastguard Worker 	new_idx += h->ibody_count;
1537*6a54128fSAndroid Build Coastguard Worker 	add_to_ibody = 0;
1538*6a54128fSAndroid Build Coastguard Worker 
1539*6a54128fSAndroid Build Coastguard Worker add_new:
1540*6a54128fSAndroid Build Coastguard Worker 	if (h->count == h->capacity) {
1541*6a54128fSAndroid Build Coastguard Worker 		ret = ext2fs_xattrs_expand(h, 4);
1542*6a54128fSAndroid Build Coastguard Worker 		if (ret)
1543*6a54128fSAndroid Build Coastguard Worker 			return ret;
1544*6a54128fSAndroid Build Coastguard Worker 	}
1545*6a54128fSAndroid Build Coastguard Worker 
1546*6a54128fSAndroid Build Coastguard Worker 	ret = xattr_update_entry(h->fs, &h->attrs[h->count], name, shortname,
1547*6a54128fSAndroid Build Coastguard Worker 				 name_idx, value, value_len, in_inode);
1548*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1549*6a54128fSAndroid Build Coastguard Worker 		return ret;
1550*6a54128fSAndroid Build Coastguard Worker 
1551*6a54128fSAndroid Build Coastguard Worker 	tmp = h->attrs[h->count];
1552*6a54128fSAndroid Build Coastguard Worker 	memmove(h->attrs + new_idx + 1, h->attrs + new_idx,
1553*6a54128fSAndroid Build Coastguard Worker 		(h->count - new_idx)*sizeof(*h->attrs));
1554*6a54128fSAndroid Build Coastguard Worker 	h->attrs[new_idx] = tmp;
1555*6a54128fSAndroid Build Coastguard Worker 	if (add_to_ibody)
1556*6a54128fSAndroid Build Coastguard Worker 		h->ibody_count++;
1557*6a54128fSAndroid Build Coastguard Worker 	h->count++;
1558*6a54128fSAndroid Build Coastguard Worker 	return 0;
1559*6a54128fSAndroid Build Coastguard Worker }
1560*6a54128fSAndroid Build Coastguard Worker 
space_used(struct ext2_xattr * attrs,int count)1561*6a54128fSAndroid Build Coastguard Worker static int space_used(struct ext2_xattr *attrs, int count)
1562*6a54128fSAndroid Build Coastguard Worker {
1563*6a54128fSAndroid Build Coastguard Worker 	int total = 0;
1564*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *x;
1565*6a54128fSAndroid Build Coastguard Worker 	int i, len;
1566*6a54128fSAndroid Build Coastguard Worker 
1567*6a54128fSAndroid Build Coastguard Worker 	for (i = 0, x = attrs; i < count; i++, x++) {
1568*6a54128fSAndroid Build Coastguard Worker 		len = strlen(x->short_name);
1569*6a54128fSAndroid Build Coastguard Worker 		total += EXT2_EXT_ATTR_LEN(len);
1570*6a54128fSAndroid Build Coastguard Worker 		if (!x->ea_ino)
1571*6a54128fSAndroid Build Coastguard Worker 			total += EXT2_EXT_ATTR_SIZE(x->value_len);
1572*6a54128fSAndroid Build Coastguard Worker 	}
1573*6a54128fSAndroid Build Coastguard Worker 	return total;
1574*6a54128fSAndroid Build Coastguard Worker }
1575*6a54128fSAndroid Build Coastguard Worker 
1576*6a54128fSAndroid Build Coastguard Worker /*
1577*6a54128fSAndroid Build Coastguard Worker  * The minimum size of EA value when you start storing it in an external inode
1578*6a54128fSAndroid Build Coastguard Worker  * size of block - size of header - size of 1 entry - 4 null bytes
1579*6a54128fSAndroid Build Coastguard Worker  */
1580*6a54128fSAndroid Build Coastguard Worker #define EXT4_XATTR_MIN_LARGE_EA_SIZE(b)	\
1581*6a54128fSAndroid Build Coastguard Worker 	((b) - EXT2_EXT_ATTR_LEN(3) - sizeof(struct ext2_ext_attr_header) - 4)
1582*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattr_set(struct ext2_xattr_handle * h,const char * name,const void * value,size_t value_len)1583*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *h,
1584*6a54128fSAndroid Build Coastguard Worker 			   const char *name,
1585*6a54128fSAndroid Build Coastguard Worker 			   const void *value,
1586*6a54128fSAndroid Build Coastguard Worker 			   size_t value_len)
1587*6a54128fSAndroid Build Coastguard Worker {
1588*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys fs = h->fs;
1589*6a54128fSAndroid Build Coastguard Worker 	const int inode_size = EXT2_INODE_SIZE(fs->super);
1590*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode_large *inode = NULL;
1591*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *x;
1592*6a54128fSAndroid Build Coastguard Worker 	char *new_value;
1593*6a54128fSAndroid Build Coastguard Worker 	int ibody_free, block_free;
1594*6a54128fSAndroid Build Coastguard Worker 	int in_inode = 0;
1595*6a54128fSAndroid Build Coastguard Worker 	int old_idx = -1;
1596*6a54128fSAndroid Build Coastguard Worker 	int extra_isize;
1597*6a54128fSAndroid Build Coastguard Worker 	errcode_t ret;
1598*6a54128fSAndroid Build Coastguard Worker 
1599*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
1600*6a54128fSAndroid Build Coastguard Worker 
1601*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_get_mem(value_len, &new_value);
1602*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1603*6a54128fSAndroid Build Coastguard Worker 		return ret;
1604*6a54128fSAndroid Build Coastguard Worker 	if (!(h->flags & XATTR_HANDLE_FLAG_RAW) &&
1605*6a54128fSAndroid Build Coastguard Worker 	    ((strcmp(name, "system.posix_acl_default") == 0) ||
1606*6a54128fSAndroid Build Coastguard Worker 	     (strcmp(name, "system.posix_acl_access") == 0))) {
1607*6a54128fSAndroid Build Coastguard Worker 		ret = convert_posix_acl_to_disk_buffer(value, value_len,
1608*6a54128fSAndroid Build Coastguard Worker 						       new_value, &value_len);
1609*6a54128fSAndroid Build Coastguard Worker 		if (ret)
1610*6a54128fSAndroid Build Coastguard Worker 			goto out;
1611*6a54128fSAndroid Build Coastguard Worker 	} else if (value_len)
1612*6a54128fSAndroid Build Coastguard Worker 		memcpy(new_value, value, value_len);
1613*6a54128fSAndroid Build Coastguard Worker 
1614*6a54128fSAndroid Build Coastguard Worker 	/* Imitate kernel behavior by skipping update if value is the same. */
1615*6a54128fSAndroid Build Coastguard Worker 	for (x = h->attrs; x < h->attrs + h->count; x++) {
1616*6a54128fSAndroid Build Coastguard Worker 		if (!strcmp(x->name, name)) {
1617*6a54128fSAndroid Build Coastguard Worker 			if (!x->ea_ino && x->value_len == value_len &&
1618*6a54128fSAndroid Build Coastguard Worker 			    (!value_len ||
1619*6a54128fSAndroid Build Coastguard Worker 			     !memcmp(x->value, new_value, value_len))) {
1620*6a54128fSAndroid Build Coastguard Worker 				ret = 0;
1621*6a54128fSAndroid Build Coastguard Worker 				goto out;
1622*6a54128fSAndroid Build Coastguard Worker 			}
1623*6a54128fSAndroid Build Coastguard Worker 			old_idx = x - h->attrs;
1624*6a54128fSAndroid Build Coastguard Worker 			break;
1625*6a54128fSAndroid Build Coastguard Worker 		}
1626*6a54128fSAndroid Build Coastguard Worker 	}
1627*6a54128fSAndroid Build Coastguard Worker 
1628*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_get_memzero(inode_size, &inode);
1629*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1630*6a54128fSAndroid Build Coastguard Worker 		goto out;
1631*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_read_inode_full(fs, h->ino,
1632*6a54128fSAndroid Build Coastguard Worker 				     (struct ext2_inode *)inode,
1633*6a54128fSAndroid Build Coastguard Worker 				     inode_size);
1634*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1635*6a54128fSAndroid Build Coastguard Worker 		goto out;
1636*6a54128fSAndroid Build Coastguard Worker 	if (inode_size > EXT2_GOOD_OLD_INODE_SIZE) {
1637*6a54128fSAndroid Build Coastguard Worker 		extra_isize = inode->i_extra_isize;
1638*6a54128fSAndroid Build Coastguard Worker 		if (extra_isize == 0) {
1639*6a54128fSAndroid Build Coastguard Worker 			extra_isize = fs->super->s_want_extra_isize;
1640*6a54128fSAndroid Build Coastguard Worker 			if (extra_isize == 0)
1641*6a54128fSAndroid Build Coastguard Worker 				extra_isize = sizeof(__u32);
1642*6a54128fSAndroid Build Coastguard Worker 		}
1643*6a54128fSAndroid Build Coastguard Worker 		ibody_free = inode_size - EXT2_GOOD_OLD_INODE_SIZE;
1644*6a54128fSAndroid Build Coastguard Worker 		ibody_free -= extra_isize;
1645*6a54128fSAndroid Build Coastguard Worker 		/* Extended attribute magic and final null entry. */
1646*6a54128fSAndroid Build Coastguard Worker 		ibody_free -= sizeof(__u32) * 2;
1647*6a54128fSAndroid Build Coastguard Worker 		ibody_free -= space_used(h->attrs, h->ibody_count);
1648*6a54128fSAndroid Build Coastguard Worker 	} else
1649*6a54128fSAndroid Build Coastguard Worker 		ibody_free = 0;
1650*6a54128fSAndroid Build Coastguard Worker 
1651*6a54128fSAndroid Build Coastguard Worker 	/* Inline data can only go to ibody. */
1652*6a54128fSAndroid Build Coastguard Worker 	if (strcmp(name, "system.data") == 0) {
1653*6a54128fSAndroid Build Coastguard Worker 		if (h->ibody_count <= old_idx) {
1654*6a54128fSAndroid Build Coastguard Worker 			ret = EXT2_ET_FILESYSTEM_CORRUPTED;
1655*6a54128fSAndroid Build Coastguard Worker 			goto out;
1656*6a54128fSAndroid Build Coastguard Worker 		}
1657*6a54128fSAndroid Build Coastguard Worker 		ret = xattr_array_update(h, name, new_value, value_len,
1658*6a54128fSAndroid Build Coastguard Worker 					 ibody_free,
1659*6a54128fSAndroid Build Coastguard Worker 					 0 /* block_free */, old_idx,
1660*6a54128fSAndroid Build Coastguard Worker 					 0 /* in_inode */);
1661*6a54128fSAndroid Build Coastguard Worker 		if (ret)
1662*6a54128fSAndroid Build Coastguard Worker 			goto out;
1663*6a54128fSAndroid Build Coastguard Worker 		goto write_out;
1664*6a54128fSAndroid Build Coastguard Worker 	}
1665*6a54128fSAndroid Build Coastguard Worker 
1666*6a54128fSAndroid Build Coastguard Worker 	block_free = fs->blocksize;
1667*6a54128fSAndroid Build Coastguard Worker 	block_free -= sizeof(struct ext2_ext_attr_header);
1668*6a54128fSAndroid Build Coastguard Worker 	/* Final null entry. */
1669*6a54128fSAndroid Build Coastguard Worker 	block_free -= sizeof(__u32);
1670*6a54128fSAndroid Build Coastguard Worker 	block_free -= space_used(h->attrs + h->ibody_count,
1671*6a54128fSAndroid Build Coastguard Worker 				 h->count - h->ibody_count);
1672*6a54128fSAndroid Build Coastguard Worker 
1673*6a54128fSAndroid Build Coastguard Worker 	if (ext2fs_has_feature_ea_inode(fs->super) &&
1674*6a54128fSAndroid Build Coastguard Worker 	    value_len > EXT4_XATTR_MIN_LARGE_EA_SIZE(fs->blocksize))
1675*6a54128fSAndroid Build Coastguard Worker 		in_inode = 1;
1676*6a54128fSAndroid Build Coastguard Worker 
1677*6a54128fSAndroid Build Coastguard Worker 	ret = xattr_array_update(h, name, new_value, value_len, ibody_free,
1678*6a54128fSAndroid Build Coastguard Worker 				 block_free, old_idx, in_inode);
1679*6a54128fSAndroid Build Coastguard Worker 	if (ret == EXT2_ET_EA_NO_SPACE && !in_inode &&
1680*6a54128fSAndroid Build Coastguard Worker 	    ext2fs_has_feature_ea_inode(fs->super))
1681*6a54128fSAndroid Build Coastguard Worker 		ret = xattr_array_update(h, name, new_value, value_len,
1682*6a54128fSAndroid Build Coastguard Worker 			ibody_free, block_free, old_idx, 1 /* in_inode */);
1683*6a54128fSAndroid Build Coastguard Worker 	if (ret)
1684*6a54128fSAndroid Build Coastguard Worker 		goto out;
1685*6a54128fSAndroid Build Coastguard Worker 
1686*6a54128fSAndroid Build Coastguard Worker write_out:
1687*6a54128fSAndroid Build Coastguard Worker 	ret = ext2fs_xattrs_write(h);
1688*6a54128fSAndroid Build Coastguard Worker out:
1689*6a54128fSAndroid Build Coastguard Worker 	if (inode)
1690*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&inode);
1691*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&new_value);
1692*6a54128fSAndroid Build Coastguard Worker 	return ret;
1693*6a54128fSAndroid Build Coastguard Worker }
1694*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattr_remove(struct ext2_xattr_handle * handle,const char * key)1695*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
1696*6a54128fSAndroid Build Coastguard Worker 			      const char *key)
1697*6a54128fSAndroid Build Coastguard Worker {
1698*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *x;
1699*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr *end = handle->attrs + handle->count;
1700*6a54128fSAndroid Build Coastguard Worker 
1701*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
1702*6a54128fSAndroid Build Coastguard Worker 	for (x = handle->attrs; x < end; x++) {
1703*6a54128fSAndroid Build Coastguard Worker 		if (strcmp(x->name, key) == 0) {
1704*6a54128fSAndroid Build Coastguard Worker 			ext2fs_free_mem(&x->name);
1705*6a54128fSAndroid Build Coastguard Worker 			ext2fs_free_mem(&x->value);
1706*6a54128fSAndroid Build Coastguard Worker 			if (x->ea_ino)
1707*6a54128fSAndroid Build Coastguard Worker 				xattr_inode_dec_ref(handle->fs, x->ea_ino);
1708*6a54128fSAndroid Build Coastguard Worker 			memmove(x, x + 1, (end - x - 1)*sizeof(*x));
1709*6a54128fSAndroid Build Coastguard Worker 			memset(end - 1, 0, sizeof(*end));
1710*6a54128fSAndroid Build Coastguard Worker 			if (x < handle->attrs + handle->ibody_count)
1711*6a54128fSAndroid Build Coastguard Worker 				handle->ibody_count--;
1712*6a54128fSAndroid Build Coastguard Worker 			handle->count--;
1713*6a54128fSAndroid Build Coastguard Worker 			return ext2fs_xattrs_write(handle);
1714*6a54128fSAndroid Build Coastguard Worker 		}
1715*6a54128fSAndroid Build Coastguard Worker 	}
1716*6a54128fSAndroid Build Coastguard Worker 
1717*6a54128fSAndroid Build Coastguard Worker 	/* no key found, success! */
1718*6a54128fSAndroid Build Coastguard Worker 	return 0;
1719*6a54128fSAndroid Build Coastguard Worker }
1720*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattrs_open(ext2_filsys fs,ext2_ino_t ino,struct ext2_xattr_handle ** handle)1721*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
1722*6a54128fSAndroid Build Coastguard Worker 			     struct ext2_xattr_handle **handle)
1723*6a54128fSAndroid Build Coastguard Worker {
1724*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr_handle *h;
1725*6a54128fSAndroid Build Coastguard Worker 	errcode_t err;
1726*6a54128fSAndroid Build Coastguard Worker 
1727*6a54128fSAndroid Build Coastguard Worker 	if (!ext2fs_has_feature_xattr(fs->super) &&
1728*6a54128fSAndroid Build Coastguard Worker 	    !ext2fs_has_feature_inline_data(fs->super))
1729*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_MISSING_EA_FEATURE;
1730*6a54128fSAndroid Build Coastguard Worker 
1731*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_get_memzero(sizeof(*h), &h);
1732*6a54128fSAndroid Build Coastguard Worker 	if (err)
1733*6a54128fSAndroid Build Coastguard Worker 		return err;
1734*6a54128fSAndroid Build Coastguard Worker 
1735*6a54128fSAndroid Build Coastguard Worker 	h->magic = EXT2_ET_MAGIC_EA_HANDLE;
1736*6a54128fSAndroid Build Coastguard Worker 	h->capacity = 4;
1737*6a54128fSAndroid Build Coastguard Worker 	err = ext2fs_get_arrayzero(h->capacity, sizeof(struct ext2_xattr),
1738*6a54128fSAndroid Build Coastguard Worker 				   &h->attrs);
1739*6a54128fSAndroid Build Coastguard Worker 	if (err) {
1740*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&h);
1741*6a54128fSAndroid Build Coastguard Worker 		return err;
1742*6a54128fSAndroid Build Coastguard Worker 	}
1743*6a54128fSAndroid Build Coastguard Worker 	h->count = 0;
1744*6a54128fSAndroid Build Coastguard Worker 	h->ino = ino;
1745*6a54128fSAndroid Build Coastguard Worker 	h->fs = fs;
1746*6a54128fSAndroid Build Coastguard Worker 	*handle = h;
1747*6a54128fSAndroid Build Coastguard Worker 	return 0;
1748*6a54128fSAndroid Build Coastguard Worker }
1749*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattrs_close(struct ext2_xattr_handle ** handle)1750*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle)
1751*6a54128fSAndroid Build Coastguard Worker {
1752*6a54128fSAndroid Build Coastguard Worker 	struct ext2_xattr_handle *h = *handle;
1753*6a54128fSAndroid Build Coastguard Worker 
1754*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
1755*6a54128fSAndroid Build Coastguard Worker 	xattrs_free_keys(h);
1756*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&h->attrs);
1757*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(handle);
1758*6a54128fSAndroid Build Coastguard Worker 	return 0;
1759*6a54128fSAndroid Build Coastguard Worker }
1760*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattrs_count(struct ext2_xattr_handle * handle,size_t * count)1761*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count)
1762*6a54128fSAndroid Build Coastguard Worker {
1763*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
1764*6a54128fSAndroid Build Coastguard Worker 	*count = handle->count;
1765*6a54128fSAndroid Build Coastguard Worker 	return 0;
1766*6a54128fSAndroid Build Coastguard Worker }
1767*6a54128fSAndroid Build Coastguard Worker 
ext2fs_xattrs_flags(struct ext2_xattr_handle * handle,unsigned int * new_flags,unsigned int * old_flags)1768*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle,
1769*6a54128fSAndroid Build Coastguard Worker 			      unsigned int *new_flags, unsigned int *old_flags)
1770*6a54128fSAndroid Build Coastguard Worker {
1771*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
1772*6a54128fSAndroid Build Coastguard Worker 	if (old_flags)
1773*6a54128fSAndroid Build Coastguard Worker 		*old_flags = handle->flags;
1774*6a54128fSAndroid Build Coastguard Worker 	if (new_flags)
1775*6a54128fSAndroid Build Coastguard Worker 		handle->flags = *new_flags;
1776*6a54128fSAndroid Build Coastguard Worker 	return 0;
1777*6a54128fSAndroid Build Coastguard Worker }
1778