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