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#ifdef __ANDROID__
65#include <linux/capability.h>
66#else
67#include <private/android_filesystem_capability.h>
68#endif
69static struct selabel_handle *sehnd = NULL;
70#endif
71/* ANDROID CHANGES END */
72
73/* compressed xattr table */
74static char *xattr_table = NULL;
75static unsigned int xattr_size = 0;
76
77/* cached uncompressed xattr data */
78static char *data_cache = NULL;
79static int cache_bytes = 0, cache_size = 0;
80
81/* cached uncompressed xattr id table */
82static struct squashfs_xattr_id *xattr_id_table = NULL;
83static int xattr_ids = 0;
84
85/* saved compressed xattr table */
86unsigned int sxattr_bytes = 0, stotal_xattr_bytes = 0;
87
88/* saved cached uncompressed xattr data */
89static char *sdata_cache = NULL;
90static int scache_bytes = 0;
91
92/* saved cached uncompressed xattr id table */
93static int sxattr_ids = 0;
94
95/* xattr hash table for value duplicate detection */
96static struct xattr_list *dupl_value[65536];
97
98/* xattr hash table for id duplicate detection */
99static struct dupl_id *dupl_id[65536];
100
101/* file system globals from mksquashfs.c */
102extern int no_xattrs, noX;
103extern long long bytes;
104extern int fd;
105extern unsigned int xattr_bytes, total_xattr_bytes;
106/* ANDROID CHANGES START*/
107extern char *context_file;
108extern char *mount_point;
109/* ANDROID CHANGES END */
110
111/* helper functions from mksquashfs.c */
112extern unsigned short get_checksum(char *, int, unsigned short);
113extern void write_destination(int, long long, int, void *);
114extern long long generic_write_table(int, void *, int, void *, int);
115extern int mangle(char *, char *, int, int, int, int);
116extern char *pathname(struct dir_ent *);
117/* ANDROID CHANGES START*/
118#ifdef ANDROID
119extern char *subpathname(struct dir_ent *);
120#endif
121/* ANDROID CHANGES END */
122
123/* helper functions and definitions from read_xattrs.c */
124extern int read_xattrs_from_disk(int, struct squashfs_super_block *);
125extern struct xattr_list *get_xattr(int, unsigned int *, int);
126extern struct prefix prefix_table[];
127
128
129static 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
152static 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
160static 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
171static 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
186static 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
289failed:
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
300static 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
314static 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
363static 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
414static 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
456static 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
488long 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
544int 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
678int 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 */
737int 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
772done:
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 */
781void 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 */
807void 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