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 #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 
get_prefix(struct xattr_list * xattr,char * name)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
read_xattrs_from_context_file(char * filename,int mode,struct selabel_handle * sehnd,struct xattr_list ** xattrs)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 
read_xattrs_from_system(char * filename,struct xattr_list ** xattrs)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 
get_xattr_size(struct xattr_list * xattr)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 
get_xattr_space(unsigned int req_size,long long * disk)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 
check_id_dupl(struct xattr_list * xattr_list,int xattrs)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 
check_value_dupl(struct xattr_list * xattr)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 
get_xattr_id(int xattrs,struct xattr_list * xattr_list,long long xattr_disk,struct dupl_id * xattr_dupl)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 
write_xattrs()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 
generate_xattrs(int xattrs,struct xattr_list * xattr_list)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 
read_xattrs(void * d)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  */
get_xattrs(int fd,struct squashfs_super_block * sBlk)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  */
save_xattrs()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  */
restore_xattrs()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