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