• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Create a squashfs filesystem.  This is a highly compressed read only
3  * filesystem.
4  *
5  * Copyright (c) 2008, 2009, 2010, 2012, 2014
6  * Phillip Lougher <phillip@squashfs.org.uk>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2,
11  * or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  *
22  * xattr.c
23  */
24 
25 #ifndef linux
26 #define __BYTE_ORDER BYTE_ORDER
27 #define __BIG_ENDIAN BIG_ENDIAN
28 #define __LITTLE_ENDIAN LITTLE_ENDIAN
29 #else
30 #include <endian.h>
31 #endif
32 
33 #define TRUE 1
34 #define FALSE 0
35 
36 #include <unistd.h>
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <dirent.h>
43 #include <string.h>
44 #include <stdlib.h>
45 #include <sys/xattr.h>
46 
47 #ifdef XATTR_NOFOLLOW /* Apple's xattrs */
48     #define llistxattr(path_, buf_, sz_) \
49         listxattr(path_, buf_, sz_, XATTR_NOFOLLOW)
50     #define lgetxattr(path_, name_, val_, sz_) \
51         getxattr(path_, name_, val_, sz_, 0, XATTR_NOFOLLOW)
52 #endif
53 
54 #include "squashfs_fs.h"
55 #include "squashfs_swap.h"
56 #include "mksquashfs.h"
57 #include "xattr.h"
58 #include "error.h"
59 #include "progressbar.h"
60 
61 /* ANDROID CHANGES START*/
62 #ifdef ANDROID
63 #include "android.h"
64 #include <linux/capability.h>
65 static struct selabel_handle *sehnd = NULL;
66 #endif
67 /* ANDROID CHANGES END */
68 
69 /* compressed xattr table */
70 static char *xattr_table = NULL;
71 static unsigned int xattr_size = 0;
72 
73 /* cached uncompressed xattr data */
74 static char *data_cache = NULL;
75 static int cache_bytes = 0, cache_size = 0;
76 
77 /* cached uncompressed xattr id table */
78 static struct squashfs_xattr_id *xattr_id_table = NULL;
79 static int xattr_ids = 0;
80 
81 /* saved compressed xattr table */
82 unsigned int sxattr_bytes = 0, stotal_xattr_bytes = 0;
83 
84 /* saved cached uncompressed xattr data */
85 static char *sdata_cache = NULL;
86 static int scache_bytes = 0;
87 
88 /* saved cached uncompressed xattr id table */
89 static int sxattr_ids = 0;
90 
91 /* xattr hash table for value duplicate detection */
92 static struct xattr_list *dupl_value[65536];
93 
94 /* xattr hash table for id duplicate detection */
95 static struct dupl_id *dupl_id[65536];
96 
97 /* file system globals from mksquashfs.c */
98 extern int no_xattrs, noX;
99 extern long long bytes;
100 extern int fd;
101 extern unsigned int xattr_bytes, total_xattr_bytes;
102 /* ANDROID CHANGES START*/
103 extern char *context_file;
104 extern char *mount_point;
105 /* ANDROID CHANGES END */
106 
107 /* helper functions from mksquashfs.c */
108 extern unsigned short get_checksum(char *, int, unsigned short);
109 extern void write_destination(int, long long, int, void *);
110 extern long long generic_write_table(int, void *, int, void *, int);
111 extern int mangle(char *, char *, int, int, int, int);
112 extern char *pathname(struct dir_ent *);
113 /* ANDROID CHANGES START*/
114 #ifdef ANDROID
115 extern char *subpathname(struct dir_ent *);
116 #endif
117 /* ANDROID CHANGES END */
118 
119 /* helper functions and definitions from read_xattrs.c */
120 extern int read_xattrs_from_disk(int, struct squashfs_super_block *);
121 extern struct xattr_list *get_xattr(int, unsigned int *, int);
122 extern struct prefix prefix_table[];
123 
124 
get_prefix(struct xattr_list * xattr,char * name)125 static int get_prefix(struct xattr_list *xattr, char *name)
126 {
127 	int i;
128 
129 	xattr->full_name = strdup(name);
130 
131 	for(i = 0; prefix_table[i].type != -1; i++) {
132 		struct prefix *p = &prefix_table[i];
133 		if(strncmp(xattr->full_name, p->prefix, strlen(p->prefix)) == 0)
134 			break;
135 	}
136 
137 	if(prefix_table[i].type != -1) {
138 		xattr->name = xattr->full_name + strlen(prefix_table[i].prefix);
139 		xattr->size = strlen(xattr->name);
140 	}
141 
142 	return prefix_table[i].type;
143 }
144 
145 
146 /* ANDROID CHANGES START*/
147 #ifdef ANDROID
next_xattr_list(int * xattr_count,struct xattr_list ** xattrs)148 static struct xattr_list *next_xattr_list(int *xattr_count, struct xattr_list **xattrs) {
149 	struct xattr_list *x;
150 	x = realloc(*xattrs, ++*xattr_count * sizeof(struct xattr_list));
151 	if (x == NULL) MEM_ERROR();
152 	*xattrs = x;
153 	return &x[*xattr_count - 1];
154 }
155 
read_selinux_xattr_from_sehnd(char * filename,int mode,struct selabel_handle * sehnd,struct xattr_list * xattrs)156 static void read_selinux_xattr_from_sehnd(char *filename, int mode,
157 	struct selabel_handle *sehnd, struct xattr_list *xattrs)
158 {
159 	char *attr_val;
160 
161 	xattrs->type = get_prefix(xattrs, "security.selinux");
162 	attr_val = set_selabel(filename, mode, sehnd);
163 	xattrs->value = (void *)attr_val;
164 	xattrs->vsize = strlen(attr_val);
165 }
166 
set_caps_xattr(uint64_t caps,struct xattr_list * xattrs)167 static void set_caps_xattr(uint64_t caps, struct xattr_list *xattrs)
168 {
169 	struct vfs_cap_data *attr_val;
170 	attr_val = malloc(sizeof(*attr_val));
171 	if (attr_val == NULL) MEM_ERROR();
172 
173 	xattrs->type = get_prefix(xattrs, "security.capability");
174 	*attr_val = set_caps(caps);
175 	xattrs->value = attr_val;
176 	xattrs->vsize = sizeof(*attr_val);
177 }
178 #endif
179 /* ANDROID CHANGES END */
180 
181 
read_xattrs_from_system(char * filename,struct xattr_list ** xattrs)182 static int read_xattrs_from_system(char *filename, struct xattr_list **xattrs)
183 {
184 	ssize_t size, vsize;
185 	char *xattr_names, *p;
186 	int i;
187 	struct xattr_list *xattr_list = NULL;
188 
189 	while(1) {
190 		size = llistxattr(filename, NULL, 0);
191 		if(size <= 0) {
192 			if(size < 0 && errno != ENOTSUP) {
193 				ERROR_START("llistxattr for %s failed in "
194 					"read_attrs, because %s", filename,
195 					strerror(errno));
196 				ERROR_EXIT(".  Ignoring");
197 			}
198 			return 0;
199 		}
200 
201 		xattr_names = malloc(size);
202 		if(xattr_names == NULL)
203 			MEM_ERROR();
204 
205 		size = llistxattr(filename, xattr_names, size);
206 		if(size < 0) {
207 			free(xattr_names);
208 			if(errno == ERANGE)
209 				/* xattr list grew?  Try again */
210 				continue;
211 			else {
212 				ERROR_START("llistxattr for %s failed in "
213 					"read_attrs, because %s", filename,
214 					strerror(errno));
215 				ERROR_EXIT(".  Ignoring");
216 				return 0;
217 			}
218 		}
219 
220 		break;
221 	}
222 
223 	for(i = 0, p = xattr_names; p < xattr_names + size; i++) {
224 		struct xattr_list *x = realloc(xattr_list, (i + 1) *
225 						sizeof(struct xattr_list));
226 		if(x == NULL)
227 			MEM_ERROR();
228 		xattr_list = x;
229 
230 		xattr_list[i].type = get_prefix(&xattr_list[i], p);
231 		p += strlen(p) + 1;
232 		if(xattr_list[i].type == -1) {
233 			ERROR("Unrecognised xattr prefix %s\n",
234 				xattr_list[i].full_name);
235 			free(xattr_list[i].full_name);
236 			i--;
237 			continue;
238 		}
239 
240 		while(1) {
241 			vsize = lgetxattr(filename, xattr_list[i].full_name,
242 								NULL, 0);
243 			if(vsize < 0) {
244 				ERROR_START("lgetxattr failed for %s in "
245 					"read_attrs, because %s", filename,
246 					strerror(errno));
247 				ERROR_EXIT(".  Ignoring");
248 				free(xattr_list[i].full_name);
249 				goto failed;
250 			}
251 
252 			xattr_list[i].value = malloc(vsize);
253 			if(xattr_list[i].value == NULL)
254 				MEM_ERROR();
255 
256 			vsize = lgetxattr(filename, xattr_list[i].full_name,
257 						xattr_list[i].value, vsize);
258 			if(vsize < 0) {
259 				free(xattr_list[i].value);
260 				if(errno == ERANGE)
261 					/* xattr grew?  Try again */
262 					continue;
263 				else {
264 					ERROR_START("lgetxattr failed for %s "
265 						"in read_attrs, because %s",
266 						filename, strerror(errno));
267 					ERROR_EXIT(".  Ignoring");
268 					free(xattr_list[i].full_name);
269 					goto failed;
270 				}
271 			}
272 
273 			break;
274 		}
275 		xattr_list[i].vsize = vsize;
276 
277 		TRACE("read_xattrs_from_system: filename %s, xattr name %s,"
278 			" vsize %d\n", filename, xattr_list[i].full_name,
279 			xattr_list[i].vsize);
280 	}
281 	free(xattr_names);
282 	*xattrs = xattr_list;
283 	return i;
284 
285 failed:
286 	while(--i >= 0) {
287 		free(xattr_list[i].full_name);
288 		free(xattr_list[i].value);
289 	}
290 	free(xattr_list);
291 	free(xattr_names);
292 	return 0;
293 }
294 
295 
get_xattr_size(struct xattr_list * xattr)296 static int get_xattr_size(struct xattr_list *xattr)
297 {
298 	int size = sizeof(struct squashfs_xattr_entry) +
299 		sizeof(struct squashfs_xattr_val) + xattr->size;
300 
301 	if(xattr->type & XATTR_VALUE_OOL)
302 		size += XATTR_VALUE_OOL_SIZE;
303 	else
304 		size += xattr->vsize;
305 
306 	return size;
307 }
308 
309 
get_xattr_space(unsigned int req_size,long long * disk)310 static void *get_xattr_space(unsigned int req_size, long long *disk)
311 {
312 	int data_space;
313 	unsigned short c_byte;
314 
315 	/*
316 	 * Move and compress cached uncompressed data into xattr table.
317 	 */
318 	while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
319 		if((xattr_size - xattr_bytes) <
320 				((SQUASHFS_METADATA_SIZE << 1)) + 2) {
321 			xattr_table = realloc(xattr_table, xattr_size +
322 				(SQUASHFS_METADATA_SIZE << 1) + 2);
323 			if(xattr_table == NULL)
324 				MEM_ERROR();
325 			xattr_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
326 		}
327 
328 		c_byte = mangle(xattr_table + xattr_bytes + BLOCK_OFFSET,
329 			data_cache, SQUASHFS_METADATA_SIZE,
330 			SQUASHFS_METADATA_SIZE, noX, 0);
331 		TRACE("Xattr block @ 0x%x, size %d\n", xattr_bytes, c_byte);
332 		SQUASHFS_SWAP_SHORTS(&c_byte, xattr_table + xattr_bytes, 1);
333 		xattr_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
334 		memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE,
335 			cache_bytes - SQUASHFS_METADATA_SIZE);
336 		cache_bytes -= SQUASHFS_METADATA_SIZE;
337 	}
338 
339 	/*
340 	 * Ensure there's enough space in the uncompressed data cache
341 	 */
342 	data_space = cache_size - cache_bytes;
343 	if(data_space < req_size) {
344 			int realloc_size = req_size - data_space;
345 			data_cache = realloc(data_cache, cache_size +
346 				realloc_size);
347 			if(data_cache == NULL)
348 				MEM_ERROR();
349 			cache_size += realloc_size;
350 	}
351 
352 	if(disk)
353 		*disk = ((long long) xattr_bytes << 16) | cache_bytes;
354 	cache_bytes += req_size;
355 	return data_cache + cache_bytes - req_size;
356 }
357 
358 
check_id_dupl(struct xattr_list * xattr_list,int xattrs)359 static struct dupl_id *check_id_dupl(struct xattr_list *xattr_list, int xattrs)
360 {
361 	struct dupl_id *entry;
362 	int i;
363 	unsigned short checksum = 0;
364 
365 	/* compute checksum over all xattrs */
366 	for(i = 0; i < xattrs; i++) {
367 		struct xattr_list *xattr = &xattr_list[i];
368 
369 		checksum = get_checksum(xattr->full_name,
370 					strlen(xattr->full_name), checksum);
371 		checksum = get_checksum(xattr->value,
372 					xattr->vsize, checksum);
373 	}
374 
375 	for(entry = dupl_id[checksum]; entry; entry = entry->next) {
376 		if (entry->xattrs != xattrs)
377 			continue;
378 
379 		for(i = 0; i < xattrs; i++) {
380 			struct xattr_list *xattr = &xattr_list[i];
381 			struct xattr_list *dup_xattr = &entry->xattr_list[i];
382 
383 			if(strcmp(xattr->full_name, dup_xattr->full_name))
384 				break;
385 
386 			if(memcmp(xattr->value, dup_xattr->value, xattr->vsize))
387 				break;
388 		}
389 
390 		if(i == xattrs)
391 			break;
392 	}
393 
394 	if(entry == NULL) {
395 		/* no duplicate exists */
396 		entry = malloc(sizeof(*entry));
397 		if(entry == NULL)
398 			MEM_ERROR();
399 		entry->xattrs = xattrs;
400 		entry->xattr_list = xattr_list;
401 		entry->xattr_id = SQUASHFS_INVALID_XATTR;
402 		entry->next = dupl_id[checksum];
403 		dupl_id[checksum] = entry;
404 	}
405 
406 	return entry;
407 }
408 
409 
check_value_dupl(struct xattr_list * xattr)410 static void check_value_dupl(struct xattr_list *xattr)
411 {
412 	struct xattr_list *entry;
413 
414 	if(xattr->vsize < XATTR_VALUE_OOL_SIZE)
415 		return;
416 
417 	/* Check if this is a duplicate of an existing value */
418 	xattr->vchecksum = get_checksum(xattr->value, xattr->vsize, 0);
419 	for(entry = dupl_value[xattr->vchecksum]; entry; entry = entry->vnext) {
420 		if(entry->vsize != xattr->vsize)
421 			continue;
422 
423 		if(memcmp(entry->value, xattr->value, xattr->vsize) == 0)
424 			break;
425 	}
426 
427 	if(entry == NULL) {
428 		/*
429 		 * No duplicate exists, add to hash table, and mark as
430 		 * requiring writing
431 		 */
432 		xattr->vnext = dupl_value[xattr->vchecksum];
433 		dupl_value[xattr->vchecksum] = xattr;
434 		xattr->ool_value = SQUASHFS_INVALID_BLK;
435 	} else {
436 		/*
437 		 * Duplicate exists, make type XATTR_VALUE_OOL, and
438 		 * remember where the duplicate is
439 		 */
440 		xattr->type |= XATTR_VALUE_OOL;
441 		xattr->ool_value = entry->ool_value;
442 		/* on appending don't free duplicate values because the
443 		 * duplicate value already points to the non-duplicate value */
444 		if(xattr->value != entry->value) {
445 			free(xattr->value);
446 			xattr->value = entry->value;
447 		}
448 	}
449 }
450 
451 
get_xattr_id(int xattrs,struct xattr_list * xattr_list,long long xattr_disk,struct dupl_id * xattr_dupl)452 static int get_xattr_id(int xattrs, struct xattr_list *xattr_list,
453 		long long xattr_disk, struct dupl_id *xattr_dupl)
454 {
455 	int i, size = 0;
456 	struct squashfs_xattr_id *xattr_id;
457 
458 	xattr_id_table = realloc(xattr_id_table, (xattr_ids + 1) *
459 		sizeof(struct squashfs_xattr_id));
460 	if(xattr_id_table == NULL)
461 		MEM_ERROR();
462 
463 	/* get total uncompressed size of xattr data, needed for stat */
464 	for(i = 0; i < xattrs; i++)
465 		size += strlen(xattr_list[i].full_name) + 1 +
466 			xattr_list[i].vsize;
467 
468 	xattr_id = &xattr_id_table[xattr_ids];
469 	xattr_id->xattr = xattr_disk;
470 	xattr_id->count = xattrs;
471 	xattr_id->size = size;
472 
473 	/*
474 	 * keep track of total uncompressed xattr data, needed for mksquashfs
475 	 * file system summary
476 	 */
477 	total_xattr_bytes += size;
478 
479 	xattr_dupl->xattr_id = xattr_ids ++;
480 	return xattr_dupl->xattr_id;
481 }
482 
483 
write_xattrs()484 long long write_xattrs()
485 {
486 	unsigned short c_byte;
487 	int i, avail_bytes;
488 	char *datap = data_cache;
489 	long long start_bytes = bytes;
490 	struct squashfs_xattr_table header;
491 
492 	if(xattr_ids == 0)
493 		return SQUASHFS_INVALID_BLK;
494 
495 	/*
496 	 * Move and compress cached uncompressed data into xattr table.
497 	 */
498 	while(cache_bytes) {
499 		if((xattr_size - xattr_bytes) <
500 				((SQUASHFS_METADATA_SIZE << 1)) + 2) {
501 			xattr_table = realloc(xattr_table, xattr_size +
502 				(SQUASHFS_METADATA_SIZE << 1) + 2);
503 			if(xattr_table == NULL)
504 				MEM_ERROR();
505 			xattr_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
506 		}
507 
508 		avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
509 			SQUASHFS_METADATA_SIZE : cache_bytes;
510 		c_byte = mangle(xattr_table + xattr_bytes + BLOCK_OFFSET, datap,
511 			avail_bytes, SQUASHFS_METADATA_SIZE, noX, 0);
512 		TRACE("Xattr block @ 0x%x, size %d\n", xattr_bytes, c_byte);
513 		SQUASHFS_SWAP_SHORTS(&c_byte, xattr_table + xattr_bytes, 1);
514 		xattr_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
515 		datap += avail_bytes;
516 		cache_bytes -= avail_bytes;
517 	}
518 
519 	/*
520 	 * Write compressed xattr table to file system
521 	 */
522 	write_destination(fd, bytes, xattr_bytes, xattr_table);
523         bytes += xattr_bytes;
524 
525 	/*
526 	 * Swap if necessary the xattr id table
527 	 */
528 	for(i = 0; i < xattr_ids; i++)
529 		SQUASHFS_INSWAP_XATTR_ID(&xattr_id_table[i]);
530 
531 	header.xattr_ids = xattr_ids;
532 	header.xattr_table_start = start_bytes;
533 	SQUASHFS_INSWAP_XATTR_TABLE(&header);
534 
535 	return generic_write_table(xattr_ids * sizeof(struct squashfs_xattr_id),
536 		xattr_id_table, sizeof(header), &header, noX);
537 }
538 
539 
generate_xattrs(int xattrs,struct xattr_list * xattr_list)540 int generate_xattrs(int xattrs, struct xattr_list *xattr_list)
541 {
542 	int total_size, i;
543 	int xattr_value_max;
544 	void *xp;
545 	long long xattr_disk;
546 	struct dupl_id *xattr_dupl;
547 
548 	/*
549 	 * check if the file xattrs are a complete duplicate of a pre-existing
550 	 * id
551 	 */
552 	xattr_dupl = check_id_dupl(xattr_list, xattrs);
553 	if(xattr_dupl->xattr_id != SQUASHFS_INVALID_XATTR)
554 		return xattr_dupl->xattr_id;
555 
556 	/*
557 	 * Scan the xattr_list deciding which type to assign to each
558 	 * xattr.  The choice is fairly straightforward, and depends on the
559 	 * size of each xattr name/value and the overall size of the
560 	 * resultant xattr list stored in the xattr metadata table.
561 	 *
562 	 * Choices are whether to store data inline or out of line.
563 	 *
564 	 * The overall goal is to optimise xattr scanning and lookup, and
565 	 * to enable the file system layout to scale from a couple of
566 	 * small xattr name/values to a large number of large xattr
567 	 * names/values without affecting performance.  While hopefully
568 	 * enabling the common case of a couple of small xattr name/values
569 	 * to be stored efficiently
570 	 *
571 	 * Code repeatedly scans, doing the following
572 	 *		move xattr data out of line if it exceeds
573 	 *		xattr_value_max.  Where xattr_value_max is
574 	 *		initially XATTR_INLINE_MAX.  If the final uncompressed
575 	 *		xattr list is larger than XATTR_TARGET_MAX then more
576 	 *		aggressively move xattr data out of line by repeatedly
577 	 *	 	setting inline threshold to 1/2, then 1/4, 1/8 of
578 	 *		XATTR_INLINE_MAX until target achieved or there's
579 	 *		nothing left to move out of line
580 	 */
581 	xattr_value_max = XATTR_INLINE_MAX;
582 	while(1) {
583 		for(total_size = 0, i = 0; i < xattrs; i++) {
584 			struct xattr_list *xattr = &xattr_list[i];
585 			xattr->type &= XATTR_PREFIX_MASK; /* all inline */
586 			if (xattr->vsize > xattr_value_max)
587 				xattr->type |= XATTR_VALUE_OOL;
588 
589 			total_size += get_xattr_size(xattr);
590 		}
591 
592 		/*
593 		 * If the total size of the uncompressed xattr list is <=
594 		 * XATTR_TARGET_MAX we're done
595 		 */
596 		if(total_size <= XATTR_TARGET_MAX)
597 			break;
598 
599 		if(xattr_value_max == XATTR_VALUE_OOL_SIZE)
600 			break;
601 
602 		/*
603 		 * Inline target not yet at minimum and so reduce it, and
604 		 * try again
605 		 */
606 		xattr_value_max /= 2;
607 		if(xattr_value_max < XATTR_VALUE_OOL_SIZE)
608 			xattr_value_max = XATTR_VALUE_OOL_SIZE;
609 	}
610 
611 	/*
612 	 * Check xattr values for duplicates
613 	 */
614 	for(i = 0; i < xattrs; i++) {
615 		check_value_dupl(&xattr_list[i]);
616 	}
617 
618 	/*
619 	 * Add each out of line value to the file system xattr table
620 	 * if it doesn't already exist as a duplicate
621 	 */
622 	for(i = 0; i < xattrs; i++) {
623 		struct xattr_list *xattr = &xattr_list[i];
624 
625 		if((xattr->type & XATTR_VALUE_OOL) &&
626 				(xattr->ool_value == SQUASHFS_INVALID_BLK)) {
627 			struct squashfs_xattr_val val;
628 			int size = sizeof(val) + xattr->vsize;
629 			xp = get_xattr_space(size, &xattr->ool_value);
630 			val.vsize = xattr->vsize;
631 			SQUASHFS_SWAP_XATTR_VAL(&val, xp);
632 			memcpy(xp + sizeof(val), xattr->value, xattr->vsize);
633 		}
634 	}
635 
636 	/*
637 	 * Create xattr list and add to file system xattr table
638 	 */
639 	get_xattr_space(0, &xattr_disk);
640 	for(i = 0; i < xattrs; i++) {
641 		struct xattr_list *xattr = &xattr_list[i];
642 		struct squashfs_xattr_entry entry;
643 		struct squashfs_xattr_val val;
644 
645 		xp = get_xattr_space(sizeof(entry) + xattr->size, NULL);
646 		entry.type = xattr->type;
647 		entry.size = xattr->size;
648 		SQUASHFS_SWAP_XATTR_ENTRY(&entry, xp);
649 		memcpy(xp + sizeof(entry), xattr->name, xattr->size);
650 
651 		if(xattr->type & XATTR_VALUE_OOL) {
652 			int size = sizeof(val) + XATTR_VALUE_OOL_SIZE;
653 			xp = get_xattr_space(size, NULL);
654 			val.vsize = XATTR_VALUE_OOL_SIZE;
655 			SQUASHFS_SWAP_XATTR_VAL(&val, xp);
656 			SQUASHFS_SWAP_LONG_LONGS(&xattr->ool_value, xp +
657 				sizeof(val), 1);
658 		} else {
659 			int size = sizeof(val) + xattr->vsize;
660 			xp = get_xattr_space(size, &xattr->ool_value);
661 			val.vsize = xattr->vsize;
662 			SQUASHFS_SWAP_XATTR_VAL(&val, xp);
663 			memcpy(xp + sizeof(val), xattr->value, xattr->vsize);
664 		}
665 	}
666 
667 	/*
668 	 * Add to xattr id lookup table
669 	 */
670 	return get_xattr_id(xattrs, xattr_list, xattr_disk, xattr_dupl);
671 }
672 
673 
read_xattrs(void * d)674 int read_xattrs(void *d)
675 {
676 	struct dir_ent *dir_ent = d;
677 	struct inode_info *inode = dir_ent->inode;
678 	char *filename = pathname(dir_ent);
679 /* ANDROID CHANGES START*/
680 #ifdef ANDROID
681     // NOTE: xattr_list has to point to an array of xattr_list elements
682 	struct xattr_list *xattr_list = NULL, *next_xattr = NULL;
683 	int xattrs = 0;
684 #else
685 	struct xattr_list *xattr_list;
686 	int xattrs;
687 #endif
688 /* ANDROID CHANGES END */
689 
690 	if(no_xattrs || IS_PSEUDO(inode) || inode->root_entry)
691 		return SQUASHFS_INVALID_XATTR;
692 
693 /* ANDROID CHANGES START*/
694 #ifdef ANDROID
695 	if (context_file) {
696 		if (sehnd == NULL)
697 			sehnd = get_sehnd(context_file);
698 		if (mount_point) {
699 			char *mounted_path;
700 			alloc_mounted_path(mount_point, subpathname(dir_ent), &mounted_path);
701 			next_xattr = next_xattr_list(&xattrs, &xattr_list);
702 			read_selinux_xattr_from_sehnd(mounted_path, inode->buf.st_mode,
703 					sehnd, next_xattr);
704 			free(mounted_path);
705 		} else {
706 			next_xattr = next_xattr_list(&xattrs, &xattr_list);
707 			read_selinux_xattr_from_sehnd(filename, inode->buf.st_mode,
708 					sehnd, next_xattr);
709 		}
710 	}
711 	if (dir_ent->capabilities != 0) {
712 		next_xattr = next_xattr_list(&xattrs, &xattr_list);
713 		set_caps_xattr(dir_ent->capabilities, next_xattr);
714 	}
715 #else
716 	xattrs = read_xattrs_from_system(filename, &xattr_list);
717 #endif
718 /* ANDROID CHANGES END */
719 
720 	if(xattrs == 0)
721 		return SQUASHFS_INVALID_XATTR;
722 
723 	return generate_xattrs(xattrs, xattr_list);
724 }
725 
726 
727 /*
728  * Add the existing xattr ids and xattr metadata in the file system being
729  * appended to, to the in-memory xattr cache.  This allows duplicate checking to
730  * take place against the xattrs already in the file system being appended to,
731  * and ensures the pre-existing xattrs are written out along with any new xattrs
732  */
get_xattrs(int fd,struct squashfs_super_block * sBlk)733 int get_xattrs(int fd, struct squashfs_super_block *sBlk)
734 {
735 	int ids, res, i, id;
736 	unsigned int count;
737 
738 	TRACE("get_xattrs\n");
739 
740 	res = read_xattrs_from_disk(fd, sBlk);
741 	if(res == SQUASHFS_INVALID_BLK || res == 0)
742 		goto done;
743 	ids = res;
744 
745 	/*
746 	 * for each xattr id read and construct its list of xattr
747 	 * name:value pairs, and add them to the in-memory xattr cache
748 	 */
749 	for(i = 0; i < ids; i++) {
750 		struct xattr_list *xattr_list = get_xattr(i, &count, 0);
751 		if(xattr_list == NULL) {
752 			res = 0;
753 			goto done;
754 		}
755 		id = generate_xattrs(count, xattr_list);
756 
757 		/*
758 		 * Sanity check, the new xattr id should be the same as the
759 		 * xattr id in the original file system
760 		 */
761 		if(id != i) {
762 			ERROR("BUG, different xattr_id in get_xattrs\n");
763 			res = 0;
764 			goto done;
765 		}
766 	}
767 
768 done:
769 	return res;
770 }
771 
772 
773 /*
774  * Save current state of xattrs, needed for restoring state in the event of an
775  * abort in appending
776  */
save_xattrs()777 void save_xattrs()
778 {
779 	/* save the current state of the compressed xattr data */
780 	sxattr_bytes = xattr_bytes;
781 	stotal_xattr_bytes = total_xattr_bytes;
782 
783 	/*
784 	 * save the current state of the cached uncompressed xattr data.
785 	 * Note we have to save the contents of the data cache because future
786 	 * operations will delete the current contents
787 	 */
788 	sdata_cache = malloc(cache_bytes);
789 	if(sdata_cache == NULL)
790 		MEM_ERROR();
791 
792 	memcpy(sdata_cache, data_cache, cache_bytes);
793 	scache_bytes = cache_bytes;
794 
795 	/* save the current state of the xattr id table */
796 	sxattr_ids = xattr_ids;
797 }
798 
799 
800 /*
801  * Restore xattrs in the event of an abort in appending
802  */
restore_xattrs()803 void restore_xattrs()
804 {
805 	/* restore the state of the compressed xattr data */
806 	xattr_bytes = sxattr_bytes;
807 	total_xattr_bytes = stotal_xattr_bytes;
808 
809 	/* restore the state of the uncomoressed xattr data */
810 	memcpy(data_cache, sdata_cache, scache_bytes);
811 	cache_bytes = scache_bytes;
812 
813 	/* restore the state of the xattr id table */
814 	xattr_ids = sxattr_ids;
815 }
816