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