xref: /aosp_15_r20/external/squashfs-tools/squashfs-tools/mksquashfs.c (revision 79398b2563bcbbbab54656397863972d8fa68df1)
1 /*
2  * Create a squashfs filesystem.  This is a highly compressed read only
3  * filesystem.
4  *
5  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
6  * 2012, 2013, 2014
7  * Phillip Lougher <[email protected]>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2,
12  * or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * mksquashfs.c
24  */
25 
26 #define FALSE 0
27 #define TRUE 1
28 #define MAX_LINE 16384
29 
30 #include <pwd.h>
31 #include <grp.h>
32 #include <time.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <stddef.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <dirent.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <signal.h>
44 #include <setjmp.h>
45 #include <sys/types.h>
46 #include <sys/mman.h>
47 #include <pthread.h>
48 #include <regex.h>
49 #include <fnmatch.h>
50 #include <sys/wait.h>
51 #include <limits.h>
52 #include <ctype.h>
53 #include <sys/sysmacros.h>
54 
55 #ifndef FNM_EXTMATCH /* glibc extension */
56     #define FNM_EXTMATCH 0
57 #endif
58 
59 #ifndef linux
60 #define __BYTE_ORDER BYTE_ORDER
61 #define __BIG_ENDIAN BIG_ENDIAN
62 #define __LITTLE_ENDIAN LITTLE_ENDIAN
63 #include <sys/sysctl.h>
64 #else
65 #include <endian.h>
66 #include <sys/sysinfo.h>
67 #endif
68 
69 #include "squashfs_fs.h"
70 #include "squashfs_swap.h"
71 #include "mksquashfs.h"
72 #include "sort.h"
73 #include "pseudo.h"
74 #include "compressor.h"
75 #include "xattr.h"
76 #include "action.h"
77 #include "error.h"
78 #include "progressbar.h"
79 #include "info.h"
80 #include "caches-queues-lists.h"
81 #include "read_fs.h"
82 #include "restore.h"
83 #include "process_fragments.h"
84 
85 /* ANDROID CHANGES START*/
86 #ifdef ANDROID
87 #include "android.h"
88 #include "private/android_filesystem_config.h"
89 #include "private/canned_fs_config.h"
90 #include "private/fs_config.h"
91 int android_config = FALSE;
92 char *context_file = NULL;
93 char *mount_point = NULL;
94 char *target_out_path = NULL;
95 fs_config_func_t fs_config_func = NULL;
96 int compress_thresh_per = 0;
97 int align_4k_blocks = TRUE;
98 FILE *block_map_file = NULL;
99 #endif
100 /* ANDROID CHANGES END */
101 
102 int delete = FALSE;
103 int fd;
104 struct squashfs_super_block sBlk;
105 
106 /* filesystem flags for building */
107 int comp_opts = FALSE;
108 int no_xattrs = XATTR_DEF;
109 int noX = FALSE;
110 int duplicate_checking = TRUE;
111 int noF = FALSE;
112 int no_fragments = FALSE;
113 int always_use_fragments = FALSE;
114 int noI = FALSE;
115 int noD = FALSE;
116 int silent = TRUE;
117 int exportable = TRUE;
118 int sparse_files = TRUE;
119 int old_exclude = TRUE;
120 int use_regex = FALSE;
121 int nopad = FALSE;
122 int exit_on_error = FALSE;
123 
124 long long global_uid = -1, global_gid = -1;
125 
126 /* superblock attributes */
127 int block_size = SQUASHFS_FILE_SIZE, block_log;
128 unsigned int id_count = 0;
129 int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0,
130 	sock_count = 0;
131 
132 /* ANDROID CHANGES START*/
133 #ifdef ANDROID
134 int whitelisted_count = 0;
135 #endif
136 /* ANDROID CHANGES END */
137 
138 /* write position within data section */
139 long long bytes = 0, total_bytes = 0;
140 
141 /* in memory directory table - possibly compressed */
142 char *directory_table = NULL;
143 unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0;
144 
145 /* cached directory table */
146 char *directory_data_cache = NULL;
147 unsigned int directory_cache_bytes = 0, directory_cache_size = 0;
148 
149 /* in memory inode table - possibly compressed */
150 char *inode_table = NULL;
151 unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0;
152 
153 /* cached inode table */
154 char *data_cache = NULL;
155 unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0;
156 
157 /* inode lookup table */
158 squashfs_inode *inode_lookup_table = NULL;
159 
160 /* in memory directory data */
161 #define I_COUNT_SIZE		128
162 #define DIR_ENTRIES		32
163 #define INODE_HASH_SIZE		65536
164 #define INODE_HASH_MASK		(INODE_HASH_SIZE - 1)
165 #define INODE_HASH(dev, ino)	(ino & INODE_HASH_MASK)
166 
167 struct cached_dir_index {
168 	struct squashfs_dir_index	index;
169 	char				*name;
170 };
171 
172 struct directory {
173 	unsigned int		start_block;
174 	unsigned int		size;
175 	unsigned char		*buff;
176 	unsigned char		*p;
177 	unsigned int		entry_count;
178 	unsigned char		*entry_count_p;
179 	unsigned int		i_count;
180 	unsigned int		i_size;
181 	struct cached_dir_index	*index;
182 	unsigned char		*index_count_p;
183 	unsigned int		inode_number;
184 };
185 
186 struct inode_info *inode_info[INODE_HASH_SIZE];
187 
188 /* hash tables used to do fast duplicate searches in duplicate check */
189 struct file_info *dupl[65536];
190 int dup_files = 0;
191 
192 /* exclude file handling */
193 /* list of exclude dirs/files */
194 struct exclude_info {
195 	dev_t			st_dev;
196 	ino_t			st_ino;
197 };
198 
199 #define EXCLUDE_SIZE 8192
200 int exclude = 0;
201 struct exclude_info *exclude_paths = NULL;
202 int old_excluded(char *filename, struct stat *buf);
203 
204 struct path_entry {
205 	char *name;
206 	regex_t *preg;
207 	struct pathname *paths;
208 };
209 
210 struct pathname {
211 	int names;
212 	struct path_entry *name;
213 };
214 
215 struct pathnames {
216 	int count;
217 	struct pathname *path[0];
218 };
219 #define PATHS_ALLOC_SIZE 10
220 
221 struct pathnames *paths = NULL;
222 struct pathname *path = NULL;
223 struct pathname *stickypath = NULL;
224 int excluded(char *name, struct pathnames *paths, struct pathnames **new);
225 
226 int fragments = 0;
227 
228 #define FRAG_SIZE 32768
229 
230 struct squashfs_fragment_entry *fragment_table = NULL;
231 int fragments_outstanding = 0;
232 
233 int fragments_locked = FALSE;
234 
235 /* current inode number for directories and non directories */
236 unsigned int inode_no = 1;
237 unsigned int root_inode_number = 0;
238 
239 /* list of source dirs/files */
240 int source = 0;
241 char **source_path;
242 
243 /* list of root directory entries read from original filesystem */
244 int old_root_entries = 0;
245 struct old_root_entry_info {
246 	char			*name;
247 	struct inode_info	inode;
248 };
249 struct old_root_entry_info *old_root_entry;
250 
251 /* restore orignal filesystem state if appending to existing filesystem is
252  * cancelled */
253 int appending = FALSE;
254 char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed;
255 
256 long long sbytes, stotal_bytes;
257 
258 unsigned int sinode_bytes, scache_bytes, sdirectory_bytes,
259 	sdirectory_cache_bytes, sdirectory_compressed_bytes,
260 	stotal_inode_bytes, stotal_directory_bytes,
261 	sinode_count = 0, sfile_count, ssym_count, sdev_count,
262 	sdir_count, sfifo_count, ssock_count, sdup_files;
263 int sfragments;
264 int threads;
265 
266 /* flag whether destination file is a block device */
267 int block_device = FALSE;
268 
269 /* flag indicating whether files are sorted using sort list(s) */
270 int sorted = FALSE;
271 
272 /* save destination file name for deleting on error */
273 char *destination_file = NULL;
274 
275 /* recovery file for abnormal exit on appending */
276 char *recovery_file = NULL;
277 int recover = TRUE;
278 
279 /* uid/gid mapping tables */
280 #define UGID_ENTRIES 340
281 
282 struct ugid_map_entry {
283 	unsigned int	child_id;
284 	unsigned int	parent_id;
285 	unsigned int	length;
286 };
287 struct ugid_map_entry uid_mapping[UGID_ENTRIES], gid_mapping[UGID_ENTRIES];
288 unsigned int uid_map_count = 0, gid_map_count = 0;
289 
290 
291 struct id *id_hash_table[ID_ENTRIES];
292 struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS];
293 unsigned int uid_count = 0, guid_count = 0;
294 unsigned int sid_count = 0, suid_count = 0, sguid_count = 0;
295 
296 struct cache *reader_buffer, *fragment_buffer, *reserve_cache;
297 struct cache *bwriter_buffer, *fwriter_buffer;
298 struct queue *to_reader, *to_deflate, *to_writer, *from_writer,
299 	*to_frag, *locked_fragment, *to_process_frag;
300 struct seq_queue *to_main;
301 pthread_t reader_thread, writer_thread, main_thread;
302 pthread_t *deflator_thread, *frag_deflator_thread, *frag_thread;
303 pthread_t *restore_thread = NULL;
304 pthread_mutex_t	fragment_mutex = PTHREAD_MUTEX_INITIALIZER;
305 pthread_mutex_t	pos_mutex = PTHREAD_MUTEX_INITIALIZER;
306 pthread_mutex_t	dup_mutex = PTHREAD_MUTEX_INITIALIZER;
307 
308 /* user options that control parallelisation */
309 int processors = -1;
310 int bwriter_size;
311 
312 /* compression operations */
313 struct compressor *comp = NULL;
314 int compressor_opt_parsed = FALSE;
315 void *stream = NULL;
316 
317 /* xattr stats */
318 unsigned int xattr_bytes = 0, total_xattr_bytes = 0;
319 
320 /* fragment to file mapping used when appending */
321 int append_fragments = 0;
322 struct append_file **file_mapping;
323 
324 /* root of the in-core directory structure */
325 struct dir_info *root_dir;
326 
327 static char *read_from_disk(long long start, unsigned int avail_bytes);
328 void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
329 	int type);
330 struct file_info *duplicate(long long file_size, long long bytes,
331 	unsigned int **block_list, long long *start, struct fragment **fragment,
332 	struct file_buffer *file_buffer, int blocks, unsigned short checksum,
333 	int checksum_flag);
334 struct dir_info *dir_scan1(char *, char *, struct pathnames *,
335 	struct dir_ent *(_readdir)(struct dir_info *), int);
336 void dir_scan2(struct dir_info *dir, struct pseudo *pseudo);
337 void dir_scan3(struct dir_info *dir);
338 void dir_scan4(struct dir_info *dir);
339 void dir_scan5(struct dir_info *dir);
340 void dir_scan6(struct dir_info *dir);
341 void dir_scan7(squashfs_inode *inode, struct dir_info *dir_info);
342 struct file_info *add_non_dup(long long file_size, long long bytes,
343 	unsigned int *block_list, long long start, struct fragment *fragment,
344 	unsigned short checksum, unsigned short fragment_checksum,
345 	int checksum_flag, int checksum_frag_flag);
346 long long generic_write_table(int, void *, int, void *, int);
347 void restorefs();
348 struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth);
349 void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad);
350 unsigned short get_checksum_mem(char *buff, int bytes);
351 void check_usable_phys_mem(int total_mem);
352 
353 /* ANDROID CHANGES START*/
354 #ifdef ANDROID
355 static int whitelisted(struct stat *buf);
356 static void add_whitelist_entry(char *filename, struct stat *buf);
357 static int add_whitelist(char *path);
358 static void process_whitelist_file(char *argv);
359 
360 #define WHITELIST_SIZE 8192
361 int whitelist = 0;
362 
363 struct whitelist_info {
364 	dev_t			st_dev;
365 	ino_t			st_ino;
366 };
367 char *whitelist_filename = NULL;
368 struct whitelist_info *whitelist_paths = NULL;
369 #endif
370 /* ANDROID CHANGES END */
371 
prep_exit()372 void prep_exit()
373 {
374 	if(restore_thread) {
375 		if(pthread_self() == *restore_thread) {
376 			/*
377 			 * Recursive failure when trying to restore filesystem!
378 			 * Nothing to do except to exit, otherwise we'll just
379 			 * appear to hang.  The user should be able to restore
380 			 * from the recovery file (which is why it was added, in
381 			 * case of catastrophic failure in Mksquashfs)
382 			 */
383 			exit(1);
384 		} else {
385 			/* signal the restore thread to restore */
386 			pthread_kill(*restore_thread, SIGUSR1);
387 			pthread_exit(NULL);
388 		}
389 	} else if(delete) {
390 		if(destination_file && !block_device)
391 			unlink(destination_file);
392 	} else if(recovery_file)
393 		unlink(recovery_file);
394 }
395 
396 
add_overflow(int a,int b)397 int add_overflow(int a, int b)
398 {
399 	return (INT_MAX - a) < b;
400 }
401 
402 
shift_overflow(int a,int shift)403 int shift_overflow(int a, int shift)
404 {
405 	return (INT_MAX >> shift) < a;
406 }
407 
408 
multiply_overflow(int a,int multiplier)409 int multiply_overflow(int a, int multiplier)
410 {
411 	return (INT_MAX / multiplier) < a;
412 }
413 
414 
multiply_overflowll(long long a,int multiplier)415 int multiply_overflowll(long long a, int multiplier)
416 {
417 	return (LLONG_MAX / multiplier) < a;
418 }
419 
420 
421 #define MKINODE(A)	((squashfs_inode)(((squashfs_inode) inode_bytes << 16) \
422 			+ (((char *)A) - data_cache)))
423 
424 
restorefs()425 void restorefs()
426 {
427 	ERROR("Exiting - restoring original filesystem!\n\n");
428 
429 	bytes = sbytes;
430 	memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes);
431 	memcpy(directory_data_cache, sdirectory_data_cache,
432 		sdirectory_cache_bytes);
433 	directory_cache_bytes = sdirectory_cache_bytes;
434 	inode_bytes = sinode_bytes;
435 	directory_bytes = sdirectory_bytes;
436  	memcpy(directory_table + directory_bytes, sdirectory_compressed,
437 		sdirectory_compressed_bytes);
438  	directory_bytes += sdirectory_compressed_bytes;
439 	total_bytes = stotal_bytes;
440 	total_inode_bytes = stotal_inode_bytes;
441 	total_directory_bytes = stotal_directory_bytes;
442 	inode_count = sinode_count;
443 	file_count = sfile_count;
444 	sym_count = ssym_count;
445 	dev_count = sdev_count;
446 	dir_count = sdir_count;
447 	fifo_count = sfifo_count;
448 	sock_count = ssock_count;
449 	dup_files = sdup_files;
450 	fragments = sfragments;
451 	id_count = sid_count;
452 	restore_xattrs();
453 	write_filesystem_tables(&sBlk, nopad);
454 	exit(1);
455 }
456 
457 
sighandler()458 void sighandler()
459 {
460 	EXIT_MKSQUASHFS();
461 }
462 
463 
mangle2(void * strm,char * d,char * s,int size,int block_size,int uncompressed,int data_block)464 int mangle2(void *strm, char *d, char *s, int size,
465 	int block_size, int uncompressed, int data_block)
466 {
467 	int error, c_byte = 0;
468 
469 	if(!uncompressed) {
470 		c_byte = compressor_compress(comp, strm, d, s, size, block_size,
471 			 &error);
472 		if(c_byte == -1)
473 			BAD_ERROR("mangle2:: %s compress failed with error "
474 				"code %d\n", comp->name, error);
475 	}
476 
477 	if(c_byte == 0 || c_byte >= size ||
478 			(c_byte > (size * ((100.0 - compress_thresh_per) / 100.0)))) {
479 		memcpy(d, s, size);
480 		return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK :
481 			SQUASHFS_COMPRESSED_BIT);
482 	}
483 
484 	return c_byte;
485 }
486 
487 
mangle(char * d,char * s,int size,int block_size,int uncompressed,int data_block)488 int mangle(char *d, char *s, int size, int block_size,
489 	int uncompressed, int data_block)
490 {
491 	return mangle2(stream, d, s, size, block_size, uncompressed,
492 		data_block);
493 }
494 
495 
get_inode(int req_size)496 void *get_inode(int req_size)
497 {
498 	int data_space;
499 	unsigned short c_byte;
500 
501 	while(cache_bytes >= SQUASHFS_METADATA_SIZE) {
502 		if((inode_size - inode_bytes) <
503 				((SQUASHFS_METADATA_SIZE << 1)) + 2) {
504 			void *it = realloc(inode_table, inode_size +
505 				(SQUASHFS_METADATA_SIZE << 1) + 2);
506 			if(it == NULL)
507 				MEM_ERROR();
508 			inode_table = it;
509 			inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
510 		}
511 
512 		c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET,
513 			data_cache, SQUASHFS_METADATA_SIZE,
514 			SQUASHFS_METADATA_SIZE, noI, 0);
515 		TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
516 		SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
517 		inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
518 		total_inode_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
519 		memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE,
520 			cache_bytes - SQUASHFS_METADATA_SIZE);
521 		cache_bytes -= SQUASHFS_METADATA_SIZE;
522 	}
523 
524 	data_space = (cache_size - cache_bytes);
525 	if(data_space < req_size) {
526 			int realloc_size = cache_size == 0 ?
527 				((req_size + SQUASHFS_METADATA_SIZE) &
528 				~(SQUASHFS_METADATA_SIZE - 1)) : req_size -
529 				data_space;
530 
531 			void *dc = realloc(data_cache, cache_size +
532 				realloc_size);
533 			if(dc == NULL)
534 				MEM_ERROR();
535 			cache_size += realloc_size;
536 			data_cache = dc;
537 	}
538 
539 	cache_bytes += req_size;
540 
541 	return data_cache + cache_bytes - req_size;
542 }
543 
544 
read_bytes(int fd,void * buff,int bytes)545 int read_bytes(int fd, void *buff, int bytes)
546 {
547 	int res, count;
548 
549 	for(count = 0; count < bytes; count += res) {
550 		res = read(fd, buff + count, bytes - count);
551 		if(res < 1) {
552 			if(res == 0)
553 				goto bytes_read;
554 			else if(errno != EINTR) {
555 				ERROR("Read failed because %s\n",
556 						strerror(errno));
557 				return -1;
558 			} else
559 				res = 0;
560 		}
561 	}
562 
563 bytes_read:
564 	return count;
565 }
566 
567 
read_fs_bytes(int fd,long long byte,int bytes,void * buff)568 int read_fs_bytes(int fd, long long byte, int bytes, void *buff)
569 {
570 	off_t off = byte;
571 	int res = 1;
572 
573 	TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n",
574 		byte, bytes);
575 
576 	pthread_cleanup_push((void *) pthread_mutex_unlock, &pos_mutex);
577 	pthread_mutex_lock(&pos_mutex);
578 	if(lseek(fd, off, SEEK_SET) == -1) {
579 		ERROR("read_fs_bytes: Lseek on destination failed because %s, "
580 			"offset=0x%llx\n", strerror(errno), off);
581 		res = 0;
582 	} else if(read_bytes(fd, buff, bytes) < bytes) {
583 		ERROR("Read on destination failed\n");
584 		res = 0;
585 	}
586 
587 	pthread_cleanup_pop(1);
588 	return res;
589 }
590 
591 
write_bytes(int fd,void * buff,int bytes)592 int write_bytes(int fd, void *buff, int bytes)
593 {
594 	int res, count;
595 
596 	for(count = 0; count < bytes; count += res) {
597 		res = write(fd, buff + count, bytes - count);
598 		if(res == -1) {
599 			if(errno != EINTR) {
600 				ERROR("Write failed because %s\n",
601 						strerror(errno));
602 				return -1;
603 			}
604 			res = 0;
605 		}
606 	}
607 
608 	return 0;
609 }
610 
611 
write_destination(int fd,long long byte,int bytes,void * buff)612 void write_destination(int fd, long long byte, int bytes, void *buff)
613 {
614 	off_t off = byte;
615 
616 	pthread_cleanup_push((void *) pthread_mutex_unlock, &pos_mutex);
617 	pthread_mutex_lock(&pos_mutex);
618 
619 	if(lseek(fd, off, SEEK_SET) == -1) {
620 		ERROR("write_destination: Lseek on destination "
621 			"failed because %s, offset=0x%llx\n", strerror(errno),
622 			off);
623 		BAD_ERROR("Probably out of space on output %s\n",
624 			block_device ? "block device" : "filesystem");
625 	}
626 
627 	if(write_bytes(fd, buff, bytes) == -1)
628 		BAD_ERROR("Failed to write to output %s\n",
629 			block_device ? "block device" : "filesystem");
630 
631 	pthread_cleanup_pop(1);
632 }
633 
634 
write_inodes()635 long long write_inodes()
636 {
637 	unsigned short c_byte;
638 	int avail_bytes;
639 	char *datap = data_cache;
640 	long long start_bytes = bytes;
641 
642 	while(cache_bytes) {
643 		if(inode_size - inode_bytes <
644 				((SQUASHFS_METADATA_SIZE << 1) + 2)) {
645 			void *it = realloc(inode_table, inode_size +
646 				((SQUASHFS_METADATA_SIZE << 1) + 2));
647 			if(it == NULL)
648 				MEM_ERROR();
649 			inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
650 			inode_table = it;
651 		}
652 		avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ?
653 			SQUASHFS_METADATA_SIZE : cache_bytes;
654 		c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, datap,
655 			avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0);
656 		TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte);
657 		SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1);
658 		inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET;
659 		total_inode_bytes += avail_bytes + BLOCK_OFFSET;
660 		datap += avail_bytes;
661 		cache_bytes -= avail_bytes;
662 	}
663 
664 	write_destination(fd, bytes, inode_bytes,  inode_table);
665 	bytes += inode_bytes;
666 
667 	return start_bytes;
668 }
669 
670 
write_directories()671 long long write_directories()
672 {
673 	unsigned short c_byte;
674 	int avail_bytes;
675 	char *directoryp = directory_data_cache;
676 	long long start_bytes = bytes;
677 
678 	while(directory_cache_bytes) {
679 		if(directory_size - directory_bytes <
680 				((SQUASHFS_METADATA_SIZE << 1) + 2)) {
681 			void *dt = realloc(directory_table,
682 				directory_size + ((SQUASHFS_METADATA_SIZE << 1)
683 				+ 2));
684 			if(dt == NULL)
685 				MEM_ERROR();
686 			directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2;
687 			directory_table = dt;
688 		}
689 		avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ?
690 			SQUASHFS_METADATA_SIZE : directory_cache_bytes;
691 		c_byte = mangle(directory_table + directory_bytes +
692 			BLOCK_OFFSET, directoryp, avail_bytes,
693 			SQUASHFS_METADATA_SIZE, noI, 0);
694 		TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
695 			c_byte);
696 		SQUASHFS_SWAP_SHORTS(&c_byte,
697 			directory_table + directory_bytes, 1);
698 		directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
699 			BLOCK_OFFSET;
700 		total_directory_bytes += avail_bytes + BLOCK_OFFSET;
701 		directoryp += avail_bytes;
702 		directory_cache_bytes -= avail_bytes;
703 	}
704 	write_destination(fd, bytes, directory_bytes, directory_table);
705 	bytes += directory_bytes;
706 
707 	return start_bytes;
708 }
709 
710 
write_id_table()711 long long write_id_table()
712 {
713 	unsigned int id_bytes = SQUASHFS_ID_BYTES(id_count);
714 	unsigned int p[id_count];
715 	int i;
716 
717 	TRACE("write_id_table: ids %d, id_bytes %d\n", id_count, id_bytes);
718 	for(i = 0; i < id_count; i++) {
719 		TRACE("write_id_table: id index %d, id %d", i, id_table[i]->id);
720 		SQUASHFS_SWAP_INTS(&id_table[i]->id, p + i, 1);
721 	}
722 
723 	return generic_write_table(id_bytes, p, 0, NULL, noI);
724 }
725 
726 
get_id(unsigned int id)727 struct id *get_id(unsigned int id)
728 {
729 	int hash = ID_HASH(id);
730 	struct id *entry = id_hash_table[hash];
731 
732 	for(; entry; entry = entry->next)
733 		if(entry->id == id)
734 			break;
735 
736 	return entry;
737 }
738 
739 
create_id(unsigned int id)740 struct id *create_id(unsigned int id)
741 {
742 	int hash = ID_HASH(id);
743 	struct id *entry = malloc(sizeof(struct id));
744 	if(entry == NULL)
745 		MEM_ERROR();
746 	entry->id = id;
747 	entry->index = id_count ++;
748 	entry->flags = 0;
749 	entry->next = id_hash_table[hash];
750 	id_hash_table[hash] = entry;
751 	id_table[entry->index] = entry;
752 	return entry;
753 }
754 
755 
resolve_child_ugid(unsigned int * ugid,const struct ugid_map_entry * ugid_mapping,unsigned int ugid_map_count)756 int resolve_child_ugid(unsigned int *ugid,
757 	const struct ugid_map_entry *ugid_mapping,
758 	unsigned int ugid_map_count)
759 {
760 	unsigned int i;
761 
762 	for (i = 0; i < ugid_map_count; i++) {
763 		if (ugid_mapping[i].parent_id <= *ugid &&
764 			*ugid <
765 			ugid_mapping[i].parent_id + ugid_mapping[i].length) {
766 			*ugid = ugid_mapping[i].child_id + *ugid -
767 				ugid_mapping[i].parent_id;
768 			return 1;
769 		}
770 	}
771 
772 	return 0;
773 }
774 
775 
get_uid(unsigned int uid,int resolve)776 unsigned int get_uid(unsigned int uid, int resolve)
777 {
778 	struct id *entry;
779 
780 	if (resolve && !resolve_child_ugid(&uid, uid_mapping, uid_map_count))
781 		BAD_ERROR("uid not found in mapping: %d\n", uid);
782 	entry = get_id(uid);
783 
784 	if(entry == NULL) {
785 		if(id_count == SQUASHFS_IDS)
786 			BAD_ERROR("Out of uids!\n");
787 		entry = create_id(uid);
788 	}
789 
790 	if((entry->flags & ISA_UID) == 0) {
791 		entry->flags |= ISA_UID;
792 		uid_count ++;
793 	}
794 
795 	return entry->index;
796 }
797 
798 
get_guid(unsigned int guid,int resolve)799 unsigned int get_guid(unsigned int guid, int resolve)
800 {
801 	struct id *entry;
802 
803 	if (resolve && !resolve_child_ugid(&guid, gid_mapping, gid_map_count))
804 		BAD_ERROR("gid not found in mapping: %d\n", guid);
805 	entry = get_id(guid);
806 
807 	if(entry == NULL) {
808 		if(id_count == SQUASHFS_IDS)
809 			BAD_ERROR("Out of gids!\n");
810 		entry = create_id(guid);
811 	}
812 
813 	if((entry->flags & ISA_GID) == 0) {
814 		entry->flags |= ISA_GID;
815 		guid_count ++;
816 	}
817 
818 	return entry->index;
819 }
820 
821 
822 #define ALLOC_SIZE 128
823 
_pathname(struct dir_ent * dir_ent,char * pathname,int * size)824 char *_pathname(struct dir_ent *dir_ent, char *pathname, int *size)
825 {
826 	if(pathname == NULL) {
827 		pathname = malloc(ALLOC_SIZE);
828 		if(pathname == NULL)
829 			MEM_ERROR();
830 	}
831 
832 	for(;;) {
833 		int res = snprintf(pathname, *size, "%s/%s",
834 			dir_ent->our_dir->pathname,
835 			dir_ent->source_name ? : dir_ent->name);
836 
837 		if(res < 0)
838 			BAD_ERROR("snprintf failed in pathname\n");
839 		else if(res >= *size) {
840 			/*
841 			 * pathname is too small to contain the result, so
842 			 * increase it and try again
843 			 */
844 			*size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1);
845 			pathname = realloc(pathname, *size);
846 			if(pathname == NULL)
847 				MEM_ERROR();
848 		} else
849 			break;
850 	}
851 
852 	return pathname;
853 }
854 
855 
pathname(struct dir_ent * dir_ent)856 char *pathname(struct dir_ent *dir_ent)
857 {
858 	static char *pathname = NULL;
859 	static int size = ALLOC_SIZE;
860 
861 	if (dir_ent->nonstandard_pathname)
862 		return dir_ent->nonstandard_pathname;
863 
864 	return pathname = _pathname(dir_ent, pathname, &size);
865 }
866 
867 
pathname_reader(struct dir_ent * dir_ent)868 char *pathname_reader(struct dir_ent *dir_ent)
869 {
870 	static char *pathname = NULL;
871 	static int size = ALLOC_SIZE;
872 
873 	if (dir_ent->nonstandard_pathname)
874 		return dir_ent->nonstandard_pathname;
875 
876 	return pathname = _pathname(dir_ent, pathname, &size);
877 }
878 
879 
subpathname(struct dir_ent * dir_ent)880 char *subpathname(struct dir_ent *dir_ent)
881 {
882 	static char *subpath = NULL;
883 	static int size = ALLOC_SIZE;
884 	int res;
885 
886 	if(subpath == NULL) {
887 		subpath = malloc(ALLOC_SIZE);
888 		if(subpath == NULL)
889 			MEM_ERROR();
890 	}
891 
892 	for(;;) {
893 		if(dir_ent->our_dir->subpath[0] != '\0')
894 			res = snprintf(subpath, size, "%s/%s",
895 				dir_ent->our_dir->subpath, dir_ent->name);
896 		else
897 			res = snprintf(subpath, size, "/%s", dir_ent->name);
898 
899 		if(res < 0)
900 			BAD_ERROR("snprintf failed in subpathname\n");
901 		else if(res >= size) {
902 			/*
903 			 * subpath is too small to contain the result, so
904 			 * increase it and try again
905 			 */
906 			size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1);
907 			subpath = realloc(subpath, size);
908 			if(subpath == NULL)
909 				MEM_ERROR();
910 		} else
911 			break;
912 	}
913 
914 	return subpath;
915 }
916 
917 
get_inode_no(struct inode_info * inode)918 static inline unsigned int get_inode_no(struct inode_info *inode)
919 {
920 	return inode->inode_number;
921 }
922 
923 
get_parent_no(struct dir_info * dir)924 static inline unsigned int get_parent_no(struct dir_info *dir)
925 {
926 	return dir->depth ? get_inode_no(dir->dir_ent->inode) : inode_no;
927 }
928 
929 
930 /* ANDROID CHANGES START*/
931 #ifdef ANDROID
932 
933 /* Round up the passed |n| value to the smallest multiple of 4096 greater or
934  * equal than |n| and return the 4K-block number for that value. */
round_up_block(unsigned long long n)935 static unsigned long long round_up_block(unsigned long long n) {
936 	const unsigned long long kMapBlockSize = 4096;
937 	return (n + kMapBlockSize - 1) / kMapBlockSize;
938 }
939 
write_block_map_entry(char * sub_path,unsigned long long start_block,unsigned long long total_size,char * mount_point,FILE * block_map_file)940 static inline void write_block_map_entry(char *sub_path, unsigned long long start_block, unsigned long long total_size,
941 		char * mount_point, FILE *block_map_file) {
942 	if (block_map_file) {
943 		/* We assign each 4K block based on what file the first byte of the block
944 		 * belongs to. The current file consists of the chunk of bytes in the
945 		 * interval [start_block, start_block + total_size), (closed on the left end
946 		 * and open on the right end). We then compute the first block whose first
947 		 * byte is equal to or greater than start_block as |round_start| and then
948 		 * the first block whose first byte is *past* this interval, as
949 		 * |round_end + 1|. This means that the blocks that should be assigned to
950 		 * the current file are in the interval [round_start, round_end + 1), or
951 		 * simply [round_start, round_end].
952 		 */
953 		unsigned long long round_start = round_up_block(start_block);
954 		unsigned long long round_end = round_up_block(start_block + total_size) - 1;
955 		if (round_start && total_size && round_start <= round_end) {
956 			fprintf(block_map_file, "/%s", mount_point);
957 			if (sub_path[0] != '/') fprintf(block_map_file, "/");
958 			if (round_start == round_end)
959 				fprintf(block_map_file, "%s %lld\n", sub_path, round_start);
960 			else
961 				fprintf(block_map_file, "%s %lld-%lld\n", sub_path, round_start, round_end);
962 		}
963 	}
964 }
965 #endif
966 /* ANDROID CHANGES END */
967 
create_inode(squashfs_inode * i_no,struct dir_info * dir_info,struct dir_ent * dir_ent,int type,long long byte_size,long long start_block,unsigned int offset,unsigned int * block_list,struct fragment * fragment,struct directory * dir_in,long long sparse)968 int create_inode(squashfs_inode *i_no, struct dir_info *dir_info,
969 	struct dir_ent *dir_ent, int type, long long byte_size,
970 	long long start_block, unsigned int offset, unsigned int *block_list,
971 	struct fragment *fragment, struct directory *dir_in, long long sparse)
972 {
973 	struct stat *buf = &dir_ent->inode->buf;
974 	union squashfs_inode_header inode_header;
975 	struct squashfs_base_inode_header *base = &inode_header.base;
976 	void *inode;
977 	char *filename = pathname(dir_ent);
978 	int nlink = dir_ent->inode->nlink;
979 	int xattr = read_xattrs(dir_ent);
980 
981 	switch(type) {
982 	case SQUASHFS_FILE_TYPE:
983 		if(dir_ent->inode->nlink > 1 ||
984 				byte_size >= (1LL << 32) ||
985 				start_block >= (1LL << 32) ||
986 				sparse || IS_XATTR(xattr))
987 			type = SQUASHFS_LREG_TYPE;
988 		break;
989 	case SQUASHFS_DIR_TYPE:
990 		if(dir_info->dir_is_ldir || IS_XATTR(xattr))
991 			type = SQUASHFS_LDIR_TYPE;
992 		break;
993 	case SQUASHFS_SYMLINK_TYPE:
994 		if(IS_XATTR(xattr))
995 			type = SQUASHFS_LSYMLINK_TYPE;
996 		break;
997 	case SQUASHFS_BLKDEV_TYPE:
998 		if(IS_XATTR(xattr))
999 			type = SQUASHFS_LBLKDEV_TYPE;
1000 		break;
1001 	case SQUASHFS_CHRDEV_TYPE:
1002 		if(IS_XATTR(xattr))
1003 			type = SQUASHFS_LCHRDEV_TYPE;
1004 		break;
1005 	case SQUASHFS_FIFO_TYPE:
1006 		if(IS_XATTR(xattr))
1007 			type = SQUASHFS_LFIFO_TYPE;
1008 		break;
1009 	case SQUASHFS_SOCKET_TYPE:
1010 		if(IS_XATTR(xattr))
1011 			type = SQUASHFS_LSOCKET_TYPE;
1012 		break;
1013 	}
1014 
1015 	base->mode = SQUASHFS_MODE(buf->st_mode);
1016 	base->uid = get_uid((unsigned int) global_uid == -1 ?
1017 		buf->st_uid : global_uid, 1);
1018 	base->inode_type = type;
1019 	base->guid = get_guid((unsigned int) global_gid == -1 ?
1020 		buf->st_gid : global_gid, 1);
1021 	base->mtime = buf->st_mtime;
1022 	base->inode_number = get_inode_no(dir_ent->inode);
1023 
1024 	if(type == SQUASHFS_FILE_TYPE) {
1025 		int i;
1026 		struct squashfs_reg_inode_header *reg = &inode_header.reg;
1027 		size_t off = offsetof(struct squashfs_reg_inode_header, block_list);
1028 /* ANDROID CHANGES START*/
1029 #ifdef ANDROID
1030 		unsigned long long total_size = 0;
1031 		char *sub_path;
1032 #endif
1033 /* ANDROID CHANGES END */
1034 
1035 		inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
1036 		reg->file_size = byte_size;
1037 		reg->start_block = start_block;
1038 		reg->fragment = fragment->index;
1039 		reg->offset = fragment->offset;
1040 		SQUASHFS_SWAP_REG_INODE_HEADER(reg, inode);
1041 		SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
1042 		TRACE("File inode, file_size %lld, start_block 0x%llx, blocks "
1043 			"%d, fragment %d, offset %d, size %d\n", byte_size,
1044 			start_block, offset, fragment->index, fragment->offset,
1045 			fragment->size);
1046 		for(i = 0; i < offset; i++) {
1047 			TRACE("Block %d, size %d\n", i, block_list[i]);
1048 			total_size += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
1049 		}
1050 /* ANDROID CHANGES START*/
1051 #ifdef ANDROID
1052 		sub_path = subpathname(dir_ent);
1053 		if (block_map_file && fragment->index == -1) {
1054 			write_block_map_entry(sub_path, start_block, total_size, mount_point, block_map_file);
1055 		}
1056 #endif
1057 /* ANDROID CHANGES END */
1058 	}
1059 	else if(type == SQUASHFS_LREG_TYPE) {
1060 /* ANDROID CHANGES START*/
1061 #ifdef ANDROID
1062 		unsigned long long total_size = 0;
1063 		char *sub_path;
1064 #endif
1065 /* ANDROID CHANGES END */
1066 		int i;
1067 		struct squashfs_lreg_inode_header *reg = &inode_header.lreg;
1068 		size_t off = offsetof(struct squashfs_lreg_inode_header, block_list);
1069 
1070 		inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int));
1071 		reg->nlink = nlink;
1072 		reg->file_size = byte_size;
1073 		reg->start_block = start_block;
1074 		reg->fragment = fragment->index;
1075 		reg->offset = fragment->offset;
1076 		if(sparse && sparse >= byte_size)
1077 			sparse = byte_size - 1;
1078 		reg->sparse = sparse;
1079 		reg->xattr = xattr;
1080 		SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inode);
1081 		SQUASHFS_SWAP_INTS(block_list, inode + off, offset);
1082 		TRACE("Long file inode, file_size %lld, start_block 0x%llx, "
1083 			"blocks %d, fragment %d, offset %d, size %d, nlink %d"
1084 			"\n", byte_size, start_block, offset, fragment->index,
1085 			fragment->offset, fragment->size, nlink);
1086 		for(i = 0; i < offset; i++) {
1087 			TRACE("Block %d, size %d\n", i, block_list[i]);
1088 			total_size += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
1089 		}
1090 /* ANDROID CHANGES START*/
1091 #ifdef ANDROID
1092 		sub_path = subpathname(dir_ent);
1093 		if (block_map_file && fragment->index == -1) {
1094 			write_block_map_entry(sub_path, start_block, total_size, mount_point, block_map_file);
1095 		}
1096 #endif
1097 /* ANDROID CHANGES END */
1098 	}
1099 	else if(type == SQUASHFS_LDIR_TYPE) {
1100 		int i;
1101 		unsigned char *p;
1102 		struct squashfs_ldir_inode_header *dir = &inode_header.ldir;
1103 		struct cached_dir_index *index = dir_in->index;
1104 		unsigned int i_count = dir_in->i_count;
1105 		unsigned int i_size = dir_in->i_size;
1106 
1107 		if(byte_size >= 1 << 27)
1108 			BAD_ERROR("directory greater than 2^27-1 bytes!\n");
1109 
1110 		inode = get_inode(sizeof(*dir) + i_size);
1111 		dir->inode_type = SQUASHFS_LDIR_TYPE;
1112 		dir->nlink = dir_ent->dir->directory_count + 2;
1113 		dir->file_size = byte_size;
1114 		dir->offset = offset;
1115 		dir->start_block = start_block;
1116 		dir->i_count = i_count;
1117 		dir->parent_inode = get_parent_no(dir_ent->our_dir);
1118 		dir->xattr = xattr;
1119 
1120 		SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode);
1121 		p = inode + offsetof(struct squashfs_ldir_inode_header, index);
1122 		for(i = 0; i < i_count; i++) {
1123 			SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p);
1124 			p += offsetof(struct squashfs_dir_index, name);
1125 			memcpy(p, index[i].name, index[i].index.size + 1);
1126 			p += index[i].index.size + 1;
1127 		}
1128 		TRACE("Long directory inode, file_size %lld, start_block "
1129 			"0x%llx, offset 0x%x, nlink %d\n", byte_size,
1130 			start_block, offset, dir_ent->dir->directory_count + 2);
1131 	}
1132 	else if(type == SQUASHFS_DIR_TYPE) {
1133 		struct squashfs_dir_inode_header *dir = &inode_header.dir;
1134 
1135 		inode = get_inode(sizeof(*dir));
1136 		dir->nlink = dir_ent->dir->directory_count + 2;
1137 		dir->file_size = byte_size;
1138 		dir->offset = offset;
1139 		dir->start_block = start_block;
1140 		dir->parent_inode = get_parent_no(dir_ent->our_dir);
1141 		SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode);
1142 		TRACE("Directory inode, file_size %lld, start_block 0x%llx, "
1143 			"offset 0x%x, nlink %d\n", byte_size, start_block,
1144 			offset, dir_ent->dir->directory_count + 2);
1145 	}
1146 	else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) {
1147 		struct squashfs_dev_inode_header *dev = &inode_header.dev;
1148 		unsigned int major = major(buf->st_rdev);
1149 		unsigned int minor = minor(buf->st_rdev);
1150 
1151 		if(major > 0xfff) {
1152 			ERROR("Major %d out of range in device node %s, "
1153 				"truncating to %d\n", major, filename,
1154 				major & 0xfff);
1155 			major &= 0xfff;
1156 		}
1157 		if(minor > 0xfffff) {
1158 			ERROR("Minor %d out of range in device node %s, "
1159 				"truncating to %d\n", minor, filename,
1160 				minor & 0xfffff);
1161 			minor &= 0xfffff;
1162 		}
1163 		inode = get_inode(sizeof(*dev));
1164 		dev->nlink = nlink;
1165 		dev->rdev = (major << 8) | (minor & 0xff) |
1166 				((minor & ~0xff) << 12);
1167 		SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode);
1168 		TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
1169 	}
1170 	else if(type == SQUASHFS_LCHRDEV_TYPE || type == SQUASHFS_LBLKDEV_TYPE) {
1171 		struct squashfs_ldev_inode_header *dev = &inode_header.ldev;
1172 		unsigned int major = major(buf->st_rdev);
1173 		unsigned int minor = minor(buf->st_rdev);
1174 
1175 		if(major > 0xfff) {
1176 			ERROR("Major %d out of range in device node %s, "
1177 				"truncating to %d\n", major, filename,
1178 				major & 0xfff);
1179 			major &= 0xfff;
1180 		}
1181 		if(minor > 0xfffff) {
1182 			ERROR("Minor %d out of range in device node %s, "
1183 				"truncating to %d\n", minor, filename,
1184 				minor & 0xfffff);
1185 			minor &= 0xfffff;
1186 		}
1187 		inode = get_inode(sizeof(*dev));
1188 		dev->nlink = nlink;
1189 		dev->rdev = (major << 8) | (minor & 0xff) |
1190 				((minor & ~0xff) << 12);
1191 		dev->xattr = xattr;
1192 		SQUASHFS_SWAP_LDEV_INODE_HEADER(dev, inode);
1193 		TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink);
1194 	}
1195 	else if(type == SQUASHFS_SYMLINK_TYPE) {
1196 		struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
1197 		int byte = strlen(dir_ent->inode->symlink);
1198 		size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
1199 
1200 		inode = get_inode(sizeof(*symlink) + byte);
1201 		symlink->nlink = nlink;
1202 		symlink->symlink_size = byte;
1203 		SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1204 		strncpy(inode + off, dir_ent->inode->symlink, byte);
1205 		TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1206 			nlink);
1207 	}
1208 	else if(type == SQUASHFS_LSYMLINK_TYPE) {
1209 		struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
1210 		int byte = strlen(dir_ent->inode->symlink);
1211 		size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
1212 
1213 		inode = get_inode(sizeof(*symlink) + byte +
1214 						sizeof(unsigned int));
1215 		symlink->nlink = nlink;
1216 		symlink->symlink_size = byte;
1217 		SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
1218 		strncpy(inode + off, dir_ent->inode->symlink, byte);
1219 		SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
1220 		TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
1221 			nlink);
1222 	}
1223 	else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) {
1224 		struct squashfs_ipc_inode_header *ipc = &inode_header.ipc;
1225 
1226 		inode = get_inode(sizeof(*ipc));
1227 		ipc->nlink = nlink;
1228 		SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode);
1229 		TRACE("ipc inode, type %s, nlink %d\n", type ==
1230 			SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
1231 	}
1232 	else if(type == SQUASHFS_LFIFO_TYPE || type == SQUASHFS_LSOCKET_TYPE) {
1233 		struct squashfs_lipc_inode_header *ipc = &inode_header.lipc;
1234 
1235 		inode = get_inode(sizeof(*ipc));
1236 		ipc->nlink = nlink;
1237 		ipc->xattr = xattr;
1238 		SQUASHFS_SWAP_LIPC_INODE_HEADER(ipc, inode);
1239 		TRACE("ipc inode, type %s, nlink %d\n", type ==
1240 			SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink);
1241 	} else
1242 		BAD_ERROR("Unrecognised inode %d in create_inode\n", type);
1243 
1244 	*i_no = MKINODE(inode);
1245 	inode_count ++;
1246 
1247 	TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type,
1248 		base->uid, base->guid);
1249 
1250 	return TRUE;
1251 }
1252 
1253 
add_dir(squashfs_inode inode,unsigned int inode_number,char * name,int type,struct directory * dir)1254 void add_dir(squashfs_inode inode, unsigned int inode_number, char *name,
1255 	int type, struct directory *dir)
1256 {
1257 	unsigned char *buff;
1258 	struct squashfs_dir_entry idir;
1259 	unsigned int start_block = inode >> 16;
1260 	unsigned int offset = inode & 0xffff;
1261 	unsigned int size = strlen(name);
1262 	size_t name_off = offsetof(struct squashfs_dir_entry, name);
1263 
1264 	if(size > SQUASHFS_NAME_LEN) {
1265 		size = SQUASHFS_NAME_LEN;
1266 		ERROR("Filename is greater than %d characters, truncating! ..."
1267 			"\n", SQUASHFS_NAME_LEN);
1268 	}
1269 
1270 	if(dir->p + sizeof(struct squashfs_dir_entry) + size +
1271 			sizeof(struct squashfs_dir_header)
1272 			>= dir->buff + dir->size) {
1273 		buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE);
1274 		if(buff == NULL)
1275 			MEM_ERROR();
1276 
1277 		dir->p = (dir->p - dir->buff) + buff;
1278 		if(dir->entry_count_p)
1279 			dir->entry_count_p = (dir->entry_count_p - dir->buff +
1280 			buff);
1281 		dir->index_count_p = dir->index_count_p - dir->buff + buff;
1282 		dir->buff = buff;
1283 	}
1284 
1285 	if(dir->entry_count == 256 || start_block != dir->start_block ||
1286 			((dir->entry_count_p != NULL) &&
1287 			((dir->p + sizeof(struct squashfs_dir_entry) + size -
1288 			dir->index_count_p) > SQUASHFS_METADATA_SIZE)) ||
1289 			((long long) inode_number - dir->inode_number) > 32767
1290 			|| ((long long) inode_number - dir->inode_number)
1291 			< -32768) {
1292 		if(dir->entry_count_p) {
1293 			struct squashfs_dir_header dir_header;
1294 
1295 			if((dir->p + sizeof(struct squashfs_dir_entry) + size -
1296 					dir->index_count_p) >
1297 					SQUASHFS_METADATA_SIZE) {
1298 				if(dir->i_count % I_COUNT_SIZE == 0) {
1299 					dir->index = realloc(dir->index,
1300 						(dir->i_count + I_COUNT_SIZE) *
1301 						sizeof(struct cached_dir_index));
1302 					if(dir->index == NULL)
1303 						MEM_ERROR();
1304 				}
1305 				dir->index[dir->i_count].index.index =
1306 					dir->p - dir->buff;
1307 				dir->index[dir->i_count].index.size = size - 1;
1308 				dir->index[dir->i_count++].name = name;
1309 				dir->i_size += sizeof(struct squashfs_dir_index)
1310 					+ size;
1311 				dir->index_count_p = dir->p;
1312 			}
1313 
1314 			dir_header.count = dir->entry_count - 1;
1315 			dir_header.start_block = dir->start_block;
1316 			dir_header.inode_number = dir->inode_number;
1317 			SQUASHFS_SWAP_DIR_HEADER(&dir_header,
1318 				dir->entry_count_p);
1319 
1320 		}
1321 
1322 
1323 		dir->entry_count_p = dir->p;
1324 		dir->start_block = start_block;
1325 		dir->entry_count = 0;
1326 		dir->inode_number = inode_number;
1327 		dir->p += sizeof(struct squashfs_dir_header);
1328 	}
1329 
1330 	idir.offset = offset;
1331 	idir.type = type;
1332 	idir.size = size - 1;
1333 	idir.inode_number = ((long long) inode_number - dir->inode_number);
1334 	SQUASHFS_SWAP_DIR_ENTRY(&idir, dir->p);
1335 	strncpy((char *) dir->p + name_off, name, size);
1336 	dir->p += sizeof(struct squashfs_dir_entry) + size;
1337 	dir->entry_count ++;
1338 }
1339 
1340 
write_dir(squashfs_inode * inode,struct dir_info * dir_info,struct directory * dir)1341 void write_dir(squashfs_inode *inode, struct dir_info *dir_info,
1342 	struct directory *dir)
1343 {
1344 	unsigned int dir_size = dir->p - dir->buff;
1345 	int data_space = directory_cache_size - directory_cache_bytes;
1346 	unsigned int directory_block, directory_offset, i_count, index;
1347 	unsigned short c_byte;
1348 
1349 	if(data_space < dir_size) {
1350 		int realloc_size = directory_cache_size == 0 ?
1351 			((dir_size + SQUASHFS_METADATA_SIZE) &
1352 			~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space;
1353 
1354 		void *dc = realloc(directory_data_cache,
1355 			directory_cache_size + realloc_size);
1356 		if(dc == NULL)
1357 			MEM_ERROR();
1358 		directory_cache_size += realloc_size;
1359 		directory_data_cache = dc;
1360 	}
1361 
1362 	if(dir_size) {
1363 		struct squashfs_dir_header dir_header;
1364 
1365 		dir_header.count = dir->entry_count - 1;
1366 		dir_header.start_block = dir->start_block;
1367 		dir_header.inode_number = dir->inode_number;
1368 		SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p);
1369 		memcpy(directory_data_cache + directory_cache_bytes, dir->buff,
1370 			dir_size);
1371 	}
1372 	directory_offset = directory_cache_bytes;
1373 	directory_block = directory_bytes;
1374 	directory_cache_bytes += dir_size;
1375 	i_count = 0;
1376 	index = SQUASHFS_METADATA_SIZE - directory_offset;
1377 
1378 	while(1) {
1379 		while(i_count < dir->i_count &&
1380 				dir->index[i_count].index.index < index)
1381 			dir->index[i_count++].index.start_block =
1382 				directory_bytes;
1383 		index += SQUASHFS_METADATA_SIZE;
1384 
1385 		if(directory_cache_bytes < SQUASHFS_METADATA_SIZE)
1386 			break;
1387 
1388 		if((directory_size - directory_bytes) <
1389 					((SQUASHFS_METADATA_SIZE << 1) + 2)) {
1390 			void *dt = realloc(directory_table,
1391 				directory_size + (SQUASHFS_METADATA_SIZE << 1)
1392 				+ 2);
1393 			if(dt == NULL)
1394 				MEM_ERROR();
1395 			directory_size += SQUASHFS_METADATA_SIZE << 1;
1396 			directory_table = dt;
1397 		}
1398 
1399 		c_byte = mangle(directory_table + directory_bytes +
1400 				BLOCK_OFFSET, directory_data_cache,
1401 				SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE,
1402 				noI, 0);
1403 		TRACE("Directory block @ 0x%x, size %d\n", directory_bytes,
1404 			c_byte);
1405 		SQUASHFS_SWAP_SHORTS(&c_byte,
1406 			directory_table + directory_bytes, 1);
1407 		directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) +
1408 			BLOCK_OFFSET;
1409 		total_directory_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET;
1410 		memmove(directory_data_cache, directory_data_cache +
1411 			SQUASHFS_METADATA_SIZE, directory_cache_bytes -
1412 			SQUASHFS_METADATA_SIZE);
1413 		directory_cache_bytes -= SQUASHFS_METADATA_SIZE;
1414 	}
1415 
1416 	create_inode(inode, dir_info, dir_info->dir_ent, SQUASHFS_DIR_TYPE,
1417 		dir_size + 3, directory_block, directory_offset, NULL, NULL,
1418 		dir, 0);
1419 
1420 #ifdef SQUASHFS_TRACE
1421 	{
1422 		unsigned char *dirp;
1423 		int count;
1424 
1425 		TRACE("Directory contents of inode 0x%llx\n", *inode);
1426 		dirp = dir->buff;
1427 		while(dirp < dir->p) {
1428 			char buffer[SQUASHFS_NAME_LEN + 1];
1429 			struct squashfs_dir_entry idir, *idirp;
1430 			struct squashfs_dir_header dirh;
1431 			SQUASHFS_SWAP_DIR_HEADER((struct squashfs_dir_header *) dirp,
1432 				&dirh);
1433 			count = dirh.count + 1;
1434 			dirp += sizeof(struct squashfs_dir_header);
1435 
1436 			TRACE("\tStart block 0x%x, count %d\n",
1437 				dirh.start_block, count);
1438 
1439 			while(count--) {
1440 				idirp = (struct squashfs_dir_entry *) dirp;
1441 				SQUASHFS_SWAP_DIR_ENTRY(idirp, &idir);
1442 				strncpy(buffer, idirp->name, idir.size + 1);
1443 				buffer[idir.size + 1] = '\0';
1444 				TRACE("\t\tname %s, inode offset 0x%x, type "
1445 					"%d\n", buffer, idir.offset, idir.type);
1446 				dirp += sizeof(struct squashfs_dir_entry) + idir.size +
1447 					1;
1448 			}
1449 		}
1450 	}
1451 #endif
1452 	dir_count ++;
1453 }
1454 
1455 
get_fragment(struct fragment * fragment)1456 static struct file_buffer *get_fragment(struct fragment *fragment)
1457 {
1458 	struct squashfs_fragment_entry *disk_fragment;
1459 	struct file_buffer *buffer, *compressed_buffer;
1460 	long long start_block;
1461 	int res, size, index = fragment->index;
1462 	char locked;
1463 
1464 	/*
1465 	 * Lookup fragment block in cache.
1466 	 * If the fragment block doesn't exist, then get the compressed version
1467 	 * from the writer cache or off disk, and decompress it.
1468 	 *
1469 	 * This routine has two things which complicate the code:
1470 	 *
1471 	 *	1. Multiple threads can simultaneously lookup/create the
1472 	 *	   same buffer.  This means a buffer needs to be "locked"
1473 	 *	   when it is being filled in, to prevent other threads from
1474 	 *	   using it when it is not ready.  This is because we now do
1475 	 *	   fragment duplicate checking in parallel.
1476 	 *	2. We have two caches which need to be checked for the
1477 	 *	   presence of fragment blocks: the normal fragment cache
1478 	 *	   and a "reserve" cache.  The reserve cache is used to
1479 	 *	   prevent an unnecessary pipeline stall when the fragment cache
1480 	 *	   is full of fragments waiting to be compressed.
1481 	 */
1482 
1483 	if(fragment->index == SQUASHFS_INVALID_FRAG)
1484 		return NULL;
1485 
1486 	pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
1487 	pthread_mutex_lock(&dup_mutex);
1488 
1489 again:
1490 	buffer = cache_lookup_nowait(fragment_buffer, index, &locked);
1491 	if(buffer) {
1492 		pthread_mutex_unlock(&dup_mutex);
1493 		if(locked)
1494 			/* got a buffer being filled in.  Wait for it */
1495 			cache_wait_unlock(buffer);
1496 		goto finished;
1497 	}
1498 
1499 	/* not in fragment cache, is it in the reserve cache? */
1500 	buffer = cache_lookup_nowait(reserve_cache, index, &locked);
1501 	if(buffer) {
1502 		pthread_mutex_unlock(&dup_mutex);
1503 		if(locked)
1504 			/* got a buffer being filled in.  Wait for it */
1505 			cache_wait_unlock(buffer);
1506 		goto finished;
1507 	}
1508 
1509 	/* in neither cache, try to get it from the fragment cache */
1510 	buffer = cache_get_nowait(fragment_buffer, index);
1511 	if(!buffer) {
1512 		/*
1513 		 * no room, get it from the reserve cache, this is
1514 		 * dimensioned so it will always have space (no more than
1515 		 * processors + 1 can have an outstanding reserve buffer)
1516 		 */
1517 		buffer = cache_get_nowait(reserve_cache, index);
1518 		if(!buffer) {
1519 			/* failsafe */
1520 			ERROR("no space in reserve cache\n");
1521 			goto again;
1522 		}
1523 	}
1524 
1525 	pthread_mutex_unlock(&dup_mutex);
1526 
1527 	compressed_buffer = cache_lookup(fwriter_buffer, index);
1528 
1529 	pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
1530 	pthread_mutex_lock(&fragment_mutex);
1531 	disk_fragment = &fragment_table[index];
1532 	size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size);
1533 	start_block = disk_fragment->start_block;
1534 	pthread_cleanup_pop(1);
1535 
1536 	if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) {
1537 		int error;
1538 		char *data;
1539 
1540 		if(compressed_buffer)
1541 			data = compressed_buffer->data;
1542 		else {
1543 			data = read_from_disk(start_block, size);
1544 			if(data == NULL) {
1545 				ERROR("Failed to read fragment from output"
1546 					" filesystem\n");
1547 				BAD_ERROR("Output filesystem corrupted?\n");
1548 			}
1549 		}
1550 
1551 		res = compressor_uncompress(comp, buffer->data, data, size,
1552 			block_size, &error);
1553 		if(res == -1)
1554 			BAD_ERROR("%s uncompress failed with error code %d\n",
1555 				comp->name, error);
1556 	} else if(compressed_buffer)
1557 		memcpy(buffer->data, compressed_buffer->data, size);
1558 	else {
1559 		res = read_fs_bytes(fd, start_block, size, buffer->data);
1560 		if(res == 0) {
1561 			ERROR("Failed to read fragment from output "
1562 				"filesystem\n");
1563 			BAD_ERROR("Output filesystem corrupted?\n");
1564 		}
1565 	}
1566 
1567 	cache_unlock(buffer);
1568 	cache_block_put(compressed_buffer);
1569 
1570 finished:
1571 	pthread_cleanup_pop(0);
1572 
1573 	return buffer;
1574 }
1575 
1576 
get_fragment_checksum(struct file_info * file)1577 unsigned short get_fragment_checksum(struct file_info *file)
1578 {
1579 	struct file_buffer *frag_buffer;
1580 	struct append_file *append;
1581 	int res, index = file->fragment->index;
1582 	unsigned short checksum;
1583 
1584 	if(index == SQUASHFS_INVALID_FRAG)
1585 		return 0;
1586 
1587 	pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
1588 	pthread_mutex_lock(&dup_mutex);
1589 	res = file->have_frag_checksum;
1590 	checksum = file->fragment_checksum;
1591 	pthread_cleanup_pop(1);
1592 
1593 	if(res)
1594 		return checksum;
1595 
1596 	frag_buffer = get_fragment(file->fragment);
1597 
1598 	pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
1599 
1600 	for(append = file_mapping[index]; append; append = append->next) {
1601 		int offset = append->file->fragment->offset;
1602 		int size = append->file->fragment->size;
1603 		unsigned short cksum =
1604 			get_checksum_mem(frag_buffer->data + offset, size);
1605 
1606 		if(file == append->file)
1607 			checksum = cksum;
1608 
1609 		pthread_mutex_lock(&dup_mutex);
1610 		append->file->fragment_checksum = cksum;
1611 		append->file->have_frag_checksum = TRUE;
1612 		pthread_mutex_unlock(&dup_mutex);
1613 	}
1614 
1615 	cache_block_put(frag_buffer);
1616 	pthread_cleanup_pop(0);
1617 
1618 	return checksum;
1619 }
1620 
1621 
lock_fragments()1622 void lock_fragments()
1623 {
1624 	pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
1625 	pthread_mutex_lock(&fragment_mutex);
1626 	fragments_locked = TRUE;
1627 	pthread_cleanup_pop(1);
1628 }
1629 
1630 
unlock_fragments()1631 void unlock_fragments()
1632 {
1633 	int frg, size;
1634 	struct file_buffer *write_buffer;
1635 
1636 	pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
1637 	pthread_mutex_lock(&fragment_mutex);
1638 
1639 	/*
1640 	 * Note queue_empty() is inherently racy with respect to concurrent
1641 	 * queue get and pushes.  We avoid this because we're holding the
1642 	 * fragment_mutex which ensures no other threads can be using the
1643 	 * queue at this time.
1644 	 */
1645 	while(!queue_empty(locked_fragment)) {
1646 		write_buffer = queue_get(locked_fragment);
1647 		frg = write_buffer->block;
1648 		size = SQUASHFS_COMPRESSED_SIZE_BLOCK(fragment_table[frg].size);
1649 		fragment_table[frg].start_block = bytes;
1650 		write_buffer->block = bytes;
1651 		bytes += size;
1652 		fragments_outstanding --;
1653 		queue_put(to_writer, write_buffer);
1654 		TRACE("fragment_locked writing fragment %d, compressed size %d"
1655 			"\n", frg, size);
1656 	}
1657 	fragments_locked = FALSE;
1658 	pthread_cleanup_pop(1);
1659 }
1660 
1661 /* Called with the fragment_mutex locked */
add_pending_fragment(struct file_buffer * write_buffer,int c_byte,int fragment)1662 void add_pending_fragment(struct file_buffer *write_buffer, int c_byte,
1663 	int fragment)
1664 {
1665 	fragment_table[fragment].size = c_byte;
1666 	write_buffer->block = fragment;
1667 
1668 	queue_put(locked_fragment, write_buffer);
1669 }
1670 
1671 
write_fragment(struct file_buffer * fragment)1672 void write_fragment(struct file_buffer *fragment)
1673 {
1674 	if(fragment == NULL)
1675 		return;
1676 
1677 	pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
1678 	pthread_mutex_lock(&fragment_mutex);
1679 	fragment_table[fragment->block].unused = 0;
1680 	fragments_outstanding ++;
1681 	queue_put(to_frag, fragment);
1682 	pthread_cleanup_pop(1);
1683 }
1684 
1685 
allocate_fragment()1686 struct file_buffer *allocate_fragment()
1687 {
1688 	struct file_buffer *fragment = cache_get(fragment_buffer, fragments);
1689 
1690 	pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
1691 	pthread_mutex_lock(&fragment_mutex);
1692 
1693 	if(fragments % FRAG_SIZE == 0) {
1694 		void *ft = realloc(fragment_table, (fragments +
1695 			FRAG_SIZE) * sizeof(struct squashfs_fragment_entry));
1696 		if(ft == NULL)
1697 			MEM_ERROR();
1698 		fragment_table = ft;
1699 	}
1700 
1701 	fragment->size = 0;
1702 	fragment->block = fragments ++;
1703 
1704 	pthread_cleanup_pop(1);
1705 
1706 	return fragment;
1707 }
1708 
1709 
1710 static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0};
1711 
1712 
free_fragment(struct fragment * fragment)1713 void free_fragment(struct fragment *fragment)
1714 {
1715 	if(fragment != &empty_fragment)
1716 		free(fragment);
1717 }
1718 
1719 
get_and_fill_fragment(struct file_buffer * file_buffer,struct dir_ent * dir_ent)1720 struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer,
1721 	struct dir_ent *dir_ent)
1722 {
1723 	struct fragment *ffrg;
1724 	struct file_buffer **fragment;
1725 
1726 	if(file_buffer == NULL || file_buffer->size == 0)
1727 		return &empty_fragment;
1728 
1729 	fragment = eval_frag_actions(root_dir, dir_ent);
1730 
1731 	if((*fragment) && (*fragment)->size + file_buffer->size > block_size) {
1732 		write_fragment(*fragment);
1733 		*fragment = NULL;
1734 	}
1735 
1736 	ffrg = malloc(sizeof(struct fragment));
1737 	if(ffrg == NULL)
1738 		MEM_ERROR();
1739 
1740 	if(*fragment == NULL)
1741 		*fragment = allocate_fragment();
1742 
1743 	ffrg->index = (*fragment)->block;
1744 	ffrg->offset = (*fragment)->size;
1745 	ffrg->size = file_buffer->size;
1746 	memcpy((*fragment)->data + (*fragment)->size, file_buffer->data,
1747 		file_buffer->size);
1748 	(*fragment)->size += file_buffer->size;
1749 
1750 	return ffrg;
1751 }
1752 
1753 
generic_write_table(int length,void * buffer,int length2,void * buffer2,int uncompressed)1754 long long generic_write_table(int length, void *buffer, int length2,
1755 	void *buffer2, int uncompressed)
1756 {
1757 	int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) /
1758 		SQUASHFS_METADATA_SIZE;
1759 	long long *list, start_bytes;
1760 	int compressed_size, i, list_size = meta_blocks * sizeof(long long);
1761 	unsigned short c_byte;
1762 	char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2];
1763 
1764 #ifdef SQUASHFS_TRACE
1765 	long long obytes = bytes;
1766 	int olength = length;
1767 #endif
1768 
1769 	list = malloc(list_size);
1770 	if(list == NULL)
1771 		MEM_ERROR();
1772 
1773 	for(i = 0; i < meta_blocks; i++) {
1774 		int avail_bytes = length > SQUASHFS_METADATA_SIZE ?
1775 			SQUASHFS_METADATA_SIZE : length;
1776 		c_byte = mangle(cbuffer + BLOCK_OFFSET, buffer + i *
1777 			SQUASHFS_METADATA_SIZE , avail_bytes,
1778 			SQUASHFS_METADATA_SIZE, uncompressed, 0);
1779 		SQUASHFS_SWAP_SHORTS(&c_byte, cbuffer, 1);
1780 		list[i] = bytes;
1781 		compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) +
1782 			BLOCK_OFFSET;
1783 		TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes,
1784 			compressed_size);
1785 		write_destination(fd, bytes, compressed_size, cbuffer);
1786 		bytes += compressed_size;
1787 		total_bytes += avail_bytes;
1788 		length -= avail_bytes;
1789 	}
1790 
1791 	start_bytes = bytes;
1792 	if(length2) {
1793 		write_destination(fd, bytes, length2, buffer2);
1794 		bytes += length2;
1795 		total_bytes += length2;
1796 	}
1797 
1798 	SQUASHFS_INSWAP_LONG_LONGS(list, meta_blocks);
1799 	write_destination(fd, bytes, list_size, list);
1800 	bytes += list_size;
1801 	total_bytes += list_size;
1802 
1803 	TRACE("generic_write_table: total uncompressed %d compressed %lld\n",
1804 		olength, bytes - obytes);
1805 
1806 	free(list);
1807 
1808 	return start_bytes;
1809 }
1810 
1811 
write_fragment_table()1812 long long write_fragment_table()
1813 {
1814 	unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments);
1815 	int i;
1816 
1817 	TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments,
1818 		frag_bytes);
1819 	for(i = 0; i < fragments; i++) {
1820 		TRACE("write_fragment_table: fragment %d, start_block 0x%llx, "
1821 			"size %d\n", i, fragment_table[i].start_block,
1822 			fragment_table[i].size);
1823 		SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]);
1824 	}
1825 
1826 	return generic_write_table(frag_bytes, fragment_table, 0, NULL, noF);
1827 }
1828 
1829 
1830 char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE];
read_from_disk(long long start,unsigned int avail_bytes)1831 static char *read_from_disk(long long start, unsigned int avail_bytes)
1832 {
1833 	int res;
1834 
1835 	res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer);
1836 	if(res == 0)
1837 		return NULL;
1838 
1839 	return read_from_file_buffer;
1840 }
1841 
1842 
1843 char read_from_file_buffer2[SQUASHFS_FILE_MAX_SIZE];
read_from_disk2(long long start,unsigned int avail_bytes)1844 char *read_from_disk2(long long start, unsigned int avail_bytes)
1845 {
1846 	int res;
1847 
1848 	res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2);
1849 	if(res == 0)
1850 		return NULL;
1851 
1852 	return read_from_file_buffer2;
1853 }
1854 
1855 
1856 /*
1857  * Compute 16 bit BSD checksum over the data
1858  */
get_checksum(char * buff,int bytes,unsigned short chksum)1859 unsigned short get_checksum(char *buff, int bytes, unsigned short chksum)
1860 {
1861 	unsigned char *b = (unsigned char *) buff;
1862 
1863 	while(bytes --) {
1864 		chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1;
1865 		chksum += *b++;
1866 	}
1867 
1868 	return chksum;
1869 }
1870 
1871 
get_checksum_disk(long long start,long long l,unsigned int * blocks)1872 unsigned short get_checksum_disk(long long start, long long l,
1873 	unsigned int *blocks)
1874 {
1875 	unsigned short chksum = 0;
1876 	unsigned int bytes;
1877 	struct file_buffer *write_buffer;
1878 	int i;
1879 
1880 	for(i = 0; l; i++)  {
1881 		bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]);
1882 		if(bytes == 0) /* sparse block */
1883 			continue;
1884 		write_buffer = cache_lookup(bwriter_buffer, start);
1885 		if(write_buffer) {
1886 			chksum = get_checksum(write_buffer->data, bytes,
1887 				chksum);
1888 			cache_block_put(write_buffer);
1889 		} else {
1890 			void *data = read_from_disk(start, bytes);
1891 			if(data == NULL) {
1892 				ERROR("Failed to checksum data from output"
1893 					" filesystem\n");
1894 				BAD_ERROR("Output filesystem corrupted?\n");
1895 			}
1896 
1897 			chksum = get_checksum(data, bytes, chksum);
1898 		}
1899 
1900 		l -= bytes;
1901 		start += bytes;
1902 	}
1903 
1904 	return chksum;
1905 }
1906 
1907 
get_checksum_mem(char * buff,int bytes)1908 unsigned short get_checksum_mem(char *buff, int bytes)
1909 {
1910 	return get_checksum(buff, bytes, 0);
1911 }
1912 
1913 
get_checksum_mem_buffer(struct file_buffer * file_buffer)1914 unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer)
1915 {
1916 	if(file_buffer == NULL)
1917 		return 0;
1918 	else
1919 		return get_checksum(file_buffer->data, file_buffer->size, 0);
1920 }
1921 
1922 
1923 #define DUP_HASH(a) (a & 0xffff)
add_file(long long start,long long file_size,long long file_bytes,unsigned int * block_listp,int blocks,unsigned int fragment,int offset,int bytes)1924 void add_file(long long start, long long file_size, long long file_bytes,
1925 	unsigned int *block_listp, int blocks, unsigned int fragment,
1926 	int offset, int bytes)
1927 {
1928 	struct fragment *frg;
1929 	unsigned int *block_list = block_listp;
1930 	struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
1931 	struct append_file *append_file;
1932 	struct file_info *file;
1933 
1934 	if(!duplicate_checking || file_size == 0)
1935 		return;
1936 
1937 	for(; dupl_ptr; dupl_ptr = dupl_ptr->next) {
1938 		if(file_size != dupl_ptr->file_size)
1939 			continue;
1940 		if(blocks != 0 && start != dupl_ptr->start)
1941 			continue;
1942 		if(fragment != dupl_ptr->fragment->index)
1943 			continue;
1944 		if(fragment != SQUASHFS_INVALID_FRAG && (offset !=
1945 				dupl_ptr->fragment->offset || bytes !=
1946 				dupl_ptr->fragment->size))
1947 			continue;
1948 		return;
1949 	}
1950 
1951 	frg = malloc(sizeof(struct fragment));
1952 	if(frg == NULL)
1953 		MEM_ERROR();
1954 
1955 	frg->index = fragment;
1956 	frg->offset = offset;
1957 	frg->size = bytes;
1958 
1959 	file = add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0,
1960 		FALSE, FALSE);
1961 
1962 	if(fragment == SQUASHFS_INVALID_FRAG)
1963 		return;
1964 
1965 	append_file = malloc(sizeof(struct append_file));
1966 	if(append_file == NULL)
1967 		MEM_ERROR();
1968 
1969 	append_file->file = file;
1970 	append_file->next = file_mapping[fragment];
1971 	file_mapping[fragment] = append_file;
1972 }
1973 
1974 
pre_duplicate(long long file_size)1975 int pre_duplicate(long long file_size)
1976 {
1977 	struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
1978 
1979 	for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
1980 		if(dupl_ptr->file_size == file_size)
1981 			return TRUE;
1982 
1983 	return FALSE;
1984 }
1985 
1986 
add_non_dup(long long file_size,long long bytes,unsigned int * block_list,long long start,struct fragment * fragment,unsigned short checksum,unsigned short fragment_checksum,int checksum_flag,int checksum_frag_flag)1987 struct file_info *add_non_dup(long long file_size, long long bytes,
1988 	unsigned int *block_list, long long start, struct fragment *fragment,
1989 	unsigned short checksum, unsigned short fragment_checksum,
1990 	int checksum_flag, int checksum_frag_flag)
1991 {
1992 	struct file_info *dupl_ptr = malloc(sizeof(struct file_info));
1993 
1994 	if(dupl_ptr == NULL)
1995 		MEM_ERROR();
1996 
1997 	dupl_ptr->file_size = file_size;
1998 	dupl_ptr->bytes = bytes;
1999 	dupl_ptr->block_list = block_list;
2000 	dupl_ptr->start = start;
2001 	dupl_ptr->fragment = fragment;
2002 	dupl_ptr->checksum = checksum;
2003 	dupl_ptr->fragment_checksum = fragment_checksum;
2004 	dupl_ptr->have_frag_checksum = checksum_frag_flag;
2005 	dupl_ptr->have_checksum = checksum_flag;
2006 
2007 	pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex);
2008         pthread_mutex_lock(&dup_mutex);
2009 	dupl_ptr->next = dupl[DUP_HASH(file_size)];
2010 	dupl[DUP_HASH(file_size)] = dupl_ptr;
2011 	dup_files ++;
2012 	pthread_cleanup_pop(1);
2013 
2014 	return dupl_ptr;
2015 }
2016 
2017 
frag_duplicate(struct file_buffer * file_buffer,char * dont_put)2018 struct fragment *frag_duplicate(struct file_buffer *file_buffer, char *dont_put)
2019 {
2020 	struct file_info *dupl_ptr;
2021 	struct file_buffer *buffer;
2022 	struct file_info *dupl_start = file_buffer->dupl_start;
2023 	long long file_size = file_buffer->file_size;
2024 	unsigned short checksum = file_buffer->checksum;
2025 	int res;
2026 
2027 	if(file_buffer->duplicate) {
2028 		TRACE("Found duplicate file, fragment %d, size %d, offset %d, "
2029 			"checksum 0x%x\n", dupl_start->fragment->index,
2030 			file_size, dupl_start->fragment->offset, checksum);
2031 		*dont_put = TRUE;
2032 		return dupl_start->fragment;
2033 	} else {
2034 		*dont_put = FALSE;
2035 		dupl_ptr = dupl[DUP_HASH(file_size)];
2036 	}
2037 
2038 	for(; dupl_ptr && dupl_ptr != dupl_start; dupl_ptr = dupl_ptr->next) {
2039 		if(file_size == dupl_ptr->file_size && file_size ==
2040 				dupl_ptr->fragment->size) {
2041 			if(get_fragment_checksum(dupl_ptr) == checksum) {
2042 				buffer = get_fragment(dupl_ptr->fragment);
2043 				res = memcmp(file_buffer->data, buffer->data +
2044 					dupl_ptr->fragment->offset, file_size);
2045 				cache_block_put(buffer);
2046 				if(res == 0)
2047 					break;
2048 			}
2049 		}
2050 	}
2051 
2052 	if(!dupl_ptr || dupl_ptr == dupl_start)
2053 		return NULL;
2054 
2055 	TRACE("Found duplicate file, fragment %d, size %d, offset %d, "
2056 		"checksum 0x%x\n", dupl_ptr->fragment->index, file_size,
2057 		dupl_ptr->fragment->offset, checksum);
2058 
2059 	return dupl_ptr->fragment;
2060 }
2061 
2062 
duplicate(long long file_size,long long bytes,unsigned int ** block_list,long long * start,struct fragment ** fragment,struct file_buffer * file_buffer,int blocks,unsigned short checksum,int checksum_flag)2063 struct file_info *duplicate(long long file_size, long long bytes,
2064 	unsigned int **block_list, long long *start, struct fragment **fragment,
2065 	struct file_buffer *file_buffer, int blocks, unsigned short checksum,
2066 	int checksum_flag)
2067 {
2068 	struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)];
2069 	int frag_bytes = file_buffer ? file_buffer->size : 0;
2070 	unsigned short fragment_checksum = file_buffer ?
2071 		file_buffer->checksum : 0;
2072 
2073 	for(; dupl_ptr; dupl_ptr = dupl_ptr->next)
2074 		if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes
2075 				 && frag_bytes == dupl_ptr->fragment->size) {
2076 			long long target_start, dup_start = dupl_ptr->start;
2077 			int block;
2078 
2079 			if(memcmp(*block_list, dupl_ptr->block_list, blocks *
2080 					sizeof(unsigned int)) != 0)
2081 				continue;
2082 
2083 			if(checksum_flag == FALSE) {
2084 				checksum = get_checksum_disk(*start, bytes,
2085 					*block_list);
2086 				checksum_flag = TRUE;
2087 			}
2088 
2089 			if(!dupl_ptr->have_checksum) {
2090 				dupl_ptr->checksum =
2091 					get_checksum_disk(dupl_ptr->start,
2092 					dupl_ptr->bytes, dupl_ptr->block_list);
2093 				dupl_ptr->have_checksum = TRUE;
2094 			}
2095 
2096 			if(checksum != dupl_ptr->checksum ||
2097 					fragment_checksum !=
2098 					get_fragment_checksum(dupl_ptr))
2099 				continue;
2100 
2101 			target_start = *start;
2102 			for(block = 0; block < blocks; block ++) {
2103 				int size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2104 					((*block_list)[block]);
2105 				struct file_buffer *target_buffer = NULL;
2106 				struct file_buffer *dup_buffer = NULL;
2107 				char *target_data, *dup_data;
2108 				int res;
2109 
2110 				if(size == 0)
2111 					continue;
2112 				target_buffer = cache_lookup(bwriter_buffer,
2113 					target_start);
2114 				if(target_buffer)
2115 					target_data = target_buffer->data;
2116 				else {
2117 					target_data =
2118 						read_from_disk(target_start,
2119 						size);
2120 					if(target_data == NULL) {
2121 						ERROR("Failed to read data from"
2122 							" output filesystem\n");
2123 						BAD_ERROR("Output filesystem"
2124 							" corrupted?\n");
2125 					}
2126 				}
2127 
2128 				dup_buffer = cache_lookup(bwriter_buffer,
2129 					dup_start);
2130 				if(dup_buffer)
2131 					dup_data = dup_buffer->data;
2132 				else {
2133 					dup_data = read_from_disk2(dup_start,
2134 						size);
2135 					if(dup_data == NULL) {
2136 						ERROR("Failed to read data from"
2137 							" output filesystem\n");
2138 						BAD_ERROR("Output filesystem"
2139 							" corrupted?\n");
2140 					}
2141 				}
2142 
2143 				res = memcmp(target_data, dup_data, size);
2144 				cache_block_put(target_buffer);
2145 				cache_block_put(dup_buffer);
2146 				if(res != 0)
2147 					break;
2148 				target_start += size;
2149 				dup_start += size;
2150 			}
2151 			if(block == blocks) {
2152 				struct file_buffer *frag_buffer =
2153 					get_fragment(dupl_ptr->fragment);
2154 
2155 				if(frag_bytes == 0 ||
2156 						memcmp(file_buffer->data,
2157 						frag_buffer->data +
2158 						dupl_ptr->fragment->offset,
2159 						frag_bytes) == 0) {
2160 					TRACE("Found duplicate file, start "
2161 						"0x%llx, size %lld, checksum "
2162 						"0x%x, fragment %d, size %d, "
2163 						"offset %d, checksum 0x%x\n",
2164 						dupl_ptr->start,
2165 						dupl_ptr->bytes,
2166 						dupl_ptr->checksum,
2167 						dupl_ptr->fragment->index,
2168 						frag_bytes,
2169 						dupl_ptr->fragment->offset,
2170 						fragment_checksum);
2171 					*block_list = dupl_ptr->block_list;
2172 					*start = dupl_ptr->start;
2173 					*fragment = dupl_ptr->fragment;
2174 					cache_block_put(frag_buffer);
2175 					return 0;
2176 				}
2177 				cache_block_put(frag_buffer);
2178 			}
2179 		}
2180 
2181 
2182 	return add_non_dup(file_size, bytes, *block_list, *start, *fragment,
2183 		checksum, fragment_checksum, checksum_flag, TRUE);
2184 }
2185 
2186 
is_fragment(struct inode_info * inode)2187 static inline int is_fragment(struct inode_info *inode)
2188 {
2189 	off_t file_size = inode->buf.st_size;
2190 
2191 	/*
2192 	 * If this block is to be compressed differently to the
2193 	 * fragment compression then it cannot be a fragment
2194 	 */
2195 	if(inode->noF != noF)
2196 		return FALSE;
2197 
2198 	return !inode->no_fragments && file_size && (file_size < block_size ||
2199 		(inode->always_use_fragments && file_size & (block_size - 1)));
2200 }
2201 
2202 
put_file_buffer(struct file_buffer * file_buffer)2203 void put_file_buffer(struct file_buffer *file_buffer)
2204 {
2205 	/*
2206 	 * Decide where to send the file buffer:
2207 	 * - compressible non-fragment blocks go to the deflate threads,
2208 	 * - fragments go to the process fragment threads,
2209 	 * - all others go directly to the main thread
2210 	 */
2211 	if(file_buffer->error) {
2212 		file_buffer->fragment = 0;
2213 		seq_queue_put(to_main, file_buffer);
2214 	} else if (file_buffer->file_size == 0)
2215 		seq_queue_put(to_main, file_buffer);
2216  	else if(file_buffer->fragment)
2217 		queue_put(to_process_frag, file_buffer);
2218 	else
2219 		queue_put(to_deflate, file_buffer);
2220 }
2221 
2222 
2223 static int seq = 0;
reader_read_process(struct dir_ent * dir_ent)2224 void reader_read_process(struct dir_ent *dir_ent)
2225 {
2226 	long long bytes = 0;
2227 	struct inode_info *inode = dir_ent->inode;
2228 	struct file_buffer *prev_buffer = NULL, *file_buffer;
2229 	int status, byte, res, child;
2230 	int file = pseudo_exec_file(get_pseudo_file(inode->pseudo_id), &child);
2231 
2232 	if(!file) {
2233 		file_buffer = cache_get_nohash(reader_buffer);
2234 		file_buffer->sequence = seq ++;
2235 		goto read_err;
2236 	}
2237 
2238 	while(1) {
2239 		file_buffer = cache_get_nohash(reader_buffer);
2240 		file_buffer->sequence = seq ++;
2241 		file_buffer->noD = inode->noD;
2242 
2243 		byte = read_bytes(file, file_buffer->data, block_size);
2244 		if(byte == -1)
2245 			goto read_err2;
2246 
2247 		file_buffer->size = byte;
2248 		file_buffer->file_size = -1;
2249 		file_buffer->error = FALSE;
2250 		file_buffer->fragment = FALSE;
2251 		bytes += byte;
2252 
2253 		if(byte == 0)
2254 			break;
2255 
2256 		/*
2257 		 * Update progress bar size.  This is done
2258 		 * on every block rather than waiting for all blocks to be
2259 		 * read incase write_file_process() is running in parallel
2260 		 * with this.  Otherwise the current progress bar position
2261 		 * may get ahead of the progress bar size.
2262 		 */
2263 		progress_bar_size(1);
2264 
2265 		if(prev_buffer)
2266 			put_file_buffer(prev_buffer);
2267 		prev_buffer = file_buffer;
2268 	}
2269 
2270 	/*
2271  	 * Update inode file size now that the size of the dynamic pseudo file
2272 	 * is known.  This is needed for the -info option.
2273 	 */
2274 	inode->buf.st_size = bytes;
2275 
2276 	res = waitpid(child, &status, 0);
2277 	close(file);
2278 
2279 	if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
2280 		goto read_err;
2281 
2282 	if(prev_buffer == NULL)
2283 		prev_buffer = file_buffer;
2284 	else {
2285 		cache_block_put(file_buffer);
2286 		seq --;
2287 	}
2288 	prev_buffer->file_size = bytes;
2289 	prev_buffer->fragment = is_fragment(inode);
2290 	put_file_buffer(prev_buffer);
2291 
2292 	return;
2293 
2294 read_err2:
2295 	close(file);
2296 read_err:
2297 	if(prev_buffer) {
2298 		cache_block_put(file_buffer);
2299 		seq --;
2300 		file_buffer = prev_buffer;
2301 	}
2302 	file_buffer->error = TRUE;
2303 	put_file_buffer(file_buffer);
2304 }
2305 
2306 
reader_read_file(struct dir_ent * dir_ent)2307 void reader_read_file(struct dir_ent *dir_ent)
2308 {
2309 	struct stat *buf = &dir_ent->inode->buf, buf2;
2310 	struct file_buffer *file_buffer;
2311 	int blocks, file, res;
2312 	long long bytes, read_size;
2313 	struct inode_info *inode = dir_ent->inode;
2314 
2315 	if(inode->read)
2316 		return;
2317 
2318 	inode->read = TRUE;
2319 again:
2320 	bytes = 0;
2321 	read_size = buf->st_size;
2322 	blocks = (read_size + block_size - 1) >> block_log;
2323 
2324 	file = open(pathname_reader(dir_ent), O_RDONLY);
2325 	if(file == -1) {
2326 		file_buffer = cache_get_nohash(reader_buffer);
2327 		file_buffer->sequence = seq ++;
2328 		goto read_err2;
2329 	}
2330 
2331 	do {
2332 		file_buffer = cache_get_nohash(reader_buffer);
2333 		file_buffer->file_size = read_size;
2334 		file_buffer->sequence = seq ++;
2335 		file_buffer->noD = inode->noD;
2336 		file_buffer->error = FALSE;
2337 
2338 		/*
2339 		 * Always try to read block_size bytes from the file rather
2340 		 * than expected bytes (which will be less than the block_size
2341 		 * at the file tail) to check that the file hasn't grown
2342 		 * since being stated.  If it is longer (or shorter) than
2343 		 * expected, then restat, and try again.  Note the special
2344 		 * case where the file is an exact multiple of the block_size
2345 		 * is dealt with later.
2346 		 */
2347 		file_buffer->size = read_bytes(file, file_buffer->data,
2348 			block_size);
2349 		if(file_buffer->size == -1)
2350 			goto read_err;
2351 
2352 		bytes += file_buffer->size;
2353 
2354 		if(blocks > 1) {
2355 			/* non-tail block should be exactly block_size */
2356 			if(file_buffer->size < block_size)
2357 				goto restat;
2358 
2359 			file_buffer->fragment = FALSE;
2360 			put_file_buffer(file_buffer);
2361 		}
2362 	} while(-- blocks > 0);
2363 
2364 	/* Overall size including tail should match */
2365 	if(read_size != bytes)
2366 		goto restat;
2367 
2368 	if(read_size && read_size % block_size == 0) {
2369 		/*
2370 		 * Special case where we've not tried to read past the end of
2371 		 * the file.  We expect to get EOF, i.e. the file isn't larger
2372 		 * than we expect.
2373 		 */
2374 		char buffer;
2375 		int res;
2376 
2377 		res = read_bytes(file, &buffer, 1);
2378 		if(res == -1)
2379 			goto read_err;
2380 
2381 		if(res != 0)
2382 			goto restat;
2383 	}
2384 
2385 	file_buffer->fragment = is_fragment(inode);
2386 	put_file_buffer(file_buffer);
2387 
2388 	close(file);
2389 
2390 	return;
2391 
2392 restat:
2393 	res = fstat(file, &buf2);
2394 	if(res == -1) {
2395 		ERROR("Cannot stat dir/file %s because %s\n",
2396 			pathname_reader(dir_ent), strerror(errno));
2397 		goto read_err;
2398 	}
2399 
2400 	if(read_size != buf2.st_size) {
2401 		close(file);
2402 		memcpy(buf, &buf2, sizeof(struct stat));
2403 		file_buffer->error = 2;
2404 		put_file_buffer(file_buffer);
2405 		goto again;
2406 	}
2407 read_err:
2408 	close(file);
2409 read_err2:
2410 	file_buffer->error = TRUE;
2411 	put_file_buffer(file_buffer);
2412 }
2413 
2414 
reader_scan(struct dir_info * dir)2415 void reader_scan(struct dir_info *dir) {
2416 	struct dir_ent *dir_ent = dir->list;
2417 
2418 	for(; dir_ent; dir_ent = dir_ent->next) {
2419 		struct stat *buf = &dir_ent->inode->buf;
2420 		if(dir_ent->inode->root_entry)
2421 			continue;
2422 
2423 		if(IS_PSEUDO_PROCESS(dir_ent->inode)) {
2424 			reader_read_process(dir_ent);
2425 			continue;
2426 		}
2427 
2428 		switch(buf->st_mode & S_IFMT) {
2429 			case S_IFREG:
2430 				reader_read_file(dir_ent);
2431 				break;
2432 			case S_IFDIR:
2433 				reader_scan(dir_ent->dir);
2434 				break;
2435 		}
2436 	}
2437 }
2438 
2439 
reader(void * arg)2440 void *reader(void *arg)
2441 {
2442 	if(!sorted)
2443 		reader_scan(queue_get(to_reader));
2444 	else {
2445 		int i;
2446 		struct priority_entry *entry;
2447 
2448 		queue_get(to_reader);
2449 		for(i = 65535; i >= 0; i--)
2450 			for(entry = priority_list[i]; entry;
2451 							entry = entry->next)
2452 				reader_read_file(entry->dir);
2453 	}
2454 
2455 	pthread_exit(NULL);
2456 }
2457 
2458 
writer(void * arg)2459 void *writer(void *arg)
2460 {
2461 	while(1) {
2462 		struct file_buffer *file_buffer = queue_get(to_writer);
2463 		off_t off;
2464 
2465 		if(file_buffer == NULL) {
2466 			queue_put(from_writer, NULL);
2467 			continue;
2468 		}
2469 
2470 		off = file_buffer->block;
2471 
2472 		pthread_cleanup_push((void *) pthread_mutex_unlock, &pos_mutex);
2473 		pthread_mutex_lock(&pos_mutex);
2474 
2475 		if(lseek(fd, off, SEEK_SET) == -1) {
2476 			ERROR("writer: Lseek on destination failed because "
2477 				"%s, offset=0x%llx\n", strerror(errno), off);
2478 			BAD_ERROR("Probably out of space on output "
2479 				"%s\n", block_device ? "block device" :
2480 				"filesystem");
2481 		}
2482 
2483 		if(write_bytes(fd, file_buffer->data,
2484 				file_buffer->size) == -1)
2485 			BAD_ERROR("Failed to write to output %s\n",
2486 				block_device ? "block device" : "filesystem");
2487 
2488 		pthread_cleanup_pop(1);
2489 
2490 		cache_block_put(file_buffer);
2491 	}
2492 }
2493 
2494 
all_zero(struct file_buffer * file_buffer)2495 int all_zero(struct file_buffer *file_buffer)
2496 {
2497 	int i;
2498 	long entries = file_buffer->size / sizeof(long);
2499 	long *p = (long *) file_buffer->data;
2500 
2501 	for(i = 0; i < entries && p[i] == 0; i++);
2502 
2503 	if(i == entries) {
2504 		for(i = file_buffer->size & ~(sizeof(long) - 1);
2505 			i < file_buffer->size && file_buffer->data[i] == 0;
2506 			i++);
2507 
2508 		return i == file_buffer->size;
2509 	}
2510 
2511 	return 0;
2512 }
2513 
2514 
deflator(void * arg)2515 void *deflator(void *arg)
2516 {
2517 	struct file_buffer *write_buffer = cache_get_nohash(bwriter_buffer);
2518 	void *stream = NULL;
2519 	int res;
2520 
2521 	res = compressor_init(comp, &stream, block_size, 1);
2522 	if(res)
2523 		BAD_ERROR("deflator:: compressor_init failed\n");
2524 
2525 	while(1) {
2526 		struct file_buffer *file_buffer = queue_get(to_deflate);
2527 
2528 		if(sparse_files && all_zero(file_buffer)) {
2529 			file_buffer->c_byte = 0;
2530 			seq_queue_put(to_main, file_buffer);
2531 		} else {
2532 			write_buffer->c_byte = mangle2(stream,
2533 				write_buffer->data, file_buffer->data,
2534 				file_buffer->size, block_size,
2535 				file_buffer->noD, 1);
2536 			write_buffer->sequence = file_buffer->sequence;
2537 			write_buffer->file_size = file_buffer->file_size;
2538 			write_buffer->block = file_buffer->block;
2539 			write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK
2540 				(write_buffer->c_byte);
2541 			write_buffer->fragment = FALSE;
2542 			write_buffer->error = FALSE;
2543 			cache_block_put(file_buffer);
2544 			seq_queue_put(to_main, write_buffer);
2545 			write_buffer = cache_get_nohash(bwriter_buffer);
2546 		}
2547 	}
2548 }
2549 
2550 
frag_deflator(void * arg)2551 void *frag_deflator(void *arg)
2552 {
2553 	void *stream = NULL;
2554 	int res;
2555 
2556 	res = compressor_init(comp, &stream, block_size, 1);
2557 	if(res)
2558 		BAD_ERROR("frag_deflator:: compressor_init failed\n");
2559 
2560 	pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
2561 
2562 	while(1) {
2563 		int c_byte, compressed_size;
2564 		struct file_buffer *file_buffer = queue_get(to_frag);
2565 		struct file_buffer *write_buffer =
2566 			cache_get(fwriter_buffer, file_buffer->block);
2567 
2568 		c_byte = mangle2(stream, write_buffer->data, file_buffer->data,
2569 			file_buffer->size, block_size, noF, 1);
2570 		compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
2571 		write_buffer->size = compressed_size;
2572 		pthread_mutex_lock(&fragment_mutex);
2573 		if(fragments_locked == FALSE) {
2574 			fragment_table[file_buffer->block].size = c_byte;
2575 			fragment_table[file_buffer->block].start_block = bytes;
2576 			write_buffer->block = bytes;
2577 			bytes += compressed_size;
2578 			fragments_outstanding --;
2579 			queue_put(to_writer, write_buffer);
2580 			pthread_mutex_unlock(&fragment_mutex);
2581 			TRACE("Writing fragment %lld, uncompressed size %d, "
2582 				"compressed size %d\n", file_buffer->block,
2583 				file_buffer->size, compressed_size);
2584 		} else {
2585 				add_pending_fragment(write_buffer, c_byte,
2586 					file_buffer->block);
2587 				pthread_mutex_unlock(&fragment_mutex);
2588 		}
2589 		cache_block_put(file_buffer);
2590 	}
2591 
2592 	pthread_cleanup_pop(0);
2593 }
2594 
2595 
get_file_buffer()2596 struct file_buffer *get_file_buffer()
2597 {
2598 	struct file_buffer *file_buffer = seq_queue_get(to_main);
2599 
2600 	return file_buffer;
2601 }
2602 
2603 
write_file_empty(squashfs_inode * inode,struct dir_ent * dir_ent,struct file_buffer * file_buffer,int * duplicate_file)2604 void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent,
2605 	struct file_buffer *file_buffer, int *duplicate_file)
2606 {
2607 	file_count ++;
2608 	*duplicate_file = FALSE;
2609 	cache_block_put(file_buffer);
2610 	create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0,
2611 		 NULL, &empty_fragment, NULL, 0);
2612 }
2613 
2614 
write_file_frag(squashfs_inode * inode,struct dir_ent * dir_ent,struct file_buffer * file_buffer,int * duplicate_file)2615 void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent,
2616 	struct file_buffer *file_buffer, int *duplicate_file)
2617 {
2618 	int size = file_buffer->file_size;
2619 	struct fragment *fragment;
2620 	unsigned short checksum = file_buffer->checksum;
2621 	char dont_put;
2622 
2623 	fragment = frag_duplicate(file_buffer, &dont_put);
2624 	*duplicate_file = !fragment;
2625 	if(!fragment) {
2626 		fragment = get_and_fill_fragment(file_buffer, dir_ent);
2627 		if(duplicate_checking)
2628 			add_non_dup(size, 0, NULL, 0, fragment, 0, checksum,
2629 				TRUE, TRUE);
2630 	}
2631 
2632 	if(dont_put)
2633 		free(file_buffer);
2634 	else
2635 		cache_block_put(file_buffer);
2636 
2637 	total_bytes += size;
2638 	file_count ++;
2639 
2640 	inc_progress_bar();
2641 
2642 	create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0,
2643 			0, NULL, fragment, NULL, 0);
2644 
2645 	if(!duplicate_checking)
2646 		free_fragment(fragment);
2647 }
2648 
2649 
write_file_process(squashfs_inode * inode,struct dir_ent * dir_ent,struct file_buffer * read_buffer,int * duplicate_file)2650 int write_file_process(squashfs_inode *inode, struct dir_ent *dir_ent,
2651 	struct file_buffer *read_buffer, int *duplicate_file)
2652 {
2653 	long long read_size, file_bytes, start;
2654 	struct fragment *fragment;
2655 	unsigned int *block_list = NULL;
2656 	int block = 0, status;
2657 	long long sparse = 0;
2658 	struct file_buffer *fragment_buffer = NULL;
2659 
2660 	*duplicate_file = FALSE;
2661 
2662 	lock_fragments();
2663 
2664 	file_bytes = 0;
2665 	start = bytes;
2666 	while (1) {
2667 		read_size = read_buffer->file_size;
2668 		if(read_buffer->fragment)
2669 			fragment_buffer = read_buffer;
2670 		else {
2671 			block_list = realloc(block_list, (block + 1) *
2672 				sizeof(unsigned int));
2673 			if(block_list == NULL)
2674 				MEM_ERROR();
2675 			block_list[block ++] = read_buffer->c_byte;
2676 			if(read_buffer->c_byte) {
2677 				read_buffer->block = bytes;
2678 				bytes += read_buffer->size;
2679 				cache_hash(read_buffer, read_buffer->block);
2680 				file_bytes += read_buffer->size;
2681 				queue_put(to_writer, read_buffer);
2682 			} else {
2683 				sparse += read_buffer->size;
2684 				cache_block_put(read_buffer);
2685 			}
2686 		}
2687 		inc_progress_bar();
2688 
2689 		if(read_size != -1)
2690 			break;
2691 
2692 		read_buffer = get_file_buffer();
2693 		if(read_buffer->error)
2694 			goto read_err;
2695 	}
2696 
2697 	unlock_fragments();
2698 	fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
2699 
2700 	if(duplicate_checking)
2701 		add_non_dup(read_size, file_bytes, block_list, start, fragment,
2702 			0, fragment_buffer ? fragment_buffer->checksum : 0,
2703 			FALSE, TRUE);
2704 	cache_block_put(fragment_buffer);
2705 	file_count ++;
2706 	total_bytes += read_size;
2707 
2708 	create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2709 		 block, block_list, fragment, NULL, sparse);
2710 
2711 	if(duplicate_checking == FALSE) {
2712 		free(block_list);
2713 		free_fragment(fragment);
2714 	}
2715 
2716 	return 0;
2717 
2718 read_err:
2719 	dec_progress_bar(block);
2720 	status = read_buffer->error;
2721 	bytes = start;
2722 	if(!block_device) {
2723 		int res;
2724 
2725 		queue_put(to_writer, NULL);
2726 		if(queue_get(from_writer) != 0)
2727 			EXIT_MKSQUASHFS();
2728 		res = ftruncate(fd, bytes);
2729 		if(res != 0)
2730 			BAD_ERROR("Failed to truncate dest file because %s\n",
2731 				strerror(errno));
2732 	}
2733 	unlock_fragments();
2734 	free(block_list);
2735 	cache_block_put(read_buffer);
2736 	return status;
2737 }
2738 
2739 
write_file_blocks_dup(squashfs_inode * inode,struct dir_ent * dir_ent,struct file_buffer * read_buffer,int * duplicate_file)2740 int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent,
2741 	struct file_buffer *read_buffer, int *duplicate_file)
2742 {
2743 	int block, thresh;
2744 	long long read_size = read_buffer->file_size;
2745 	long long file_bytes, dup_start, start;
2746 	struct fragment *fragment;
2747 	struct file_info *dupl_ptr;
2748 	int blocks = (read_size + block_size - 1) >> block_log;
2749 	unsigned int *block_list, *block_listp;
2750 	struct file_buffer **buffer_list;
2751 	int status;
2752 	long long sparse = 0;
2753 	struct file_buffer *fragment_buffer = NULL;
2754 
2755 	block_list = malloc(blocks * sizeof(unsigned int));
2756 	if(block_list == NULL)
2757 		MEM_ERROR();
2758 	block_listp = block_list;
2759 
2760 	buffer_list = malloc(blocks * sizeof(struct file_buffer *));
2761 	if(buffer_list == NULL)
2762 		MEM_ERROR();
2763 
2764 	lock_fragments();
2765 
2766 	file_bytes = 0;
2767 	start = dup_start = bytes;
2768 	thresh = blocks > bwriter_size ? blocks - bwriter_size : 0;
2769 
2770 	for(block = 0; block < blocks;) {
2771 		if(read_buffer->fragment) {
2772 			block_list[block] = 0;
2773 			buffer_list[block] = NULL;
2774 			fragment_buffer = read_buffer;
2775 			blocks = read_size >> block_log;
2776 		} else {
2777 			block_list[block] = read_buffer->c_byte;
2778 
2779 			if(read_buffer->c_byte) {
2780 				read_buffer->block = bytes;
2781 				bytes += read_buffer->size;
2782 				file_bytes += read_buffer->size;
2783 				cache_hash(read_buffer, read_buffer->block);
2784 				if(block < thresh) {
2785 					buffer_list[block] = NULL;
2786 					queue_put(to_writer, read_buffer);
2787 				} else
2788 					buffer_list[block] = read_buffer;
2789 			} else {
2790 				buffer_list[block] = NULL;
2791 				sparse += read_buffer->size;
2792 				cache_block_put(read_buffer);
2793 			}
2794 		}
2795 		inc_progress_bar();
2796 
2797 		if(++block < blocks) {
2798 			read_buffer = get_file_buffer();
2799 			if(read_buffer->error)
2800 				goto read_err;
2801 		}
2802 	}
2803 
2804 	dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start,
2805 		&fragment, fragment_buffer, blocks, 0, FALSE);
2806 
2807 	if(dupl_ptr) {
2808 		*duplicate_file = FALSE;
2809 		for(block = thresh; block < blocks; block ++)
2810 			if(buffer_list[block])
2811 				queue_put(to_writer, buffer_list[block]);
2812 		fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
2813 		dupl_ptr->fragment = fragment;
2814 	} else {
2815 		*duplicate_file = TRUE;
2816 		for(block = thresh; block < blocks; block ++)
2817 			cache_block_put(buffer_list[block]);
2818 		bytes = start;
2819 		if(thresh && !block_device) {
2820 			int res;
2821 
2822 			queue_put(to_writer, NULL);
2823 			if(queue_get(from_writer) != 0)
2824 				EXIT_MKSQUASHFS();
2825 			res = ftruncate(fd, bytes);
2826 			if(res != 0)
2827 				BAD_ERROR("Failed to truncate dest file because"
2828 					"  %s\n", strerror(errno));
2829 		}
2830 	}
2831 
2832 	unlock_fragments();
2833 	cache_block_put(fragment_buffer);
2834 	free(buffer_list);
2835 	file_count ++;
2836 	total_bytes += read_size;
2837 
2838 	/*
2839 	 * sparse count is needed to ensure squashfs correctly reports a
2840  	 * a smaller block count on stat calls to sparse files.  This is
2841  	 * to ensure intelligent applications like cp correctly handle the
2842  	 * file as a sparse file.  If the file in the original filesystem isn't
2843  	 * stored as a sparse file then still store it sparsely in squashfs, but
2844  	 * report it as non-sparse on stat calls to preserve semantics
2845  	 */
2846 	if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
2847 		sparse = 0;
2848 
2849 	create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size,
2850 		dup_start, blocks, block_listp, fragment, NULL, sparse);
2851 
2852 	if(*duplicate_file == TRUE)
2853 		free(block_list);
2854 
2855 	return 0;
2856 
2857 read_err:
2858 	dec_progress_bar(block);
2859 	status = read_buffer->error;
2860 	bytes = start;
2861 	if(thresh && !block_device) {
2862 		int res;
2863 
2864 		queue_put(to_writer, NULL);
2865 		if(queue_get(from_writer) != 0)
2866 			EXIT_MKSQUASHFS();
2867 		res = ftruncate(fd, bytes);
2868 		if(res != 0)
2869 			BAD_ERROR("Failed to truncate dest file because %s\n",
2870 				strerror(errno));
2871 	}
2872 	unlock_fragments();
2873 	for(blocks = thresh; blocks < block; blocks ++)
2874 		cache_block_put(buffer_list[blocks]);
2875 	free(buffer_list);
2876 	free(block_list);
2877 	cache_block_put(read_buffer);
2878 	return status;
2879 }
2880 
2881 
write_file_blocks(squashfs_inode * inode,struct dir_ent * dir_ent,struct file_buffer * read_buffer,int * dup)2882 int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent,
2883 	struct file_buffer *read_buffer, int *dup)
2884 {
2885 	long long read_size = read_buffer->file_size;
2886 	long long file_bytes, start;
2887 	struct fragment *fragment;
2888 	unsigned int *block_list;
2889 	int block, status;
2890 	int blocks = (read_size + block_size - 1) >> block_log;
2891 	long long sparse = 0;
2892 	struct file_buffer *fragment_buffer = NULL;
2893 
2894 	if(pre_duplicate(read_size))
2895 		return write_file_blocks_dup(inode, dir_ent, read_buffer, dup);
2896 
2897 	*dup = FALSE;
2898 
2899 	block_list = malloc(blocks * sizeof(unsigned int));
2900 	if(block_list == NULL)
2901 		MEM_ERROR();
2902 
2903 	lock_fragments();
2904 
2905 	file_bytes = 0;
2906 /* ANDROID CHANGES START*/
2907 #ifdef ANDROID
2908 	if (align_4k_blocks && bytes % 4096) {
2909 		bytes += 4096 - (bytes % 4096);
2910 	}
2911 #endif
2912 /* ANDROID CHANGES END */
2913 	start = bytes;
2914 	for(block = 0; block < blocks;) {
2915 		if(read_buffer->fragment) {
2916 			block_list[block] = 0;
2917 			fragment_buffer = read_buffer;
2918 			blocks = read_size >> block_log;
2919 		} else {
2920 			block_list[block] = read_buffer->c_byte;
2921 			if(read_buffer->c_byte) {
2922 				read_buffer->block = bytes;
2923 				bytes += read_buffer->size;
2924 				cache_hash(read_buffer, read_buffer->block);
2925 				file_bytes += read_buffer->size;
2926 				queue_put(to_writer, read_buffer);
2927 			} else {
2928 				sparse += read_buffer->size;
2929 				cache_block_put(read_buffer);
2930 			}
2931 		}
2932 		inc_progress_bar();
2933 
2934 		if(++block < blocks) {
2935 			read_buffer = get_file_buffer();
2936 			if(read_buffer->error)
2937 				goto read_err;
2938 		}
2939 	}
2940 
2941 	unlock_fragments();
2942 	fragment = get_and_fill_fragment(fragment_buffer, dir_ent);
2943 
2944 	if(duplicate_checking)
2945 		add_non_dup(read_size, file_bytes, block_list, start, fragment,
2946 			0, fragment_buffer ? fragment_buffer->checksum : 0,
2947 			FALSE, TRUE);
2948 	cache_block_put(fragment_buffer);
2949 	file_count ++;
2950 	total_bytes += read_size;
2951 
2952 	/*
2953 	 * sparse count is needed to ensure squashfs correctly reports a
2954  	 * a smaller block count on stat calls to sparse files.  This is
2955  	 * to ensure intelligent applications like cp correctly handle the
2956  	 * file as a sparse file.  If the file in the original filesystem isn't
2957  	 * stored as a sparse file then still store it sparsely in squashfs, but
2958  	 * report it as non-sparse on stat calls to preserve semantics
2959  	 */
2960 	if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size)
2961 		sparse = 0;
2962 
2963 	create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start,
2964 		 blocks, block_list, fragment, NULL, sparse);
2965 
2966 	if(duplicate_checking == FALSE) {
2967 		free(block_list);
2968 		free_fragment(fragment);
2969 	}
2970 
2971 	return 0;
2972 
2973 read_err:
2974 	dec_progress_bar(block);
2975 	status = read_buffer->error;
2976 	bytes = start;
2977 	if(!block_device) {
2978 		int res;
2979 
2980 		queue_put(to_writer, NULL);
2981 		if(queue_get(from_writer) != 0)
2982 			EXIT_MKSQUASHFS();
2983 		res = ftruncate(fd, bytes);
2984 		if(res != 0)
2985 			BAD_ERROR("Failed to truncate dest file because %s\n",
2986 				strerror(errno));
2987 	}
2988 	unlock_fragments();
2989 	free(block_list);
2990 	cache_block_put(read_buffer);
2991 	return status;
2992 }
2993 
2994 
write_file(squashfs_inode * inode,struct dir_ent * dir,int * dup)2995 void write_file(squashfs_inode *inode, struct dir_ent *dir, int *dup)
2996 {
2997 	int status;
2998 	struct file_buffer *read_buffer;
2999 
3000 again:
3001 	read_buffer = get_file_buffer();
3002 	status = read_buffer->error;
3003 
3004 	if(status)
3005 		cache_block_put(read_buffer);
3006 	else if(read_buffer->file_size == -1)
3007 		status = write_file_process(inode, dir, read_buffer, dup);
3008 	else if(read_buffer->file_size == 0)
3009 		write_file_empty(inode, dir, read_buffer, dup);
3010 	else if(read_buffer->fragment && read_buffer->c_byte)
3011 		write_file_frag(inode, dir, read_buffer, dup);
3012 	else
3013 		status = write_file_blocks(inode, dir, read_buffer, dup);
3014 
3015 	if(status == 2) {
3016 		ERROR("File %s changed size while reading filesystem, "
3017 			"attempting to re-read\n", pathname(dir));
3018 		goto again;
3019 	} else if(status == 1) {
3020 		ERROR_START("Failed to read file %s", pathname(dir));
3021 		ERROR_EXIT(", creating empty file\n");
3022 		write_file_empty(inode, dir, NULL, dup);
3023 	}
3024 }
3025 
3026 
3027 #define BUFF_SIZE 512
3028 char *name;
3029 char *basename_r();
3030 
getbase(char * pathname)3031 char *getbase(char *pathname)
3032 {
3033 	static char *b_buffer = NULL;
3034 	static int b_size = BUFF_SIZE;
3035 	char *result;
3036 
3037 	if(b_buffer == NULL) {
3038 		b_buffer = malloc(b_size);
3039 		if(b_buffer == NULL)
3040 			MEM_ERROR();
3041 	}
3042 
3043 	while(1) {
3044 		if(*pathname != '/') {
3045 			result = getcwd(b_buffer, b_size);
3046 			if(result == NULL && errno != ERANGE)
3047 				BAD_ERROR("Getcwd failed in getbase\n");
3048 
3049 			/* enough room for pathname + "/" + '\0' terminator? */
3050 			if(result && strlen(pathname) + 2 <=
3051 						b_size - strlen(b_buffer)) {
3052 				strcat(strcat(b_buffer, "/"), pathname);
3053 				break;
3054 			}
3055 		} else if(strlen(pathname) < b_size) {
3056 			strcpy(b_buffer, pathname);
3057 			break;
3058 		}
3059 
3060 		/* Buffer not large enough, realloc and try again */
3061 		b_buffer = realloc(b_buffer, b_size += BUFF_SIZE);
3062 		if(b_buffer == NULL)
3063 			MEM_ERROR();
3064 	}
3065 
3066 	name = b_buffer;
3067 	if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0))
3068 		return NULL;
3069 	else
3070 		return result;
3071 }
3072 
3073 
basename_r()3074 char *basename_r()
3075 {
3076 	char *s;
3077 	char *p;
3078 	int n = 1;
3079 
3080 	for(;;) {
3081 		s = name;
3082 		if(*name == '\0')
3083 			return NULL;
3084 		if(*name != '/') {
3085 			while(*name != '\0' && *name != '/') name++;
3086 			n = name - s;
3087 		}
3088 		while(*name == '/') name++;
3089 		if(strncmp(s, ".", n) == 0)
3090 			continue;
3091 		if((*name == '\0') || (strncmp(s, "..", n) == 0) ||
3092 				((p = basename_r()) == NULL)) {
3093 			s[n] = '\0';
3094 			return s;
3095 		}
3096 		if(strcmp(p, "..") == 0)
3097 			continue;
3098 		return p;
3099 	}
3100 }
3101 
3102 
lookup_inode3(struct stat * buf,int pseudo,int id,char * symlink,int bytes)3103 struct inode_info *lookup_inode3(struct stat *buf, int pseudo, int id,
3104 	char *symlink, int bytes)
3105 {
3106 	int ino_hash = INODE_HASH(buf->st_dev, buf->st_ino);
3107 	struct inode_info *inode;
3108 
3109 	/*
3110 	 * Look-up inode in hash table, if it already exists we have a
3111 	 * hard-link, so increment the nlink count and return it.
3112 	 * Don't do the look-up for directories because we don't hard-link
3113 	 * directories.
3114 	 */
3115 	if ((buf->st_mode & S_IFMT) != S_IFDIR) {
3116 		for(inode = inode_info[ino_hash]; inode; inode = inode->next) {
3117 			if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) {
3118 				inode->nlink ++;
3119 				return inode;
3120 			}
3121 		}
3122 	}
3123 
3124 	inode = malloc(sizeof(struct inode_info) + bytes);
3125 	if(inode == NULL)
3126 		MEM_ERROR();
3127 
3128 	if(bytes)
3129 		memcpy(&inode->symlink, symlink, bytes);
3130 	memcpy(&inode->buf, buf, sizeof(struct stat));
3131 	inode->read = FALSE;
3132 	inode->root_entry = FALSE;
3133 	inode->pseudo_file = pseudo;
3134 	inode->pseudo_id = id;
3135 	inode->inode = SQUASHFS_INVALID_BLK;
3136 	inode->nlink = 1;
3137 	inode->inode_number = 0;
3138 
3139 	/*
3140 	 * Copy filesystem wide defaults into inode, these filesystem
3141 	 * wide defaults may be altered on an individual inode basis by
3142 	 * user specified actions
3143 	 *
3144 	*/
3145 	inode->no_fragments = no_fragments;
3146 	inode->always_use_fragments = always_use_fragments;
3147 
3148 /* ANDROID CHANGES START*/
3149 #ifdef ANDROID
3150 	/* Check the whitelist */
3151 	inode->noD = whitelisted(buf);
3152 #else
3153 	inode->noD = noD;
3154 #endif
3155 /* ANDROID CHANGES END */
3156 
3157 	inode->noF = noF;
3158 
3159 	inode->next = inode_info[ino_hash];
3160 	inode_info[ino_hash] = inode;
3161 
3162 	return inode;
3163 }
3164 
3165 
lookup_inode2(struct stat * buf,int pseudo,int id)3166 static inline struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
3167 {
3168 	return lookup_inode3(buf, pseudo, id, NULL, 0);
3169 }
3170 
3171 
lookup_inode(struct stat * buf)3172 static inline struct inode_info *lookup_inode(struct stat *buf)
3173 {
3174 	return lookup_inode2(buf, 0, 0);
3175 }
3176 
3177 
alloc_inode_no(struct inode_info * inode,unsigned int use_this)3178 static inline void alloc_inode_no(struct inode_info *inode, unsigned int use_this)
3179 {
3180 	if (inode->inode_number == 0) {
3181 		inode->inode_number = use_this ? : inode_no ++;
3182 		if((inode->buf.st_mode & S_IFMT) == S_IFREG)
3183 			progress_bar_size((inode->buf.st_size + block_size - 1)
3184 								 >> block_log);
3185 	}
3186 }
3187 
3188 
create_dir_entry(char * name,char * source_name,char * nonstandard_pathname,struct dir_info * dir)3189 static inline struct dir_ent *create_dir_entry(char *name, char *source_name,
3190 	char *nonstandard_pathname, struct dir_info *dir)
3191 {
3192 	struct dir_ent *dir_ent = malloc(sizeof(struct dir_ent));
3193 	if(dir_ent == NULL)
3194 		MEM_ERROR();
3195 
3196 	dir_ent->name = name;
3197 	dir_ent->source_name = source_name;
3198 	dir_ent->nonstandard_pathname = nonstandard_pathname;
3199 	dir_ent->our_dir = dir;
3200 	dir_ent->inode = NULL;
3201 	dir_ent->next = NULL;
3202 /* ANDROID CHANGES START*/
3203 #ifdef ANDROID
3204 	dir_ent->capabilities = 0;
3205 #endif
3206 /* ANDROID CHANGES END */
3207 
3208 	return dir_ent;
3209 }
3210 
3211 
add_dir_entry(struct dir_ent * dir_ent,struct dir_info * sub_dir,struct inode_info * inode_info)3212 static inline void add_dir_entry(struct dir_ent *dir_ent, struct dir_info *sub_dir,
3213 	struct inode_info *inode_info)
3214 {
3215 	struct dir_info *dir = dir_ent->our_dir;
3216 
3217 	if(sub_dir)
3218 		sub_dir->dir_ent = dir_ent;
3219 
3220 /* ANDROID CHANGES START*/
3221 #ifdef ANDROID
3222 	if (android_config) {
3223 		if (mount_point) {
3224 			char *mounted_path;
3225 			char *rel_path;
3226 
3227 			alloc_mounted_path(mount_point, subpathname(dir_ent), &mounted_path);
3228 			rel_path = mounted_path;
3229 			while (rel_path && *rel_path == '/')
3230 				rel_path++;
3231 			android_fs_config(fs_config_func, rel_path, &inode_info->buf, target_out_path, &dir_ent->capabilities);
3232 			free(mounted_path);
3233 		} else {
3234 			android_fs_config(fs_config_func, pathname(dir_ent), &inode_info->buf, target_out_path, &dir_ent->capabilities);
3235 		}
3236 	}
3237 #endif
3238 /* ANDROID CHANGES END */
3239 
3240 	dir_ent->inode = inode_info;
3241 	dir_ent->dir = sub_dir;
3242 
3243 	dir_ent->next = dir->list;
3244 	dir->list = dir_ent;
3245 	dir->count++;
3246 }
3247 
add_dir_entry2(char * name,char * source_name,char * nonstandard_pathname,struct dir_info * sub_dir,struct inode_info * inode_info,struct dir_info * dir)3248 static inline void add_dir_entry2(char *name, char *source_name,
3249 	char *nonstandard_pathname, struct dir_info *sub_dir,
3250 	struct inode_info *inode_info, struct dir_info *dir)
3251 {
3252 	struct dir_ent *dir_ent = create_dir_entry(name, source_name,
3253 		nonstandard_pathname, dir);
3254 
3255 
3256 	add_dir_entry(dir_ent, sub_dir, inode_info);
3257 }
3258 
3259 
free_dir_entry(struct dir_ent * dir_ent)3260 static inline void free_dir_entry(struct dir_ent *dir_ent)
3261 {
3262 	if(dir_ent->name)
3263 		free(dir_ent->name);
3264 
3265 	if(dir_ent->source_name)
3266 		free(dir_ent->source_name);
3267 
3268 	if(dir_ent->nonstandard_pathname)
3269 		free(dir_ent->nonstandard_pathname);
3270 
3271 	/* if this entry has been associated with an inode, then we need
3272 	 * to update the inode nlink count.  Orphaned inodes are harmless, and
3273 	 * is easier to leave them than go to the bother of deleting them */
3274 	if(dir_ent->inode && !dir_ent->inode->root_entry)
3275 		dir_ent->inode->nlink --;
3276 
3277 	free(dir_ent);
3278 }
3279 
3280 
add_excluded(struct dir_info * dir)3281 static inline void add_excluded(struct dir_info *dir)
3282 {
3283 	dir->excluded ++;
3284 }
3285 
3286 
dir_scan(squashfs_inode * inode,char * pathname,struct dir_ent * (_readdir)(struct dir_info *),int progress)3287 void dir_scan(squashfs_inode *inode, char *pathname,
3288 	struct dir_ent *(_readdir)(struct dir_info *), int progress)
3289 {
3290 	struct stat buf;
3291 	struct dir_ent *dir_ent;
3292 /* ANDROID CHANGES START*/
3293 #ifdef ANDROID
3294 	uint64_t caps = 0;
3295 #endif
3296 /* ANDROID CHANGES END */
3297 
3298 	root_dir = dir_scan1(pathname, "", paths, _readdir, 1);
3299 	if(root_dir == NULL)
3300 		return;
3301 
3302 	/* Create root directory dir_ent and associated inode, and connect
3303 	 * it to the root directory dir_info structure */
3304 	dir_ent = create_dir_entry("", NULL, pathname,
3305 						scan1_opendir("", "", 0));
3306 
3307 	if(pathname[0] == '\0') {
3308 		/*
3309  		 * dummy top level directory, if multiple sources specified on
3310 		 * command line
3311 		 */
3312 		memset(&buf, 0, sizeof(buf));
3313 		buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR;
3314 		buf.st_uid = getuid();
3315 		buf.st_gid = getgid();
3316 		buf.st_mtime = time(NULL);
3317 		buf.st_dev = 0;
3318 		buf.st_ino = 0;
3319 		dir_ent->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0);
3320 	} else {
3321 		if(lstat(pathname, &buf) == -1)
3322 			/* source directory has disappeared? */
3323 			BAD_ERROR("Cannot stat source directory %s because %s\n",
3324 				pathname, strerror(errno));
3325 /* ANDROID CHANGES START*/
3326 #ifdef ANDROID
3327 		buf.st_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH | S_IFDIR; // root mode
3328 		buf.st_uid = 0;
3329 		buf.st_gid = 0;
3330 		buf.st_mtime = time(NULL);
3331 		buf.st_dev = 0;
3332 		buf.st_ino = 0;
3333 #endif
3334 /* ANDROID CHANGES END */
3335 		dir_ent->inode = lookup_inode(&buf);
3336 	}
3337 
3338 /* ANDROID CHANGES START*/
3339 #ifdef ANDROID
3340 	dir_ent->capabilities = caps;
3341 	if (android_config) {
3342 		android_fs_config(fs_config_func, "", &dir_ent->inode->buf, target_out_path, &dir_ent->capabilities);
3343 	}
3344 #endif
3345 /* ANDROID CHANGES END */
3346 
3347 	dir_ent->dir = root_dir;
3348 	root_dir->dir_ent = dir_ent;
3349 
3350 	/*
3351 	 * Process most actions and any pseudo files
3352 	 */
3353 	if(actions() || get_pseudo())
3354 		dir_scan2(root_dir, get_pseudo());
3355 
3356 	/*
3357 	 * Process move actions
3358 	 */
3359 	if(move_actions()) {
3360 		dir_scan3(root_dir);
3361 		do_move_actions();
3362 	}
3363 
3364 	/*
3365 	 * Process prune actions
3366 	 */
3367 	if(prune_actions())
3368 		dir_scan4(root_dir);
3369 
3370 	/*
3371 	 * Process empty actions
3372 	 */
3373 	if(empty_actions())
3374 		dir_scan5(root_dir);
3375 
3376  	/*
3377 	 * Sort directories and compute the inode numbers
3378 	 */
3379 	dir_scan6(root_dir);
3380 
3381 	alloc_inode_no(dir_ent->inode, root_inode_number);
3382 
3383 	eval_actions(root_dir, dir_ent);
3384 
3385 	if(sorted)
3386 		generate_file_priorities(root_dir, 0,
3387 			&root_dir->dir_ent->inode->buf);
3388 
3389 	if(appending) {
3390 		sigset_t sigmask;
3391 
3392 		restore_thread = init_restore_thread();
3393 		sigemptyset(&sigmask);
3394 		sigaddset(&sigmask, SIGINT);
3395 		sigaddset(&sigmask, SIGTERM);
3396 		sigaddset(&sigmask, SIGUSR1);
3397 		if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1)
3398 			BAD_ERROR("Failed to set signal mask\n");
3399 		write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0");
3400 	}
3401 
3402 	queue_put(to_reader, root_dir);
3403 
3404 	set_progressbar_state(progress);
3405 
3406 	if(sorted)
3407 		sort_files_and_write(root_dir);
3408 
3409 	dir_scan7(inode, root_dir);
3410 	dir_ent->inode->inode = *inode;
3411 	dir_ent->inode->type = SQUASHFS_DIR_TYPE;
3412 }
3413 
3414 
3415 /*
3416  * dir_scan1 routines...
3417  * These scan the source directories into memory for processing.
3418  * Exclude actions are processed here (in contrast to the other actions)
3419  * because they affect what is scanned.
3420  */
scan1_opendir(char * pathname,char * subpath,int depth)3421 struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth)
3422 {
3423 	struct dir_info *dir;
3424 
3425 	dir = malloc(sizeof(struct dir_info));
3426 	if(dir == NULL)
3427 		MEM_ERROR();
3428 
3429 	if(pathname[0] != '\0') {
3430 		dir->linuxdir = opendir(pathname);
3431 		if(dir->linuxdir == NULL) {
3432 			free(dir);
3433 			return NULL;
3434 		}
3435 	}
3436 
3437 	dir->pathname = strdup(pathname);
3438 	dir->subpath = strdup(subpath);
3439 	dir->count = 0;
3440 	dir->directory_count = 0;
3441 	dir->dir_is_ldir = TRUE;
3442 	dir->list = NULL;
3443 	dir->depth = depth;
3444 	dir->excluded = 0;
3445 
3446 	return dir;
3447 }
3448 
3449 
scan1_encomp_readdir(struct dir_info * dir)3450 struct dir_ent *scan1_encomp_readdir(struct dir_info *dir)
3451 {
3452 	static int index = 0;
3453 
3454 	if(dir->count < old_root_entries) {
3455 		int i;
3456 
3457 		for(i = 0; i < old_root_entries; i++) {
3458 			if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
3459 				dir->directory_count ++;
3460 			add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
3461 				&old_root_entry[i].inode, dir);
3462 		}
3463 	}
3464 
3465 	while(index < source) {
3466 		char *basename = NULL;
3467 		char *dir_name = getbase(source_path[index]);
3468 		int pass = 1, res;
3469 
3470 		if(dir_name == NULL) {
3471 			ERROR_START("Bad source directory %s",
3472 				source_path[index]);
3473 			ERROR_EXIT(" - skipping ...\n");
3474 			index ++;
3475 			continue;
3476 		}
3477 		dir_name = strdup(dir_name);
3478 		for(;;) {
3479 			struct dir_ent *dir_ent = dir->list;
3480 
3481 			for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3482 				dir_ent = dir_ent->next);
3483 			if(dir_ent == NULL)
3484 				break;
3485 			ERROR("Source directory entry %s already used! - trying"
3486 				" ", dir_name);
3487 			if(pass == 1)
3488 				basename = dir_name;
3489 			else
3490 				free(dir_name);
3491 			res = asprintf(&dir_name, "%s_%d", basename, pass++);
3492 			if(res == -1)
3493 				BAD_ERROR("asprintf failed in "
3494 					"scan1_encomp_readdir\n");
3495 			ERROR("%s\n", dir_name);
3496 		}
3497 		return create_dir_entry(dir_name, basename,
3498 			strdup(source_path[index ++]), dir);
3499 	}
3500 	return NULL;
3501 }
3502 
3503 
scan1_single_readdir(struct dir_info * dir)3504 struct dir_ent *scan1_single_readdir(struct dir_info *dir)
3505 {
3506 	struct dirent *d_name;
3507 	int i;
3508 
3509 	if(dir->count < old_root_entries) {
3510 		for(i = 0; i < old_root_entries; i++) {
3511 			if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE)
3512 				dir->directory_count ++;
3513 			add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL,
3514 				&old_root_entry[i].inode, dir);
3515 		}
3516 	}
3517 
3518 	if((d_name = readdir(dir->linuxdir)) != NULL) {
3519 		char *basename = NULL;
3520 		char *dir_name = strdup(d_name->d_name);
3521 		int pass = 1, res;
3522 
3523 		for(;;) {
3524 			struct dir_ent *dir_ent = dir->list;
3525 
3526 			for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0;
3527 				dir_ent = dir_ent->next);
3528 			if(dir_ent == NULL)
3529 				break;
3530 			ERROR("Source directory entry %s already used! - trying"
3531 				" ", dir_name);
3532 			if (pass == 1)
3533 				basename = dir_name;
3534 			else
3535 				free(dir_name);
3536 			res = asprintf(&dir_name, "%s_%d", d_name->d_name, pass++);
3537 			if(res == -1)
3538 				BAD_ERROR("asprintf failed in "
3539 					"scan1_single_readdir\n");
3540 			ERROR("%s\n", dir_name);
3541 		}
3542 		return create_dir_entry(dir_name, basename, NULL, dir);
3543 	}
3544 
3545 	return NULL;
3546 }
3547 
3548 
scan1_readdir(struct dir_info * dir)3549 struct dir_ent *scan1_readdir(struct dir_info *dir)
3550 {
3551 	struct dirent *d_name = readdir(dir->linuxdir);
3552 
3553 	return d_name ?
3554 		create_dir_entry(strdup(d_name->d_name), NULL, NULL, dir) :
3555 		NULL;
3556 }
3557 
3558 
scan1_freedir(struct dir_info * dir)3559 void scan1_freedir(struct dir_info *dir)
3560 {
3561 	if(dir->pathname[0] != '\0')
3562 		closedir(dir->linuxdir);
3563 }
3564 
3565 
dir_scan1(char * filename,char * subpath,struct pathnames * paths,struct dir_ent * (_readdir)(struct dir_info *),int depth)3566 struct dir_info *dir_scan1(char *filename, char *subpath,
3567 	struct pathnames *paths,
3568 	struct dir_ent *(_readdir)(struct dir_info *), int depth)
3569 {
3570 	struct dir_info *dir = scan1_opendir(filename, subpath, depth);
3571 	struct dir_ent *dir_ent;
3572 
3573 	if(dir == NULL) {
3574 		ERROR_START("Could not open %s", filename);
3575 		ERROR_EXIT(", skipping...\n");
3576 		return NULL;
3577 	}
3578 
3579 	while((dir_ent = _readdir(dir))) {
3580 		struct dir_info *sub_dir;
3581 		struct stat buf;
3582 		struct pathnames *new = NULL;
3583 		char *filename = pathname(dir_ent);
3584 		char *subpath = NULL;
3585 		char *dir_name = dir_ent->name;
3586 
3587 		if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0) {
3588 			free_dir_entry(dir_ent);
3589 			continue;
3590 		}
3591 
3592 		if(lstat(filename, &buf) == -1) {
3593 			ERROR_START("Cannot stat dir/file %s because %s",
3594 				filename, strerror(errno));
3595 			ERROR_EXIT(", ignoring\n");
3596 			free_dir_entry(dir_ent);
3597 			continue;
3598 		}
3599 
3600 		if((buf.st_mode & S_IFMT) != S_IFREG &&
3601 					(buf.st_mode & S_IFMT) != S_IFDIR &&
3602 					(buf.st_mode & S_IFMT) != S_IFLNK &&
3603 					(buf.st_mode & S_IFMT) != S_IFCHR &&
3604 					(buf.st_mode & S_IFMT) != S_IFBLK &&
3605 					(buf.st_mode & S_IFMT) != S_IFIFO &&
3606 					(buf.st_mode & S_IFMT) != S_IFSOCK) {
3607 			ERROR_START("File %s has unrecognised filetype %d",
3608 				filename, buf.st_mode & S_IFMT);
3609 			ERROR_EXIT(", ignoring\n");
3610 			free_dir_entry(dir_ent);
3611 			continue;
3612 		}
3613 
3614 		if((old_exclude && old_excluded(filename, &buf)) ||
3615 			(!old_exclude && excluded(dir_name, paths, &new))) {
3616 			add_excluded(dir);
3617 			free_dir_entry(dir_ent);
3618 			continue;
3619 		}
3620 
3621 		if(exclude_actions()) {
3622 			subpath = subpathname(dir_ent);
3623 
3624 			if(eval_exclude_actions(dir_name, filename, subpath,
3625 							&buf, depth, dir_ent)) {
3626 				add_excluded(dir);
3627 				free_dir_entry(dir_ent);
3628 				continue;
3629 			}
3630 		}
3631 
3632 		switch(buf.st_mode & S_IFMT) {
3633 		case S_IFDIR:
3634 			if(subpath == NULL)
3635 				subpath = subpathname(dir_ent);
3636 
3637 			sub_dir = dir_scan1(filename, subpath, new,
3638 					scan1_readdir, depth + 1);
3639 			if(sub_dir) {
3640 				dir->directory_count ++;
3641 				add_dir_entry(dir_ent, sub_dir,
3642 							lookup_inode(&buf));
3643 			} else
3644 				free_dir_entry(dir_ent);
3645 			break;
3646 		case S_IFLNK: {
3647 			int byte;
3648 			static char buff[65536]; /* overflow safe */
3649 
3650 			byte = readlink(filename, buff, 65536);
3651 			if(byte == -1) {
3652 				ERROR_START("Failed to read symlink %s",
3653 								filename);
3654 				ERROR_EXIT(", ignoring\n");
3655 			} else if(byte == 65536) {
3656 				ERROR_START("Symlink %s is greater than 65536 "
3657 							"bytes!", filename);
3658 				ERROR_EXIT(", ignoring\n");
3659 			} else {
3660 				/* readlink doesn't 0 terminate the returned
3661 				 * path */
3662 				buff[byte] = '\0';
3663 				add_dir_entry(dir_ent, NULL, lookup_inode3(&buf,
3664 							 0, 0, buff, byte + 1));
3665 			}
3666 			break;
3667 		}
3668 		default:
3669 			add_dir_entry(dir_ent, NULL, lookup_inode(&buf));
3670 		}
3671 
3672 		free(new);
3673 	}
3674 
3675 	scan1_freedir(dir);
3676 
3677 	return dir;
3678 }
3679 
3680 
3681 /*
3682  * dir_scan2 routines...
3683  * This processes most actions and any pseudo files
3684  */
scan2_readdir(struct dir_info * dir,struct dir_ent * dir_ent)3685 struct dir_ent *scan2_readdir(struct dir_info *dir, struct dir_ent *dir_ent)
3686 {
3687 	if (dir_ent == NULL)
3688 		dir_ent = dir->list;
3689 	else
3690 		dir_ent = dir_ent->next;
3691 
3692 	for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next);
3693 
3694 	return dir_ent;
3695 }
3696 
3697 
scan2_lookup(struct dir_info * dir,char * name)3698 struct dir_ent *scan2_lookup(struct dir_info *dir, char *name)
3699 {
3700 	struct dir_ent *dir_ent = dir->list;
3701 
3702 	for(; dir_ent && strcmp(dir_ent->name, name) != 0;
3703 					dir_ent = dir_ent->next);
3704 
3705 	return dir_ent;
3706 }
3707 
3708 
dir_scan2(struct dir_info * dir,struct pseudo * pseudo)3709 void dir_scan2(struct dir_info *dir, struct pseudo *pseudo)
3710 {
3711 	struct dir_ent *dir_ent = NULL;
3712 	struct pseudo_entry *pseudo_ent;
3713 	struct stat buf;
3714 	static int pseudo_ino = 1;
3715 
3716 	while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
3717 		struct inode_info *inode_info = dir_ent->inode;
3718 		struct stat *buf = &inode_info->buf;
3719 		char *name = dir_ent->name;
3720 
3721 		eval_actions(root_dir, dir_ent);
3722 
3723 		if((buf->st_mode & S_IFMT) == S_IFDIR)
3724 			dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo));
3725 	}
3726 
3727 	while((pseudo_ent = pseudo_readdir(pseudo)) != NULL) {
3728 		dir_ent = scan2_lookup(dir, pseudo_ent->name);
3729 		if(pseudo_ent->dev->type == 'm') {
3730 			struct stat *buf;
3731 			if(dir_ent == NULL) {
3732 				ERROR_START("Pseudo modify file \"%s\" does "
3733 					"not exist in source filesystem.",
3734 					pseudo_ent->pathname);
3735 				ERROR_EXIT("  Ignoring.\n");
3736 				continue;
3737 			}
3738 			if(dir_ent->inode->root_entry) {
3739 				ERROR_START("Pseudo modify file \"%s\" is a "
3740 					"pre-existing file in the filesystem "
3741 					"being appended to.  It cannot be "\
3742 					"modified.", pseudo_ent->pathname);
3743 				ERROR_EXIT("  Ignoring.\n");
3744 				continue;
3745 			}
3746 			buf = &dir_ent->inode->buf;
3747 			buf->st_mode = (buf->st_mode & S_IFMT) |
3748 				pseudo_ent->dev->mode;
3749 			buf->st_uid = pseudo_ent->dev->uid;
3750 			buf->st_gid = pseudo_ent->dev->gid;
3751 			continue;
3752 		}
3753 
3754 		if(dir_ent) {
3755 			if(dir_ent->inode->root_entry) {
3756 				ERROR_START("Pseudo file \"%s\" is a "
3757 					"pre-existing file in the filesystem "
3758 					"being appended to.",
3759 					pseudo_ent->pathname);
3760 				ERROR_EXIT("  Ignoring.\n");
3761 			} else {
3762 				ERROR_START("Pseudo file \"%s\" exists in "
3763 					"source filesystem \"%s\".",
3764 					pseudo_ent->pathname,
3765 					pathname(dir_ent));
3766 				ERROR_EXIT("\nIgnoring, exclude it (-e/-ef) to "
3767 					"override.\n");
3768 			}
3769 			continue;
3770 		}
3771 
3772 		memset(&buf, 0, sizeof(buf));
3773 		buf.st_mode = pseudo_ent->dev->mode;
3774 		buf.st_uid = pseudo_ent->dev->uid;
3775 		buf.st_gid = pseudo_ent->dev->gid;
3776 		buf.st_rdev = makedev(pseudo_ent->dev->major,
3777 			pseudo_ent->dev->minor);
3778 		buf.st_mtime = time(NULL);
3779 		buf.st_ino = pseudo_ino ++;
3780 
3781 		if(pseudo_ent->dev->type == 'd') {
3782 			struct dir_ent *dir_ent =
3783 				create_dir_entry(pseudo_ent->name, NULL,
3784 						pseudo_ent->pathname, dir);
3785 			char *subpath = strdup(subpathname(dir_ent));
3786 			struct dir_info *sub_dir = scan1_opendir("", subpath,
3787 						dir->depth + 1);
3788 			if(sub_dir == NULL) {
3789 				ERROR_START("Could not create pseudo directory "
3790 					"\"%s\"", pseudo_ent->pathname);
3791 				ERROR_EXIT(", skipping...\n");
3792 				free(subpath);
3793 				pseudo_ino --;
3794 				continue;
3795 			}
3796 			dir_scan2(sub_dir, pseudo_ent->pseudo);
3797 			dir->directory_count ++;
3798 			add_dir_entry(dir_ent, sub_dir,
3799 				lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0));
3800 		} else if(pseudo_ent->dev->type == 'f') {
3801 			add_dir_entry2(pseudo_ent->name, NULL,
3802 				pseudo_ent->pathname, NULL,
3803 				lookup_inode2(&buf, PSEUDO_FILE_PROCESS,
3804 				pseudo_ent->dev->pseudo_id), dir);
3805 		} else {
3806 			add_dir_entry2(pseudo_ent->name, NULL,
3807 				pseudo_ent->pathname, NULL,
3808 				lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir);
3809 		}
3810 	}
3811 }
3812 
3813 
3814 /*
3815  * dir_scan3 routines...
3816  * This processes the move action
3817  */
dir_scan3(struct dir_info * dir)3818 void dir_scan3(struct dir_info *dir)
3819 {
3820 	struct dir_ent *dir_ent = NULL;
3821 
3822 	while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) {
3823 
3824 		eval_move_actions(root_dir, dir_ent);
3825 
3826 		if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
3827 			dir_scan3(dir_ent->dir);
3828 	}
3829 }
3830 
3831 
3832 /*
3833  * dir_scan4 routines...
3834  * This processes the prune action.  This action is designed to do fine
3835  * grained tuning of the in-core directory structure after the exclude,
3836  * move and pseudo actions have been performed.  This allows complex
3837  * tests to be performed which are impossible at exclude time (i.e.
3838  * tests which rely on the in-core directory structure)
3839  */
free_dir(struct dir_info * dir)3840 void free_dir(struct dir_info *dir)
3841 {
3842 	struct dir_ent *dir_ent = dir->list;
3843 
3844 	while(dir_ent) {
3845 		struct dir_ent *tmp = dir_ent;
3846 
3847 		if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
3848 			free_dir(dir_ent->dir);
3849 
3850 		dir_ent = dir_ent->next;
3851 		free_dir_entry(tmp);
3852 	}
3853 
3854 	free(dir->pathname);
3855 	free(dir->subpath);
3856 	free(dir);
3857 }
3858 
3859 
dir_scan4(struct dir_info * dir)3860 void dir_scan4(struct dir_info *dir)
3861 {
3862 	struct dir_ent *dir_ent = dir->list, *prev = NULL;
3863 
3864 	while(dir_ent) {
3865 		if(dir_ent->inode->root_entry) {
3866 			prev = dir_ent;
3867 			dir_ent = dir_ent->next;
3868 			continue;
3869 		}
3870 
3871 		if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
3872 			dir_scan4(dir_ent->dir);
3873 
3874 		if(eval_prune_actions(root_dir, dir_ent)) {
3875 			struct dir_ent *tmp = dir_ent;
3876 
3877 			if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) {
3878 				free_dir(dir_ent->dir);
3879 				dir->directory_count --;
3880 			}
3881 
3882 			dir->count --;
3883 
3884 			/* remove dir_ent from list */
3885 			dir_ent = dir_ent->next;
3886 			if(prev)
3887 				prev->next = dir_ent;
3888 			else
3889 				dir->list = dir_ent;
3890 
3891 			/* free it */
3892 			free_dir_entry(tmp);
3893 
3894 			add_excluded(dir);
3895 			continue;
3896 		}
3897 
3898 		prev = dir_ent;
3899 		dir_ent = dir_ent->next;
3900 	}
3901 }
3902 
3903 
3904 /*
3905  * dir_scan5 routines...
3906  * This processes the empty action.  This action has to be processed after
3907  * all other actions because the previous exclude and move actions and the
3908  * pseudo actions affect whether a directory is empty
3909  */
dir_scan5(struct dir_info * dir)3910 void dir_scan5(struct dir_info *dir)
3911 {
3912 	struct dir_ent *dir_ent = dir->list, *prev = NULL;
3913 
3914 	while(dir_ent) {
3915 		if(dir_ent->inode->root_entry) {
3916 			prev = dir_ent;
3917 			dir_ent = dir_ent->next;
3918 			continue;
3919 		}
3920 
3921 		if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) {
3922 			dir_scan5(dir_ent->dir);
3923 
3924 			if(eval_empty_actions(root_dir, dir_ent)) {
3925 				struct dir_ent *tmp = dir_ent;
3926 
3927 				/*
3928 				 * delete sub-directory, this is by definition
3929 				 * empty
3930 				 */
3931 				free(dir_ent->dir->pathname);
3932 				free(dir_ent->dir->subpath);
3933 				free(dir_ent->dir);
3934 
3935 				/* remove dir_ent from list */
3936 				dir_ent = dir_ent->next;
3937 				if(prev)
3938 					prev->next = dir_ent;
3939 				else
3940 					dir->list = dir_ent;
3941 
3942 				/* free it */
3943 				free_dir_entry(tmp);
3944 
3945 				/* update counts */
3946 				dir->directory_count --;
3947 				dir->count --;
3948 				add_excluded(dir);
3949 				continue;
3950 			}
3951 		}
3952 
3953 		prev = dir_ent;
3954 		dir_ent = dir_ent->next;
3955 	}
3956 }
3957 
3958 
3959 /*
3960  * dir_scan6 routines...
3961  * This sorts every directory and computes the inode numbers
3962  */
3963 
3964 /*
3965  * Bottom up linked list merge sort.
3966  *
3967  * Qsort and other O(n log n) algorithms work well with arrays but not
3968  * linked lists.  Merge sort another O(n log n) sort algorithm on the other hand
3969  * is not ideal for arrays (as it needs an additonal n storage locations
3970  * as sorting is not done in place), but it is ideal for linked lists because
3971  * it doesn't require any extra storage,
3972  */
sort_directory(struct dir_info * dir)3973 void sort_directory(struct dir_info *dir)
3974 {
3975 	struct dir_ent *cur, *l1, *l2, *next;
3976 	int len1, len2, stride = 1;
3977 
3978 	if(dir->list == NULL || dir->count < 2)
3979 		return;
3980 
3981 	/*
3982 	 * We can consider our linked-list to be made up of stride length
3983 	 * sublists.  Eacn iteration around this loop merges adjacent
3984 	 * stride length sublists into larger 2*stride sublists.  We stop
3985 	 * when stride becomes equal to the entire list.
3986 	 *
3987 	 * Initially stride = 1 (by definition a sublist of 1 is sorted), and
3988 	 * these 1 element sublists are merged into 2 element sublists,  which
3989 	 * are then merged into 4 element sublists and so on.
3990 	 */
3991 	do {
3992 		l2 = dir->list; /* head of current linked list */
3993 		cur = NULL; /* empty output list */
3994 
3995 		/*
3996 		 * Iterate through the linked list, merging adjacent sublists.
3997 		 * On each interation l2 points to the next sublist pair to be
3998 		 * merged (if there's only one sublist left this is simply added
3999 		 * to the output list)
4000 		 */
4001 		while(l2) {
4002 			l1 = l2;
4003 			for(len1 = 0; l2 && len1 < stride; len1 ++, l2 = l2->next);
4004 			len2 = stride;
4005 
4006 			/*
4007 			 * l1 points to first sublist.
4008 			 * l2 points to second sublist.
4009 			 * Merge them onto the output list
4010 			 */
4011 			while(len1 && l2 && len2) {
4012 				if(strcmp(l1->name, l2->name) <= 0) {
4013 					next = l1;
4014 					l1 = l1->next;
4015 					len1 --;
4016 				} else {
4017 					next = l2;
4018 					l2 = l2->next;
4019 					len2 --;
4020 				}
4021 
4022 				if(cur) {
4023 					cur->next = next;
4024 					cur = next;
4025 				} else
4026 					dir->list = cur = next;
4027 			}
4028 			/*
4029 			 * One sublist is now empty, copy the other one onto the
4030 			 * output list
4031 			 */
4032 			for(; len1; len1 --, l1 = l1->next) {
4033 				if(cur) {
4034 					cur->next = l1;
4035 					cur = l1;
4036 				} else
4037 					dir->list = cur = l1;
4038 			}
4039 			for(; l2 && len2; len2 --, l2 = l2->next) {
4040 				if(cur) {
4041 					cur->next = l2;
4042 					cur = l2;
4043 				} else
4044 					dir->list = cur = l2;
4045 			}
4046 		}
4047 		cur->next = NULL;
4048 		stride = stride << 1;
4049 	} while(stride < dir->count);
4050 }
4051 
4052 
dir_scan6(struct dir_info * dir)4053 void dir_scan6(struct dir_info *dir)
4054 {
4055 	struct dir_ent *dir_ent;
4056 	unsigned int byte_count = 0;
4057 
4058 	sort_directory(dir);
4059 
4060 	for(dir_ent = dir->list; dir_ent; dir_ent = dir_ent->next) {
4061 		byte_count += strlen(dir_ent->name) +
4062 			sizeof(struct squashfs_dir_entry);
4063 
4064 		if(dir_ent->inode->root_entry)
4065 			continue;
4066 
4067 		alloc_inode_no(dir_ent->inode, 0);
4068 
4069 		if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR)
4070 			dir_scan6(dir_ent->dir);
4071 	}
4072 
4073 	if((dir->count < 257 && byte_count < SQUASHFS_METADATA_SIZE))
4074 		dir->dir_is_ldir = FALSE;
4075 }
4076 
4077 
4078 /*
4079  * dir_scan6 routines...
4080  * This generates the filesystem metadata and writes it out to the destination
4081  */
scan7_init_dir(struct directory * dir)4082 void scan7_init_dir(struct directory *dir)
4083 {
4084 	dir->buff = malloc(SQUASHFS_METADATA_SIZE);
4085 	if(dir->buff == NULL)
4086 		MEM_ERROR();
4087 
4088 	dir->size = SQUASHFS_METADATA_SIZE;
4089 	dir->p = dir->index_count_p = dir->buff;
4090 	dir->entry_count = 256;
4091 	dir->entry_count_p = NULL;
4092 	dir->index = NULL;
4093 	dir->i_count = dir->i_size = 0;
4094 }
4095 
4096 
scan7_readdir(struct directory * dir,struct dir_info * dir_info,struct dir_ent * dir_ent)4097 struct dir_ent *scan7_readdir(struct directory *dir, struct dir_info *dir_info,
4098 	struct dir_ent *dir_ent)
4099 {
4100 	if (dir_ent == NULL)
4101 		dir_ent = dir_info->list;
4102 	else
4103 		dir_ent = dir_ent->next;
4104 
4105 	for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next)
4106 		add_dir(dir_ent->inode->inode, dir_ent->inode->inode_number,
4107 			dir_ent->name, dir_ent->inode->type, dir);
4108 
4109 	return dir_ent;
4110 }
4111 
4112 
scan7_freedir(struct directory * dir)4113 void scan7_freedir(struct directory *dir)
4114 {
4115 	if(dir->index)
4116 		free(dir->index);
4117 	free(dir->buff);
4118 }
4119 
4120 
dir_scan7(squashfs_inode * inode,struct dir_info * dir_info)4121 void dir_scan7(squashfs_inode *inode, struct dir_info *dir_info)
4122 {
4123 	int squashfs_type;
4124 	int duplicate_file;
4125 	struct directory dir;
4126 	struct dir_ent *dir_ent = NULL;
4127 
4128 	scan7_init_dir(&dir);
4129 
4130 	while((dir_ent = scan7_readdir(&dir, dir_info, dir_ent)) != NULL) {
4131 		struct stat *buf = &dir_ent->inode->buf;
4132 
4133 		update_info(dir_ent);
4134 
4135 		if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) {
4136 			switch(buf->st_mode & S_IFMT) {
4137 				case S_IFREG:
4138 					squashfs_type = SQUASHFS_FILE_TYPE;
4139 					write_file(inode, dir_ent,
4140 						&duplicate_file);
4141 					INFO("file %s, uncompressed size %lld "
4142 						"bytes %s\n",
4143 						subpathname(dir_ent),
4144 						(long long) buf->st_size,
4145 						duplicate_file ?  "DUPLICATE" :
4146 						 "");
4147 					break;
4148 
4149 				case S_IFDIR:
4150 					squashfs_type = SQUASHFS_DIR_TYPE;
4151 					dir_scan7(inode, dir_ent->dir);
4152 					break;
4153 
4154 				case S_IFLNK:
4155 					squashfs_type = SQUASHFS_SYMLINK_TYPE;
4156 					create_inode(inode, NULL, dir_ent,
4157 						squashfs_type, 0, 0, 0, NULL,
4158 						NULL, NULL, 0);
4159 					INFO("symbolic link %s inode 0x%llx\n",
4160 						subpathname(dir_ent), *inode);
4161 					sym_count ++;
4162 					break;
4163 
4164 				case S_IFCHR:
4165 					squashfs_type = SQUASHFS_CHRDEV_TYPE;
4166 					create_inode(inode, NULL, dir_ent,
4167 						squashfs_type, 0, 0, 0, NULL,
4168 						NULL, NULL, 0);
4169 					INFO("character device %s inode 0x%llx"
4170 						"\n", subpathname(dir_ent),
4171 						*inode);
4172 					dev_count ++;
4173 					break;
4174 
4175 				case S_IFBLK:
4176 					squashfs_type = SQUASHFS_BLKDEV_TYPE;
4177 					create_inode(inode, NULL, dir_ent,
4178 						squashfs_type, 0, 0, 0, NULL,
4179 						NULL, NULL, 0);
4180 					INFO("block device %s inode 0x%llx\n",
4181 						subpathname(dir_ent), *inode);
4182 					dev_count ++;
4183 					break;
4184 
4185 				case S_IFIFO:
4186 					squashfs_type = SQUASHFS_FIFO_TYPE;
4187 					create_inode(inode, NULL, dir_ent,
4188 						squashfs_type, 0, 0, 0, NULL,
4189 						NULL, NULL, 0);
4190 					INFO("fifo %s inode 0x%llx\n",
4191 						subpathname(dir_ent), *inode);
4192 					fifo_count ++;
4193 					break;
4194 
4195 				case S_IFSOCK:
4196 					squashfs_type = SQUASHFS_SOCKET_TYPE;
4197 					create_inode(inode, NULL, dir_ent,
4198 						squashfs_type, 0, 0, 0, NULL,
4199 						NULL, NULL, 0);
4200 					INFO("unix domain socket %s inode "
4201 						"0x%llx\n",
4202 						subpathname(dir_ent), *inode);
4203 					sock_count ++;
4204 					break;
4205 
4206 				default:
4207 					BAD_ERROR("%s unrecognised file type, "
4208 						"mode is %x\n",
4209 						subpathname(dir_ent),
4210 						buf->st_mode);
4211 			}
4212 			dir_ent->inode->inode = *inode;
4213 			dir_ent->inode->type = squashfs_type;
4214 		 } else {
4215 			*inode = dir_ent->inode->inode;
4216 			squashfs_type = dir_ent->inode->type;
4217 			switch(squashfs_type) {
4218 				case SQUASHFS_FILE_TYPE:
4219 					if(!sorted)
4220 						INFO("file %s, uncompressed "
4221 							"size %lld bytes LINK"
4222 							"\n",
4223 							subpathname(dir_ent),
4224 							(long long)
4225 							buf->st_size);
4226 					break;
4227 				case SQUASHFS_SYMLINK_TYPE:
4228 					INFO("symbolic link %s inode 0x%llx "
4229 						"LINK\n", subpathname(dir_ent),
4230 						 *inode);
4231 					break;
4232 				case SQUASHFS_CHRDEV_TYPE:
4233 					INFO("character device %s inode 0x%llx "
4234 						"LINK\n", subpathname(dir_ent),
4235 						*inode);
4236 					break;
4237 				case SQUASHFS_BLKDEV_TYPE:
4238 					INFO("block device %s inode 0x%llx "
4239 						"LINK\n", subpathname(dir_ent),
4240 						*inode);
4241 					break;
4242 				case SQUASHFS_FIFO_TYPE:
4243 					INFO("fifo %s inode 0x%llx LINK\n",
4244 						subpathname(dir_ent), *inode);
4245 					break;
4246 				case SQUASHFS_SOCKET_TYPE:
4247 					INFO("unix domain socket %s inode "
4248 						"0x%llx LINK\n",
4249 						subpathname(dir_ent), *inode);
4250 					break;
4251 			}
4252 		}
4253 
4254 		add_dir(*inode, get_inode_no(dir_ent->inode), dir_ent->name,
4255 			squashfs_type, &dir);
4256 	}
4257 
4258 	write_dir(inode, dir_info, &dir);
4259 	INFO("directory %s inode 0x%llx\n", subpathname(dir_info->dir_ent),
4260 		*inode);
4261 
4262 	scan7_freedir(&dir);
4263 }
4264 
4265 
slog(unsigned int block)4266 unsigned int slog(unsigned int block)
4267 {
4268 	int i;
4269 
4270 	for(i = 12; i <= 20; i++)
4271 		if(block == (1 << i))
4272 			return i;
4273 	return 0;
4274 }
4275 
4276 
old_excluded(char * filename,struct stat * buf)4277 int old_excluded(char *filename, struct stat *buf)
4278 {
4279 	int i;
4280 
4281 	for(i = 0; i < exclude; i++)
4282 		if((exclude_paths[i].st_dev == buf->st_dev) &&
4283 				(exclude_paths[i].st_ino == buf->st_ino))
4284 			return TRUE;
4285 	return FALSE;
4286 }
4287 
4288 
4289 #define ADD_ENTRY(buf) \
4290 	if(exclude % EXCLUDE_SIZE == 0) { \
4291 		exclude_paths = realloc(exclude_paths, (exclude + EXCLUDE_SIZE) \
4292 			* sizeof(struct exclude_info)); \
4293 		if(exclude_paths == NULL) \
4294 			MEM_ERROR(); \
4295 	} \
4296 	exclude_paths[exclude].st_dev = buf.st_dev; \
4297 	exclude_paths[exclude++].st_ino = buf.st_ino;
old_add_exclude(char * path)4298 int old_add_exclude(char *path)
4299 {
4300 	int i;
4301 	char *filename;
4302 	struct stat buf;
4303 
4304 	if(path[0] == '/' || strncmp(path, "./", 2) == 0 ||
4305 			strncmp(path, "../", 3) == 0) {
4306 		if(lstat(path, &buf) == -1) {
4307 			ERROR_START("Cannot stat exclude dir/file %s because "
4308 				"%s", path, strerror(errno));
4309 			ERROR_EXIT(", ignoring\n");
4310 			return TRUE;
4311 		}
4312 		ADD_ENTRY(buf);
4313 		return TRUE;
4314 	}
4315 
4316 	for(i = 0; i < source; i++) {
4317 		int res = asprintf(&filename, "%s/%s", source_path[i], path);
4318 		if(res == -1)
4319 			BAD_ERROR("asprintf failed in old_add_exclude\n");
4320 		if(lstat(filename, &buf) == -1) {
4321 			if(!(errno == ENOENT || errno == ENOTDIR)) {
4322 				ERROR_START("Cannot stat exclude dir/file %s "
4323 					"because %s", filename, strerror(errno));
4324 				ERROR_EXIT(", ignoring\n");
4325 			}
4326 			free(filename);
4327 			continue;
4328 		}
4329 		free(filename);
4330 		ADD_ENTRY(buf);
4331 	}
4332 	return TRUE;
4333 }
4334 
4335 
add_old_root_entry(char * name,squashfs_inode inode,int inode_number,int type)4336 void add_old_root_entry(char *name, squashfs_inode inode, int inode_number,
4337 	int type)
4338 {
4339 	old_root_entry = realloc(old_root_entry,
4340 		sizeof(struct old_root_entry_info) * (old_root_entries + 1));
4341 	if(old_root_entry == NULL)
4342 		MEM_ERROR();
4343 
4344 	old_root_entry[old_root_entries].name = strdup(name);
4345 	old_root_entry[old_root_entries].inode.inode = inode;
4346 	old_root_entry[old_root_entries].inode.inode_number = inode_number;
4347 	old_root_entry[old_root_entries].inode.type = type;
4348 	old_root_entry[old_root_entries++].inode.root_entry = TRUE;
4349 }
4350 
4351 
initialise_threads(int readq,int fragq,int bwriteq,int fwriteq,int freelst,char * destination_file)4352 void initialise_threads(int readq, int fragq, int bwriteq, int fwriteq,
4353 	int freelst, char *destination_file)
4354 {
4355 	int i;
4356 	sigset_t sigmask, old_mask;
4357 	int total_mem = readq;
4358 	int reader_size;
4359 	int fragment_size;
4360 	int fwriter_size;
4361 	/*
4362 	 * bwriter_size is global because it is needed in
4363 	 * write_file_blocks_dup()
4364 	 */
4365 
4366 	/*
4367 	 * Never allow the total size of the queues to be larger than
4368 	 * physical memory
4369 	 *
4370 	 * When adding together the possibly user supplied values, make
4371 	 * sure they've not been deliberately contrived to overflow an int
4372 	 */
4373 	if(add_overflow(total_mem, fragq))
4374 		BAD_ERROR("Queue sizes rediculously too large\n");
4375 	total_mem += fragq;
4376 	if(add_overflow(total_mem, bwriteq))
4377 		BAD_ERROR("Queue sizes rediculously too large\n");
4378 	total_mem += bwriteq;
4379 	if(add_overflow(total_mem, fwriteq))
4380 		BAD_ERROR("Queue sizes rediculously too large\n");
4381 	total_mem += fwriteq;
4382 
4383 	check_usable_phys_mem(total_mem);
4384 
4385 	/*
4386 	 * convert from queue size in Mbytes to queue size in
4387 	 * blocks.
4388 	 *
4389 	 * This isn't going to overflow an int unless there exists
4390 	 * systems with more than 8 Petabytes of RAM!
4391 	 */
4392 	reader_size = readq << (20 - block_log);
4393 	fragment_size = fragq << (20 - block_log);
4394 	bwriter_size = bwriteq << (20 - block_log);
4395 	fwriter_size = fwriteq << (20 - block_log);
4396 
4397 	/*
4398 	 * setup signal handlers for the main thread, these cleanup
4399 	 * deleting the destination file, if appending the
4400 	 * handlers for SIGTERM and SIGINT will be replaced with handlers
4401 	 * allowing the user to press ^C twice to restore the existing
4402 	 * filesystem.
4403 	 *
4404 	 * SIGUSR1 is an internal signal, which is used by the sub-threads
4405 	 * to tell the main thread to terminate, deleting the destination file,
4406 	 * or if necessary restoring the filesystem on appending
4407 	 */
4408 	signal(SIGTERM, sighandler);
4409 	signal(SIGINT, sighandler);
4410 	signal(SIGUSR1, sighandler);
4411 
4412 	/* block SIGQUIT and SIGHUP, these are handled by the info thread */
4413 	sigemptyset(&sigmask);
4414 	sigaddset(&sigmask, SIGQUIT);
4415 	sigaddset(&sigmask, SIGHUP);
4416 	sigaddset(&sigmask, SIGALRM);
4417 	if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1)
4418 		BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4419 
4420 	/*
4421 	 * temporarily block these signals, so the created sub-threads
4422 	 * will ignore them, ensuring the main thread handles them
4423 	 */
4424 	sigemptyset(&sigmask);
4425 	sigaddset(&sigmask, SIGINT);
4426 	sigaddset(&sigmask, SIGTERM);
4427 	sigaddset(&sigmask, SIGUSR1);
4428 	if(pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
4429 		BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4430 
4431 	if(processors == -1) {
4432 #ifndef linux
4433 		int mib[2];
4434 		size_t len = sizeof(processors);
4435 
4436 		mib[0] = CTL_HW;
4437 #ifdef HW_AVAILCPU
4438 		mib[1] = HW_AVAILCPU;
4439 #else
4440 		mib[1] = HW_NCPU;
4441 #endif
4442 
4443 		if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
4444 			ERROR_START("Failed to get number of available "
4445 				"processors.");
4446 			ERROR_EXIT("  Defaulting to 1\n");
4447 			processors = 1;
4448 		}
4449 #else
4450 		processors = sysconf(_SC_NPROCESSORS_ONLN);
4451 #endif
4452 	}
4453 
4454 	if(multiply_overflow(processors, 3) ||
4455 			multiply_overflow(processors * 3, sizeof(pthread_t)))
4456 		BAD_ERROR("Processors too large\n");
4457 
4458 	deflator_thread = malloc(processors * 3 * sizeof(pthread_t));
4459 	if(deflator_thread == NULL)
4460 		MEM_ERROR();
4461 
4462 	frag_deflator_thread = &deflator_thread[processors];
4463 	frag_thread = &frag_deflator_thread[processors];
4464 
4465 	to_reader = queue_init(1);
4466 	to_deflate = queue_init(reader_size);
4467 	to_process_frag = queue_init(reader_size);
4468 	to_writer = queue_init(bwriter_size + fwriter_size);
4469 	from_writer = queue_init(1);
4470 	to_frag = queue_init(fragment_size);
4471 	locked_fragment = queue_init(fragment_size);
4472 	to_main = seq_queue_init();
4473 	reader_buffer = cache_init(block_size, reader_size, 0, 0);
4474 	bwriter_buffer = cache_init(block_size, bwriter_size, 1, freelst);
4475 	fwriter_buffer = cache_init(block_size, fwriter_size, 1, freelst);
4476 	fragment_buffer = cache_init(block_size, fragment_size, 1, 0);
4477 	reserve_cache = cache_init(block_size, processors + 1, 1, 0);
4478 	pthread_create(&reader_thread, NULL, reader, NULL);
4479 	pthread_create(&writer_thread, NULL, writer, NULL);
4480 	init_progress_bar();
4481 	init_info();
4482 
4483 	for(i = 0; i < processors; i++) {
4484 		if(pthread_create(&deflator_thread[i], NULL, deflator, NULL))
4485 			BAD_ERROR("Failed to create thread\n");
4486 		if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator,
4487 				NULL) != 0)
4488 			BAD_ERROR("Failed to create thread\n");
4489 		if(pthread_create(&frag_thread[i], NULL, frag_thrd,
4490 				(void *) destination_file) != 0)
4491 			BAD_ERROR("Failed to create thread\n");
4492 	}
4493 
4494 	main_thread = pthread_self();
4495 
4496 	printf("Parallel mksquashfs: Using %d processor%s\n", processors,
4497 			processors == 1 ? "" : "s");
4498 
4499 	/* Restore the signal mask for the main thread */
4500 	if(pthread_sigmask(SIG_SETMASK, &old_mask, NULL) == -1)
4501 		BAD_ERROR("Failed to set signal mask in intialise_threads\n");
4502 }
4503 
4504 
write_inode_lookup_table()4505 long long write_inode_lookup_table()
4506 {
4507 	int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count);
4508 	void *it;
4509 
4510 	if(inode_count == sinode_count)
4511 		goto skip_inode_hash_table;
4512 
4513 	it = realloc(inode_lookup_table, lookup_bytes);
4514 	if(it == NULL)
4515 		MEM_ERROR();
4516 	inode_lookup_table = it;
4517 
4518 	for(i = 0; i < INODE_HASH_SIZE; i ++) {
4519 		struct inode_info *inode;
4520 
4521 		for(inode = inode_info[i]; inode; inode = inode->next) {
4522 
4523 			inode_number = get_inode_no(inode);
4524 
4525 			/* The empty action will produce orphaned inode
4526 			 * entries in the inode_info[] table.  These
4527 			 * entries because they are orphaned will not be
4528 			 * allocated an inode number in dir_scan5(), so
4529 			 * skip any entries with the default dummy inode
4530 			 * number of 0 */
4531 			if(inode_number == 0)
4532 				continue;
4533 
4534 			SQUASHFS_SWAP_LONG_LONGS(&inode->inode,
4535 				&inode_lookup_table[inode_number - 1], 1);
4536 
4537 		}
4538 	}
4539 
4540 skip_inode_hash_table:
4541 	return generic_write_table(lookup_bytes, inode_lookup_table, 0, NULL,
4542 		noI);
4543 }
4544 
4545 
get_component(char * target,char ** targname)4546 char *get_component(char *target, char **targname)
4547 {
4548 	char *start;
4549 
4550 	while(*target == '/')
4551 		target ++;
4552 
4553 	start = target;
4554 	while(*target != '/' && *target != '\0')
4555 		target ++;
4556 
4557 	*targname = strndup(start, target - start);
4558 
4559 	while(*target == '/')
4560 		target ++;
4561 
4562 	return target;
4563 }
4564 
4565 
free_path(struct pathname * paths)4566 void free_path(struct pathname *paths)
4567 {
4568 	int i;
4569 
4570 	for(i = 0; i < paths->names; i++) {
4571 		if(paths->name[i].paths)
4572 			free_path(paths->name[i].paths);
4573 		free(paths->name[i].name);
4574 		if(paths->name[i].preg) {
4575 			regfree(paths->name[i].preg);
4576 			free(paths->name[i].preg);
4577 		}
4578 	}
4579 
4580 	free(paths);
4581 }
4582 
4583 
add_path(struct pathname * paths,char * target,char * alltarget)4584 struct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
4585 {
4586 	char *targname;
4587 	int i, error;
4588 
4589 	target = get_component(target, &targname);
4590 
4591 	if(paths == NULL) {
4592 		paths = malloc(sizeof(struct pathname));
4593 		if(paths == NULL)
4594 			MEM_ERROR();
4595 
4596 		paths->names = 0;
4597 		paths->name = NULL;
4598 	}
4599 
4600 	for(i = 0; i < paths->names; i++)
4601 		if(strcmp(paths->name[i].name, targname) == 0)
4602 			break;
4603 
4604 	if(i == paths->names) {
4605 		/* allocate new name entry */
4606 		paths->names ++;
4607 		paths->name = realloc(paths->name, (i + 1) *
4608 			sizeof(struct path_entry));
4609 		if(paths->name == NULL)
4610 			MEM_ERROR();
4611 		paths->name[i].name = targname;
4612 		paths->name[i].paths = NULL;
4613 		if(use_regex) {
4614 			paths->name[i].preg = malloc(sizeof(regex_t));
4615 			if(paths->name[i].preg == NULL)
4616 				MEM_ERROR();
4617 			error = regcomp(paths->name[i].preg, targname,
4618 				REG_EXTENDED|REG_NOSUB);
4619 			if(error) {
4620 				char str[1024]; /* overflow safe */
4621 
4622 				regerror(error, paths->name[i].preg, str, 1024);
4623 				BAD_ERROR("invalid regex %s in export %s, "
4624 					"because %s\n", targname, alltarget,
4625 					str);
4626 			}
4627 		} else
4628 			paths->name[i].preg = NULL;
4629 
4630 		if(target[0] == '\0')
4631 			/* at leaf pathname component */
4632 			paths->name[i].paths = NULL;
4633 		else
4634 			/* recurse adding child components */
4635 			paths->name[i].paths = add_path(NULL, target,
4636 				alltarget);
4637 	} else {
4638 		/* existing matching entry */
4639 		free(targname);
4640 
4641 		if(paths->name[i].paths == NULL) {
4642 			/* No sub-directory which means this is the leaf
4643 			 * component of a pre-existing exclude which subsumes
4644 			 * the exclude currently being added, in which case stop
4645 			 * adding components */
4646 		} else if(target[0] == '\0') {
4647 			/* at leaf pathname component and child components exist
4648 			 * from more specific excludes, delete as they're
4649 			 * subsumed by this exclude */
4650 			free_path(paths->name[i].paths);
4651 			paths->name[i].paths = NULL;
4652 		} else
4653 			/* recurse adding child components */
4654 			add_path(paths->name[i].paths, target, alltarget);
4655 	}
4656 
4657 	return paths;
4658 }
4659 
4660 
add_exclude(char * target)4661 void add_exclude(char *target)
4662 {
4663 
4664 	if(target[0] == '/' || strncmp(target, "./", 2) == 0 ||
4665 			strncmp(target, "../", 3) == 0)
4666 		BAD_ERROR("/, ./ and ../ prefixed excludes not supported with "
4667 			"-wildcards or -regex options\n");
4668 	else if(strncmp(target, "... ", 4) == 0)
4669 		stickypath = add_path(stickypath, target + 4, target + 4);
4670 	else
4671 		path = add_path(path, target, target);
4672 }
4673 
4674 
display_path(int depth,struct pathname * paths)4675 void display_path(int depth, struct pathname *paths)
4676 {
4677 	int i, n;
4678 
4679 	if(paths == NULL)
4680 		return;
4681 
4682 	for(i = 0; i < paths->names; i++) {
4683 		for(n = 0; n < depth; n++)
4684 			printf("\t");
4685 		printf("%d: %s\n", depth, paths->name[i].name);
4686 		display_path(depth + 1, paths->name[i].paths);
4687 	}
4688 }
4689 
4690 
display_path2(struct pathname * paths,char * string)4691 void display_path2(struct pathname *paths, char *string)
4692 {
4693 	int i;
4694 	char *path;
4695 
4696 	if(paths == NULL) {
4697 		printf("%s\n", string);
4698 		return;
4699 	}
4700 
4701 	for(i = 0; i < paths->names; i++) {
4702 		int res = asprintf(&path, "%s/%s", string, paths->name[i].name);
4703 		if(res == -1)
4704 			BAD_ERROR("asprintf failed in display_path2\n");
4705 		display_path2(paths->name[i].paths, path);
4706 		free(path);
4707 	}
4708 }
4709 
4710 
add_subdir(struct pathnames * paths,struct pathname * path)4711 struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
4712 {
4713 	int count = paths == NULL ? 0 : paths->count;
4714 
4715 	if(count % PATHS_ALLOC_SIZE == 0) {
4716 		paths = realloc(paths, sizeof(struct pathnames) +
4717 			(count + PATHS_ALLOC_SIZE) * sizeof(struct pathname *));
4718 		if(paths == NULL)
4719 			MEM_ERROR();
4720 	}
4721 
4722 	paths->path[count] = path;
4723 	paths->count = count  + 1;
4724 	return paths;
4725 }
4726 
4727 
excluded_match(char * name,struct pathname * path,struct pathnames ** new)4728 int excluded_match(char *name, struct pathname *path, struct pathnames **new)
4729 {
4730 	int i;
4731 
4732 	for(i = 0; i < path->names; i++) {
4733 		int match = use_regex ?
4734 			regexec(path->name[i].preg, name, (size_t) 0,
4735 					NULL, 0) == 0 :
4736 			fnmatch(path->name[i].name, name,
4737 				FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;
4738 
4739 		if(match) {
4740 			 if(path->name[i].paths == NULL || new == NULL)
4741 				/* match on a leaf component, any subdirectories
4742 			 	* in the filesystem should be excluded */
4743 				return TRUE;
4744 			else
4745 				/* match on a non-leaf component, add any
4746 				 * subdirectories to the new set of
4747 				 * subdirectories to scan for this name */
4748 				*new = add_subdir(*new, path->name[i].paths);
4749 		}
4750 	}
4751 
4752 	return FALSE;
4753 }
4754 
4755 
excluded(char * name,struct pathnames * paths,struct pathnames ** new)4756 int excluded(char *name, struct pathnames *paths, struct pathnames **new)
4757 {
4758 	int n;
4759 
4760 	if(stickypath && excluded_match(name, stickypath, NULL))
4761 		return TRUE;
4762 
4763 	for(n = 0; paths && n < paths->count; n++) {
4764 		int res = excluded_match(name, paths->path[n], new);
4765 		if(res) {
4766 			free(*new);
4767 			*new = NULL;
4768 			return TRUE;
4769 		}
4770 	}
4771 
4772 	/*
4773 	 * Either:
4774 	 * -  no matching names found, return empty new search set, or
4775 	 * -  one or more matches with sub-directories found (no leaf matches),
4776 	 *    in which case return new search set.
4777 	 *
4778 	 * In either case return FALSE as we don't want to exclude this entry
4779 	 */
4780 	return FALSE;
4781 }
4782 
4783 
process_exclude_file(char * argv)4784 void process_exclude_file(char *argv)
4785 {
4786 	FILE *fd;
4787 	char buffer[MAX_LINE + 1]; /* overflow safe */
4788 	char *filename;
4789 
4790 	fd = fopen(argv, "r");
4791 	if(fd == NULL)
4792 		BAD_ERROR("Failed to open exclude file \"%s\" because %s\n",
4793 			argv, strerror(errno));
4794 
4795 	while(fgets(filename = buffer, MAX_LINE + 1, fd) != NULL) {
4796 		int len = strlen(filename);
4797 
4798 		if(len == MAX_LINE && filename[len - 1] != '\n')
4799 			/* line too large */
4800 			BAD_ERROR("Line too long when reading "
4801 				"exclude file \"%s\", larger than %d "
4802 				"bytes\n", argv, MAX_LINE);
4803 
4804 		/*
4805 		 * Remove '\n' terminator if it exists (the last line
4806 		 * in the file may not be '\n' terminated)
4807 		 */
4808 		if(len && filename[len - 1] == '\n')
4809 			filename[len - 1] = '\0';
4810 
4811 		/* Skip any leading whitespace */
4812 		while(isspace(*filename))
4813 			filename ++;
4814 
4815 		/* if comment line, skip */
4816 		if(*filename == '#')
4817 			continue;
4818 
4819 		/*
4820 		 * check for initial backslash, to accommodate
4821 		 * filenames with leading space or leading # character
4822 		 */
4823 		if(*filename == '\\')
4824 			filename ++;
4825 
4826 		/* if line is now empty after skipping characters, skip it */
4827 		if(*filename == '\0')
4828 			continue;
4829 
4830 		if(old_exclude)
4831 			old_add_exclude(filename);
4832 		else
4833 			add_exclude(filename);
4834 	}
4835 
4836 	if(ferror(fd))
4837 		BAD_ERROR("Reading exclude file \"%s\" failed because %s\n",
4838 			argv, strerror(errno));
4839 
4840 	fclose(fd);
4841 }
4842 
4843 /* ANDROID CHANGES START*/
4844 #ifdef ANDROID
4845 /*
4846  * Return TRUE (don't compress) if the (regular) file is in the
4847  * whitelist. Else return the Global noD value.
4848  *
4849  * Note : These functions are lifted 100% from the existing exclude
4850  * file code. For maintainability, I've kept this code separate from
4851  * the exclude code instead of having common code for both paths.
4852  */
4853 static int
whitelisted(struct stat * buf)4854 whitelisted(struct stat *buf)
4855 {
4856 	int i;
4857 
4858 	/*
4859 	 * only regular files in the whitelist
4860 	 */
4861 	if (!S_ISREG(buf->st_mode))
4862 		return noD;
4863 	for (i = 0; i < whitelist; i++) {
4864 		if ((whitelist_paths[i].st_dev == buf->st_dev) &&
4865 		    (whitelist_paths[i].st_ino == buf->st_ino)) {
4866 			/* Don't compress */
4867 			whitelisted_count++;
4868 			return TRUE;
4869 		}
4870 	}
4871 	return noD;
4872 }
4873 
4874 static void
add_whitelist_entry(char * filename,struct stat * buf)4875 add_whitelist_entry(char *filename, struct stat *buf)
4876 {
4877 	if (!S_ISREG(buf->st_mode)) {
4878 		BAD_ERROR("Cannot whitelist %s only regular files can be whitelisted",
4879 			  filename);
4880 	}
4881 	if (whitelist % WHITELIST_SIZE == 0) {
4882 		whitelist_paths = realloc(whitelist_paths,
4883 					  (whitelist + WHITELIST_SIZE)
4884 					  * sizeof(struct whitelist_info));
4885 		if (whitelist_paths == NULL)
4886 			MEM_ERROR();
4887 	}
4888 	whitelist_paths[whitelist].st_dev = buf->st_dev;
4889 	whitelist_paths[whitelist++].st_ino = buf->st_ino;
4890 }
4891 
4892 static int
add_whitelist(char * path)4893 add_whitelist(char *path)
4894 {
4895 	int i;
4896 	char *filename;
4897 	struct stat buf;
4898 
4899 	/* Absolute of (filesystem) relative path */
4900 	if (path[0] == '/' || strncmp(path, "./", 2) == 0 ||
4901 	    strncmp(path, "../", 3) == 0) {
4902 		if(lstat(path, &buf) == -1) {
4903 			BAD_ERROR("Cannot stat whitelist dir/file %s because "
4904 				  "%s", path, strerror(errno));
4905 		}
4906 		add_whitelist_entry(path, &buf);
4907 		return TRUE;
4908 	}
4909 
4910 	/* pathname relative to mksquashfs source dirs */
4911 	for(i = 0; i < source; i++) {
4912 		int res = asprintf(&filename, "%s/%s", source_path[i], path);
4913 		if(res == -1)
4914 			BAD_ERROR("asprintf failed in add_whitelist\n");
4915 		if(lstat(filename, &buf) == -1) {
4916 			if(!(errno == ENOENT || errno == ENOTDIR)) {
4917 				BAD_ERROR("Cannot stat whitelist dir/file %s "
4918 					  "because %s", filename, strerror(errno));
4919 			}
4920 			free(filename);
4921 			continue;
4922 		}
4923 		add_whitelist_entry(filename, &buf);
4924 		free(filename);
4925 	}
4926 	return TRUE;
4927 }
4928 
4929 static void
process_whitelist_file(char * argv)4930 process_whitelist_file(char *argv)
4931 {
4932 	FILE *fd;
4933 	char buffer[MAX_LINE + 1]; /* overflow safe */
4934 	char *filename;
4935 
4936 	fd = fopen(argv, "r");
4937 	if(fd == NULL)
4938 		BAD_ERROR("Failed to open whitelist file \"%s\" because %s\n",
4939 			argv, strerror(errno));
4940 
4941 	while(fgets(filename = buffer, MAX_LINE + 1, fd) != NULL) {
4942 		int len = strlen(filename);
4943 
4944 		if(len == MAX_LINE && filename[len - 1] != '\n')
4945 			/* line too large */
4946 			BAD_ERROR("Line too long when reading "
4947 				"whitelist file \"%s\", larger than %d "
4948 				"bytes\n", argv, MAX_LINE);
4949 
4950 		/*
4951 		 * Remove '\n' terminator if it exists (the last line
4952 		 * in the file may not be '\n' terminated)
4953 		 */
4954 		if(len && filename[len - 1] == '\n')
4955 			filename[len - 1] = '\0';
4956 
4957 		/* Skip any leading whitespace */
4958 		while(isspace(*filename))
4959 			filename ++;
4960 
4961 		/* if comment line, skip */
4962 		if(*filename == '#')
4963 			continue;
4964 
4965 		/*
4966 		 * check for initial backslash, to accommodate
4967 		 * filenames with leading space or leading # character
4968 		 */
4969 		if(*filename == '\\')
4970 			filename ++;
4971 
4972 		/* if line is now empty after skipping characters, skip it */
4973 		if(*filename == '\0')
4974 			continue;
4975 
4976 		add_whitelist(filename);
4977 	}
4978 
4979 	if(ferror(fd))
4980 		BAD_ERROR("Reading whitelist file \"%s\" failed because %s\n",
4981 			argv, strerror(errno));
4982 
4983 	fclose(fd);
4984 }
4985 #endif
4986 /* ANDROID CHANGES END */
4987 
4988 #define RECOVER_ID "Squashfs recovery file v1.0\n"
4989 #define RECOVER_ID_SIZE 28
4990 
write_recovery_data(struct squashfs_super_block * sBlk)4991 void write_recovery_data(struct squashfs_super_block *sBlk)
4992 {
4993 	int res, recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start;
4994 	pid_t pid = getpid();
4995 	char *metadata;
4996 	char header[] = RECOVER_ID;
4997 
4998 	if(recover == FALSE) {
4999 		printf("No recovery data option specified.\n");
5000 		printf("Skipping saving recovery file.\n\n");
5001 		return;
5002 	}
5003 
5004 	metadata = malloc(bytes);
5005 	if(metadata == NULL)
5006 		MEM_ERROR();
5007 
5008 	res = read_fs_bytes(fd, sBlk->inode_table_start, bytes, metadata);
5009 	if(res == 0) {
5010 		ERROR("Failed to read append filesystem metadata\n");
5011 		BAD_ERROR("Filesystem corrupted?\n");
5012 	}
5013 
5014 	res = asprintf(&recovery_file, "squashfs_recovery_%s_%d",
5015 		getbase(destination_file), pid);
5016 	if(res == -1)
5017 		MEM_ERROR();
5018 
5019 	recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
5020 	if(recoverfd == -1)
5021 		BAD_ERROR("Failed to create recovery file, because %s.  "
5022 			"Aborting\n", strerror(errno));
5023 
5024 	if(write_bytes(recoverfd, header, RECOVER_ID_SIZE) == -1)
5025 		BAD_ERROR("Failed to write recovery file, because %s\n",
5026 			strerror(errno));
5027 
5028 	if(write_bytes(recoverfd, sBlk, sizeof(struct squashfs_super_block)) == -1)
5029 		BAD_ERROR("Failed to write recovery file, because %s\n",
5030 			strerror(errno));
5031 
5032 	if(write_bytes(recoverfd, metadata, bytes) == -1)
5033 		BAD_ERROR("Failed to write recovery file, because %s\n",
5034 			strerror(errno));
5035 
5036 	close(recoverfd);
5037 	free(metadata);
5038 
5039 	printf("Recovery file \"%s\" written\n", recovery_file);
5040 	printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n");
5041 	printf("mksquashfs dummy %s -recover %s\n", destination_file,
5042 		recovery_file);
5043 	printf("to restore filesystem\n\n");
5044 }
5045 
5046 
read_recovery_data(char * recovery_file,char * destination_file)5047 void read_recovery_data(char *recovery_file, char *destination_file)
5048 {
5049 	int fd, recoverfd, bytes;
5050 	struct squashfs_super_block orig_sBlk, sBlk;
5051 	char *metadata;
5052 	int res;
5053 	struct stat buf;
5054 	char header[] = RECOVER_ID;
5055 	char header2[RECOVER_ID_SIZE];
5056 
5057 	recoverfd = open(recovery_file, O_RDONLY);
5058 	if(recoverfd == -1)
5059 		BAD_ERROR("Failed to open recovery file because %s\n",
5060 			strerror(errno));
5061 
5062 	if(stat(destination_file, &buf) == -1)
5063 		BAD_ERROR("Failed to stat destination file, because %s\n",
5064 			strerror(errno));
5065 
5066 	fd = open(destination_file, O_RDWR);
5067 	if(fd == -1)
5068 		BAD_ERROR("Failed to open destination file because %s\n",
5069 			strerror(errno));
5070 
5071 	res = read_bytes(recoverfd, header2, RECOVER_ID_SIZE);
5072 	if(res == -1)
5073 		BAD_ERROR("Failed to read recovery file, because %s\n",
5074 			strerror(errno));
5075 	if(res < RECOVER_ID_SIZE)
5076 		BAD_ERROR("Recovery file appears to be truncated\n");
5077 	if(strncmp(header, header2, RECOVER_ID_SIZE) !=0 )
5078 		BAD_ERROR("Not a recovery file\n");
5079 
5080 	res = read_bytes(recoverfd, &sBlk, sizeof(struct squashfs_super_block));
5081 	if(res == -1)
5082 		BAD_ERROR("Failed to read recovery file, because %s\n",
5083 			strerror(errno));
5084 	if(res < sizeof(struct squashfs_super_block))
5085 		BAD_ERROR("Recovery file appears to be truncated\n");
5086 
5087 	res = read_fs_bytes(fd, 0, sizeof(struct squashfs_super_block), &orig_sBlk);
5088 	if(res == 0) {
5089 		ERROR("Failed to read superblock from output filesystem\n");
5090 		BAD_ERROR("Output filesystem is empty!\n");
5091 	}
5092 
5093 	if(memcmp(((char *) &sBlk) + 4, ((char *) &orig_sBlk) + 4,
5094 			sizeof(struct squashfs_super_block) - 4) != 0)
5095 		BAD_ERROR("Recovery file and destination file do not seem to "
5096 			"match\n");
5097 
5098 	bytes = sBlk.bytes_used - sBlk.inode_table_start;
5099 
5100 	metadata = malloc(bytes);
5101 	if(metadata == NULL)
5102 		MEM_ERROR();
5103 
5104 	res = read_bytes(recoverfd, metadata, bytes);
5105 	if(res == -1)
5106 		BAD_ERROR("Failed to read recovery file, because %s\n",
5107 			strerror(errno));
5108 	if(res < bytes)
5109 		BAD_ERROR("Recovery file appears to be truncated\n");
5110 
5111 	write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk);
5112 
5113 	write_destination(fd, sBlk.inode_table_start, bytes, metadata);
5114 
5115 	close(recoverfd);
5116 	close(fd);
5117 
5118 	printf("Successfully wrote recovery file \"%s\".  Exiting\n",
5119 		recovery_file);
5120 
5121 	exit(0);
5122 }
5123 
5124 
write_filesystem_tables(struct squashfs_super_block * sBlk,int nopad)5125 void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad)
5126 {
5127 	int i;
5128 
5129 	sBlk->fragments = fragments;
5130 	sBlk->no_ids = id_count;
5131 	sBlk->inode_table_start = write_inodes();
5132 	sBlk->directory_table_start = write_directories();
5133 	sBlk->fragment_table_start = write_fragment_table();
5134 	sBlk->lookup_table_start = exportable ? write_inode_lookup_table() :
5135 		SQUASHFS_INVALID_BLK;
5136 	sBlk->id_table_start = write_id_table();
5137 	sBlk->xattr_id_table_start = write_xattrs();
5138 
5139 	TRACE("sBlk->inode_table_start 0x%llx\n", sBlk->inode_table_start);
5140 	TRACE("sBlk->directory_table_start 0x%llx\n",
5141 		sBlk->directory_table_start);
5142 	TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk->fragment_table_start);
5143 	if(exportable)
5144 		TRACE("sBlk->lookup_table_start 0x%llx\n",
5145 			sBlk->lookup_table_start);
5146 
5147 	sBlk->bytes_used = bytes;
5148 
5149 	sBlk->compression = comp->id;
5150 
5151 	SQUASHFS_INSWAP_SUPER_BLOCK(sBlk);
5152 	write_destination(fd, SQUASHFS_START, sizeof(*sBlk), sBlk);
5153 
5154 	if(!nopad && (i = bytes & (4096 - 1))) {
5155 		char temp[4096] = {0};
5156 		write_destination(fd, bytes, 4096 - i, temp);
5157 	}
5158 
5159 	close(fd);
5160 
5161 	if(recovery_file)
5162 		unlink(recovery_file);
5163 
5164 	total_bytes += total_inode_bytes + total_directory_bytes +
5165 		sizeof(struct squashfs_super_block) + total_xattr_bytes;
5166 
5167 	printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size"
5168 		" %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR,
5169 		SQUASHFS_MINOR, comp->name, block_size);
5170 	printf("\t%s data, %s metadata, %s fragments, %s xattrs\n",
5171 		noD ? "uncompressed" : "compressed", noI ?  "uncompressed" :
5172 		"compressed", no_fragments ? "no" : noF ? "uncompressed" :
5173 		"compressed", no_xattrs ? "no" : noX ? "uncompressed" :
5174 		"compressed");
5175 	printf("\tduplicates are %sremoved\n", duplicate_checking ? "" :
5176 		"not ");
5177 	printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0,
5178 		bytes / (1024.0 * 1024.0));
5179 	printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n",
5180 		((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0);
5181 	printf("Inode table size %d bytes (%.2f Kbytes)\n",
5182 		inode_bytes, inode_bytes / 1024.0);
5183 	printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n",
5184 		((float) inode_bytes / total_inode_bytes) * 100.0,
5185 		total_inode_bytes);
5186 	printf("Directory table size %d bytes (%.2f Kbytes)\n",
5187 		directory_bytes, directory_bytes / 1024.0);
5188 	printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n",
5189 		((float) directory_bytes / total_directory_bytes) * 100.0,
5190 		total_directory_bytes);
5191 	if(total_xattr_bytes) {
5192 		printf("Xattr table size %d bytes (%.2f Kbytes)\n",
5193 			xattr_bytes, xattr_bytes / 1024.0);
5194 		printf("\t%.2f%% of uncompressed xattr table size (%d bytes)\n",
5195 			((float) xattr_bytes / total_xattr_bytes) * 100.0,
5196 			total_xattr_bytes);
5197 	}
5198 	if(duplicate_checking)
5199 		printf("Number of duplicate files found %d\n", file_count -
5200 			dup_files);
5201 	else
5202 		printf("No duplicate files removed\n");
5203 	printf("Number of inodes %d\n", inode_count);
5204 	printf("Number of files %d\n", file_count);
5205 	if(!no_fragments)
5206 		printf("Number of fragments %d\n", fragments);
5207 	printf("Number of symbolic links  %d\n", sym_count);
5208 	printf("Number of device nodes %d\n", dev_count);
5209 	printf("Number of fifo nodes %d\n", fifo_count);
5210 	printf("Number of socket nodes %d\n", sock_count);
5211 	printf("Number of directories %d\n", dir_count);
5212 	printf("Number of ids (unique uids + gids) %d\n", id_count);
5213 	printf("Number of uids %d\n", uid_count);
5214 
5215 	for(i = 0; i < id_count; i++) {
5216 		if(id_table[i]->flags & ISA_UID) {
5217 			struct passwd *user = getpwuid(id_table[i]->id);
5218 			printf("\t%s (%d)\n", user == NULL ? "unknown" :
5219 				user->pw_name, id_table[i]->id);
5220 		}
5221 	}
5222 
5223 	printf("Number of gids %d\n", guid_count);
5224 
5225 	for(i = 0; i < id_count; i++) {
5226 		if(id_table[i]->flags & ISA_GID) {
5227 			struct group *group = getgrgid(id_table[i]->id);
5228 			printf("\t%s (%d)\n", group == NULL ? "unknown" :
5229 				group->gr_name, id_table[i]->id);
5230 		}
5231 	}
5232 
5233 	printf("Number of whitelisted (uncompressed) files %d\n",
5234 	       whitelisted_count);
5235 }
5236 
5237 
parse_numberll(char * start,long long * res,int size)5238 int parse_numberll(char *start, long long *res, int size)
5239 {
5240 	char *end;
5241 	long long number;
5242 
5243 	errno = 0; /* To distinguish success/failure after call */
5244 
5245 	number = strtoll(start, &end, 10);
5246 
5247 	/*
5248 	 * check for strtoll underflow or overflow in conversion, and other
5249 	 * errors.
5250 	 */
5251 	if((errno == ERANGE && (number == LLONG_MIN || number == LLONG_MAX)) ||
5252 			(errno != 0 && number == 0))
5253 		return 0;
5254 
5255 	/* reject negative numbers as invalid */
5256 	if(number < 0)
5257 		return 0;
5258 
5259 	if(size) {
5260 		/*
5261 		 * Check for multiplier and trailing junk.
5262 		 * But first check that a number exists before the
5263 		 * multiplier
5264 		 */
5265 		if(end == start)
5266 			return 0;
5267 
5268 		switch(end[0]) {
5269 		case 'g':
5270 		case 'G':
5271 			if(multiply_overflowll(number, 1073741824))
5272 				return 0;
5273 			number *= 1073741824;
5274 
5275 			if(end[1] != '\0')
5276 				/* trailing junk after multiplier, but
5277 				 * allow it to be "bytes" */
5278 				if(strcmp(end + 1, "bytes"))
5279 					return 0;
5280 
5281 			break;
5282 		case 'm':
5283 		case 'M':
5284 			if(multiply_overflowll(number, 1048576))
5285 				return 0;
5286 			number *= 1048576;
5287 
5288 			if(end[1] != '\0')
5289 				/* trailing junk after multiplier, but
5290 				 * allow it to be "bytes" */
5291 				if(strcmp(end + 1, "bytes"))
5292 					return 0;
5293 
5294 			break;
5295 		case 'k':
5296 		case 'K':
5297 			if(multiply_overflowll(number, 1024))
5298 				return 0;
5299 			number *= 1024;
5300 
5301 			if(end[1] != '\0')
5302 				/* trailing junk after multiplier, but
5303 				 * allow it to be "bytes" */
5304 				if(strcmp(end + 1, "bytes"))
5305 					return 0;
5306 
5307 			break;
5308 		case '\0':
5309 			break;
5310 		default:
5311 			/* trailing junk after number */
5312 			return 0;
5313 		}
5314 	} else if(end[0] != '\0')
5315 		/* trailing junk after number */
5316 		return 0;
5317 
5318 	*res = number;
5319 	return 1;
5320 }
5321 
5322 
parse_number(char * start,int * res,int size)5323 int parse_number(char *start, int *res, int size)
5324 {
5325 	long long number;
5326 
5327 	if(!parse_numberll(start, &number, size))
5328 		return 0;
5329 
5330 	/* check if long result will overflow signed int */
5331 	if(number > INT_MAX)
5332 		return 0;
5333 
5334 	*res = (int) number;
5335 	return 1;
5336 }
5337 
5338 
parse_num(char * arg,int * res)5339 int parse_num(char *arg, int *res)
5340 {
5341 	return parse_number(arg, res, 0);
5342 }
5343 
5344 
parse_ugid_map(char * map_str,struct ugid_map_entry ugid_mapping[UGID_ENTRIES],unsigned int * ugid_map_count)5345 int parse_ugid_map(char *map_str,
5346 	struct ugid_map_entry ugid_mapping[UGID_ENTRIES],
5347 	unsigned int *ugid_map_count)
5348 {
5349 	char *line_state, *token_state;
5350 	char *line, *line_str, *token, *token_str;
5351 	long long numbers[3];
5352 	int i;
5353 
5354 	for (*ugid_map_count = 0, line_str = map_str;;
5355 		++*ugid_map_count, line_str = NULL) {
5356 		line = strtok_r(line_str, "\n", &line_state);
5357 		if (line == NULL)
5358 			break;
5359                 ERROR("line: %s\n", line);
5360 		if (*ugid_map_count >= UGID_ENTRIES) {
5361 			ERROR("Too many entries for u/gid mapping\n");
5362 			return -1;
5363 		}
5364 
5365 		for (i = 0, token_str = line; i < 3; i++, token_str = NULL) {
5366 			token = strtok_r(token_str, " ", &token_state);
5367                         ERROR("token: %d, %s\n", i, token);
5368 			if (token == NULL ||
5369 				!parse_numberll(token, &numbers[i], 0) ||
5370 				numbers[i] < 0 || numbers[i] > ULONG_MAX) {
5371 				ERROR("Malformed u/gid mapping line1\n");
5372 				return -1;
5373 			}
5374 		}
5375 
5376 		if (numbers[0] + numbers[2] > ULONG_MAX) {
5377 			ERROR("u/gid mapping overflow\n");
5378 			return -1;
5379 		}
5380 
5381 		if (numbers[1] + numbers[2] > ULONG_MAX) {
5382 			ERROR("u/gid mapping overflow\n");
5383 			return -1;
5384 		}
5385 
5386 		if (strtok_r(NULL, " ", &token_state) != NULL) {
5387 			ERROR("Malformed u/gid mapping line2\n");
5388 			return -1;
5389 		}
5390 
5391 		ugid_mapping[*ugid_map_count].child_id =
5392 			(unsigned int)numbers[0];
5393 		ugid_mapping[*ugid_map_count].parent_id =
5394 			(unsigned int)numbers[1];
5395 		ugid_mapping[*ugid_map_count].length = (unsigned int)numbers[2];
5396 	}
5397 
5398 	return 0;
5399 }
5400 
5401 
get_physical_memory()5402 int get_physical_memory()
5403 {
5404 	int phys_mem;
5405 #ifndef linux
5406 	#ifdef HW_MEMSIZE
5407 		#define SYSCTL_PHYSMEM HW_MEMSIZE
5408 	#elif defined(HW_PHYSMEM64)
5409 		#define SYSCTL_PHYSMEM HW_PHYSMEM64
5410 	#else
5411 		#define SYSCTL_PHYSMEM HW_PHYSMEM
5412 	#endif
5413 
5414 	int mib[2];
5415 	uint64_t sysctl_physmem = 0;
5416 	size_t sysctl_len = sizeof(sysctl_physmem);
5417 
5418 	mib[0] = CTL_HW;
5419 	mib[1] = SYSCTL_PHYSMEM;
5420 
5421 	if(sysctl(mib, 2, &sysctl_physmem, &sysctl_len, NULL, 0) == 0) {
5422 		/* some systems use 32-bit values, work with what we're given */
5423 		if (sysctl_len == 4)
5424 			sysctl_physmem = *(uint32_t*)&sysctl_physmem;
5425 		phys_mem = sysctl_physmem >> 20;
5426 	} else {
5427 		ERROR_START("Failed to get amount of available "
5428 			"memory.");
5429 		ERROR_EXIT("  Defaulting to least viable amount\n");
5430 		phys_mem = SQUASHFS_LOWMEM;
5431 	}
5432   #undef SYSCTL_PHYSMEM
5433 #else
5434 	/* Long longs are used here because with PAE, a 32-bit
5435 	  machine can have more than 4GB of physical memory */
5436 
5437 	long long num_pages = sysconf(_SC_PHYS_PAGES);
5438 	long long page_size = sysconf(_SC_PAGESIZE);
5439 	phys_mem = num_pages * page_size >> 20;
5440 	if(num_pages == -1 || page_size == -1)
5441 		return 0;
5442 
5443 #endif
5444 
5445 	if(phys_mem < SQUASHFS_LOWMEM)
5446 		BAD_ERROR("Mksquashfs requires more physical memory than is "
5447 			"available!\n");
5448 
5449 	return phys_mem;
5450 }
5451 
5452 
check_usable_phys_mem(int total_mem)5453 void check_usable_phys_mem(int total_mem)
5454 {
5455 	/*
5456 	 * We want to allow users to use as much of their physical
5457 	 * memory as they wish.  However, for practical reasons there are
5458 	 * limits which need to be imposed, to protect users from themselves
5459 	 * and to prevent people from using Mksquashfs as a DOS attack by using
5460 	 * all physical memory.   Mksquashfs uses memory to cache data from disk
5461 	 * to optimise performance.  It is pointless to ask it to use more
5462 	 * than 75% of physical memory, as this causes thrashing and it is thus
5463 	 * self-defeating.
5464 	 */
5465 	int mem = get_physical_memory();
5466 
5467 	mem = (mem >> 1) + (mem >> 2); /* 75% */
5468 
5469 	if(total_mem > mem && mem) {
5470 		ERROR("Total memory requested is more than 75%% of physical "
5471 						"memory.\n");
5472 		ERROR("Mksquashfs uses memory to cache data from disk to "
5473 						"optimise performance.\n");
5474 		ERROR("It is pointless to ask it to use more than this amount "
5475 						"of memory, as this\n");
5476 		ERROR("causes thrashing and it is thus self-defeating.\n");
5477 		BAD_ERROR("Requested memory size too large\n");
5478 	}
5479 
5480 	if(sizeof(void *) == 4 && total_mem > 2048) {
5481 		/*
5482 		 * If we're running on a kernel with PAE or on a 64-bit kernel,
5483 		 * then the 75% physical memory limit can still easily exceed
5484 		 * the addressable memory by this process.
5485 		 *
5486 		 * Due to the typical kernel/user-space split (1GB/3GB, or
5487 		 * 2GB/2GB), we have to conservatively assume the 32-bit
5488 		 * processes can only address 2-3GB.  So refuse if the user
5489 		 * tries to allocate more than 2GB.
5490 		 */
5491 		ERROR("Total memory requested may exceed maximum "
5492 				"addressable memory by this process\n");
5493 		BAD_ERROR("Requested memory size too large\n");
5494 	}
5495 }
5496 
5497 
get_default_phys_mem()5498 int get_default_phys_mem()
5499 {
5500 	/*
5501 	 * get_physical_memory() relies on /proc being mounted.
5502 	 * If it fails, issue a warning, and use
5503 	 * SQUASHFS_LOWMEM / SQUASHFS_TAKE as default,
5504 	 * and allow a larger value to be set with -mem.
5505 	 */
5506 	int mem = get_physical_memory();
5507 
5508 	if(mem == 0) {
5509 		mem = SQUASHFS_LOWMEM / SQUASHFS_TAKE;
5510 
5511 		ERROR("Warning: Cannot get size of physical memory, probably "
5512 				"because /proc is missing.\n");
5513 		ERROR("Warning: Defaulting to minimal use of %d Mbytes, use "
5514 				"-mem to set a better value,\n", mem);
5515 		ERROR("Warning: or fix /proc.\n");
5516 	} else
5517 		mem /= SQUASHFS_TAKE;
5518 
5519 	if(sizeof(void *) == 4 && mem > 640) {
5520 		/*
5521 		 * If we're running on a kernel with PAE or on a 64-bit kernel,
5522 		 * the default memory usage can exceed the addressable
5523 		 * memory by this process.
5524 		 * Due to the typical kernel/user-space split (1GB/3GB, or
5525 		 * 2GB/2GB), we have to conservatively assume the 32-bit
5526 		 * processes can only address 2-3GB.  So limit the  default
5527 		 * usage to 640M, which gives room for other data.
5528 		 */
5529 		mem = 640;
5530 	}
5531 
5532 	return mem;
5533 }
5534 
5535 
calculate_queue_sizes(int mem,int * readq,int * fragq,int * bwriteq,int * fwriteq)5536 void calculate_queue_sizes(int mem, int *readq, int *fragq, int *bwriteq,
5537 							int *fwriteq)
5538 {
5539 	*readq = mem / SQUASHFS_READQ_MEM;
5540 	*bwriteq = mem / SQUASHFS_BWRITEQ_MEM;
5541 	*fwriteq = mem / SQUASHFS_FWRITEQ_MEM;
5542 	*fragq = mem - *readq - *bwriteq - *fwriteq;
5543 }
5544 
5545 
5546 #define VERSION() \
5547 	printf("mksquashfs version 4.3-git (2014/09/12)\n");\
5548 	printf("copyright (C) 2014 Phillip Lougher "\
5549 		"<[email protected]>\n\n"); \
5550 	printf("This program is free software; you can redistribute it and/or"\
5551 		"\n");\
5552 	printf("modify it under the terms of the GNU General Public License"\
5553 		"\n");\
5554 	printf("as published by the Free Software Foundation; either version "\
5555 		"2,\n");\
5556 	printf("or (at your option) any later version.\n\n");\
5557 	printf("This program is distributed in the hope that it will be "\
5558 		"useful,\n");\
5559 	printf("but WITHOUT ANY WARRANTY; without even the implied warranty "\
5560 		"of\n");\
5561 	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the"\
5562 		"\n");\
5563 	printf("GNU General Public License for more details.\n");
main(int argc,char * argv[])5564 int main(int argc, char *argv[])
5565 {
5566 	struct stat buf, source_buf;
5567 	int res, i;
5568 	char *b, *root_name = NULL;
5569 	int keep_as_directory = FALSE;
5570 	squashfs_inode inode;
5571 	int readq;
5572 	int fragq;
5573 	int bwriteq;
5574 	int fwriteq;
5575 	int total_mem = get_default_phys_mem();
5576 	int progress = TRUE;
5577 	int force_progress = FALSE;
5578 	struct file_buffer **fragment = NULL;
5579 /* ANDROID CHANGES START*/
5580 #ifdef ANDROID
5581 	const char *fs_config_file = NULL;
5582 #endif
5583 /* ANDROID CHANGES END */
5584 
5585 	if(argc > 1 && strcmp(argv[1], "-version") == 0) {
5586 		VERSION();
5587 		exit(0);
5588 	}
5589 
5590 	block_log = slog(block_size);
5591 	calculate_queue_sizes(total_mem, &readq, &fragq, &bwriteq, &fwriteq);
5592 
5593         for(i = 1; i < argc && argv[i][0] != '-'; i++);
5594 	if(i < 3)
5595 		goto printOptions;
5596 	source_path = argv + 1;
5597 	source = i - 2;
5598 
5599 	/*
5600 	 * Scan the command line for -comp xxx option, this is to ensure
5601 	 * any -X compressor specific options are passed to the
5602 	 * correct compressor
5603 	 */
5604 	for(; i < argc; i++) {
5605 		struct compressor *prev_comp = comp;
5606 
5607 		if(strcmp(argv[i], "-comp") == 0) {
5608 			if(++i == argc) {
5609 				ERROR("%s: -comp missing compression type\n",
5610 					argv[0]);
5611 				exit(1);
5612 			}
5613 			comp = lookup_compressor(argv[i]);
5614 			if(!comp->supported) {
5615 				ERROR("%s: Compressor \"%s\" is not supported!"
5616 					"\n", argv[0], argv[i]);
5617 				ERROR("%s: Compressors available:\n", argv[0]);
5618 				display_compressors("", COMP_DEFAULT);
5619 				exit(1);
5620 			}
5621 			if(prev_comp != NULL && prev_comp != comp) {
5622 				ERROR("%s: -comp multiple conflicting -comp"
5623 					" options specified on command line"
5624 					", previously %s, now %s\n", argv[0],
5625 					prev_comp->name, comp->name);
5626 				exit(1);
5627 			}
5628 			compressor_opt_parsed = 1;
5629 
5630 		} else if(strcmp(argv[i], "-e") == 0)
5631 			break;
5632 		else if(strcmp(argv[i], "-root-becomes") == 0 ||
5633 				strcmp(argv[i], "-ef") == 0 ||
5634 				strcmp(argv[i], "-pf") == 0 ||
5635 				strcmp(argv[i], "-vaf") == 0 ||
5636 				strcmp(argv[i], "-comp") == 0)
5637 			i++;
5638 	}
5639 
5640 	/*
5641 	 * if no -comp option specified lookup default compressor.  Note the
5642 	 * Makefile ensures the default compressor has been built, and so we
5643 	 * don't need to to check for failure here
5644 	 */
5645 	if(comp == NULL)
5646 		comp = lookup_compressor(COMP_DEFAULT);
5647 
5648 	for(i = source + 2; i < argc; i++) {
5649 		if(strcmp(argv[i], "-action") == 0 ||
5650 				strcmp(argv[i], "-a") ==0) {
5651 			if(++i == argc) {
5652 				ERROR("%s: %s missing action\n",
5653 					argv[0], argv[i - 1]);
5654 				exit(1);
5655 			}
5656 			res = parse_action(argv[i], ACTION_LOG_NONE);
5657 			if(res == 0)
5658 				exit(1);
5659 
5660 		} else if(strcmp(argv[i], "-verbose-action") == 0 ||
5661 				strcmp(argv[i], "-va") ==0) {
5662 			if(++i == argc) {
5663 				ERROR("%s: %s missing action\n",
5664 					argv[0], argv[i - 1]);
5665 				exit(1);
5666 			}
5667 			res = parse_action(argv[i], ACTION_LOG_VERBOSE);
5668 			if(res == 0)
5669 				exit(1);
5670 
5671 		} else if(strcmp(argv[i], "-true-action") == 0 ||
5672 				strcmp(argv[i], "-ta") ==0) {
5673 			if(++i == argc) {
5674 				ERROR("%s: %s missing action\n",
5675 					argv[0], argv[i - 1]);
5676 				exit(1);
5677 			}
5678 			res = parse_action(argv[i], ACTION_LOG_TRUE);
5679 			if(res == 0)
5680 				exit(1);
5681 
5682 		} else if(strcmp(argv[i], "-false-action") == 0 ||
5683 				strcmp(argv[i], "-fa") ==0) {
5684 			if(++i == argc) {
5685 				ERROR("%s: %s missing action\n",
5686 					argv[0], argv[i - 1]);
5687 				exit(1);
5688 			}
5689 			res = parse_action(argv[i], ACTION_LOG_FALSE);
5690 			if(res == 0)
5691 				exit(1);
5692 
5693 		} else if(strcmp(argv[i], "-action-file") == 0 ||
5694 				strcmp(argv[i], "-af") ==0) {
5695 			if(++i == argc) {
5696 				ERROR("%s: %s missing filename\n", argv[0],
5697 							argv[i - 1]);
5698 				exit(1);
5699 			}
5700 			if(read_action_file(argv[i], ACTION_LOG_NONE) == FALSE)
5701 				exit(1);
5702 
5703 		} else if(strcmp(argv[i], "-verbose-action-file") == 0 ||
5704 				strcmp(argv[i], "-vaf") ==0) {
5705 			if(++i == argc) {
5706 				ERROR("%s: %s missing filename\n", argv[0],
5707 							argv[i - 1]);
5708 				exit(1);
5709 			}
5710 			if(read_action_file(argv[i], ACTION_LOG_VERBOSE) == FALSE)
5711 				exit(1);
5712 
5713 		} else if(strcmp(argv[i], "-true-action-file") == 0 ||
5714 				strcmp(argv[i], "-taf") ==0) {
5715 			if(++i == argc) {
5716 				ERROR("%s: %s missing filename\n", argv[0],
5717 							argv[i - 1]);
5718 				exit(1);
5719 			}
5720 			if(read_action_file(argv[i], ACTION_LOG_TRUE) == FALSE)
5721 				exit(1);
5722 
5723 		} else if(strcmp(argv[i], "-false-action-file") == 0 ||
5724 				strcmp(argv[i], "-faf") ==0) {
5725 			if(++i == argc) {
5726 				ERROR("%s: %s missing filename\n", argv[0],
5727 							argv[i - 1]);
5728 				exit(1);
5729 			}
5730 			if(read_action_file(argv[i], ACTION_LOG_FALSE) == FALSE)
5731 				exit(1);
5732 
5733 		} else if(strcmp(argv[i], "-comp") == 0)
5734 			/* parsed previously */
5735 			i++;
5736 
5737 		else if(strncmp(argv[i], "-X", 2) == 0) {
5738 			int args;
5739 
5740 			if(strcmp(argv[i] + 2, "help") == 0)
5741 				goto print_compressor_options;
5742 
5743 			args = compressor_options(comp, argv + i, argc - i);
5744 			if(args < 0) {
5745 				if(args == -1) {
5746 					ERROR("%s: Unrecognised compressor"
5747 						" option %s\n", argv[0],
5748 						argv[i]);
5749 					if(!compressor_opt_parsed)
5750 						ERROR("%s: Did you forget to"
5751 							" specify -comp?\n",
5752 							argv[0]);
5753 print_compressor_options:
5754 					ERROR("%s: selected compressor \"%s\""
5755 						".  Options supported: %s\n",
5756 						argv[0], comp->name,
5757 						comp->usage ? "" : "none");
5758 					if(comp->usage)
5759 						comp->usage();
5760 				}
5761 				exit(1);
5762 			}
5763 			i += args;
5764 
5765 		} else if(strcmp(argv[i], "-pf") == 0) {
5766 			if(++i == argc) {
5767 				ERROR("%s: -pf missing filename\n", argv[0]);
5768 				exit(1);
5769 			}
5770 			if(read_pseudo_file(argv[i]) == FALSE)
5771 				exit(1);
5772 		} else if(strcmp(argv[i], "-p") == 0) {
5773 			if(++i == argc) {
5774 				ERROR("%s: -p missing pseudo file definition\n",
5775 					argv[0]);
5776 				exit(1);
5777 			}
5778 			if(read_pseudo_def(argv[i]) == FALSE)
5779 				exit(1);
5780 		} else if(strcmp(argv[i], "-recover") == 0) {
5781 			if(++i == argc) {
5782 				ERROR("%s: -recover missing recovery file\n",
5783 					argv[0]);
5784 				exit(1);
5785 			}
5786 			read_recovery_data(argv[i], argv[source + 1]);
5787 		} else if(strcmp(argv[i], "-no-recovery") == 0)
5788 			recover = FALSE;
5789 		else if(strcmp(argv[i], "-wildcards") == 0) {
5790 			old_exclude = FALSE;
5791 			use_regex = FALSE;
5792 		} else if(strcmp(argv[i], "-regex") == 0) {
5793 			old_exclude = FALSE;
5794 			use_regex = TRUE;
5795 		} else if(strcmp(argv[i], "-no-sparse") == 0)
5796 			sparse_files = FALSE;
5797 		else if(strcmp(argv[i], "-no-progress") == 0)
5798 			progress = FALSE;
5799 		else if(strcmp(argv[i], "-progress") == 0)
5800 			force_progress = TRUE;
5801 		else if(strcmp(argv[i], "-no-exports") == 0)
5802 			exportable = FALSE;
5803 		else if(strcmp(argv[i], "-processors") == 0) {
5804 			if((++i == argc) || !parse_num(argv[i], &processors)) {
5805 				ERROR("%s: -processors missing or invalid "
5806 					"processor number\n", argv[0]);
5807 				exit(1);
5808 			}
5809 			if(processors < 1) {
5810 				ERROR("%s: -processors should be 1 or larger\n",
5811 					argv[0]);
5812 				exit(1);
5813 			}
5814 		} else if(strcmp(argv[i], "-read-queue") == 0) {
5815 			if((++i == argc) || !parse_num(argv[i], &readq)) {
5816 				ERROR("%s: -read-queue missing or invalid "
5817 					"queue size\n", argv[0]);
5818 				exit(1);
5819 			}
5820 			if(readq < 1) {
5821 				ERROR("%s: -read-queue should be 1 megabyte or "
5822 					"larger\n", argv[0]);
5823 				exit(1);
5824 			}
5825 		} else if(strcmp(argv[i], "-write-queue") == 0) {
5826 			if((++i == argc) || !parse_num(argv[i], &bwriteq)) {
5827 				ERROR("%s: -write-queue missing or invalid "
5828 					"queue size\n", argv[0]);
5829 				exit(1);
5830 			}
5831 			if(bwriteq < 2) {
5832 				ERROR("%s: -write-queue should be 2 megabytes "
5833 					"or larger\n", argv[0]);
5834 				exit(1);
5835 			}
5836 			fwriteq = bwriteq >> 1;
5837 			bwriteq -= fwriteq;
5838 		} else if(strcmp(argv[i], "-fragment-queue") == 0) {
5839 			if((++i == argc) || !parse_num(argv[i], &fragq)) {
5840 				ERROR("%s: -fragment-queue missing or invalid "
5841 					"queue size\n", argv[0]);
5842 				exit(1);
5843 			}
5844 			if(fragq < 1) {
5845 				ERROR("%s: -fragment-queue should be 1 "
5846 					"megabyte or larger\n", argv[0]);
5847 				exit(1);
5848 			}
5849 		} else if(strcmp(argv[i], "-mem") == 0) {
5850 			long long number;
5851 
5852 			if((++i == argc) ||
5853 					!parse_numberll(argv[i], &number, 1)) {
5854 				ERROR("%s: -mem missing or invalid mem size\n",
5855 					 argv[0]);
5856 				exit(1);
5857 			}
5858 
5859 			/*
5860 			 * convert from bytes to Mbytes, ensuring the value
5861 			 * does not overflow a signed int
5862 			 */
5863 			if(number >= (1LL << 51)) {
5864 				ERROR("%s: -mem invalid mem size\n", argv[0]);
5865 				exit(1);
5866 			}
5867 
5868 			total_mem = number / 1048576;
5869 			if(total_mem < (SQUASHFS_LOWMEM / SQUASHFS_TAKE)) {
5870 				ERROR("%s: -mem should be %d Mbytes or "
5871 					"larger\n", argv[0],
5872 					SQUASHFS_LOWMEM / SQUASHFS_TAKE);
5873 				exit(1);
5874 			}
5875 			calculate_queue_sizes(total_mem, &readq, &fragq,
5876 				&bwriteq, &fwriteq);
5877 		} else if(strcmp(argv[i], "-b") == 0) {
5878 			if(++i == argc) {
5879 				ERROR("%s: -b missing block size\n", argv[0]);
5880 				exit(1);
5881 			}
5882 			if(!parse_number(argv[i], &block_size, 1)) {
5883 				ERROR("%s: -b invalid block size\n", argv[0]);
5884 				exit(1);
5885 			}
5886 			if((block_log = slog(block_size)) == 0) {
5887 				ERROR("%s: -b block size not power of two or "
5888 					"not between 4096 and 1Mbyte\n",
5889 					argv[0]);
5890 				exit(1);
5891 			}
5892 		} else if(strcmp(argv[i], "-ef") == 0) {
5893 			if(++i == argc) {
5894 				ERROR("%s: -ef missing filename\n", argv[0]);
5895 				exit(1);
5896 			}
5897 		} else if(strcmp(argv[i], "-no-duplicates") == 0)
5898 			duplicate_checking = FALSE;
5899 
5900 		else if(strcmp(argv[i], "-no-fragments") == 0)
5901 			no_fragments = TRUE;
5902 
5903 		 else if(strcmp(argv[i], "-always-use-fragments") == 0)
5904 			always_use_fragments = TRUE;
5905 
5906 		 else if(strcmp(argv[i], "-sort") == 0) {
5907 			if(++i == argc) {
5908 				ERROR("%s: -sort missing filename\n", argv[0]);
5909 				exit(1);
5910 			}
5911 		} else if(strcmp(argv[i], "-all-root") == 0 ||
5912 				strcmp(argv[i], "-root-owned") == 0)
5913 			global_uid = global_gid = 0;
5914 
5915 		else if(strcmp(argv[i], "-force-uid") == 0) {
5916 			if(++i == argc) {
5917 				ERROR("%s: -force-uid missing uid or user\n",
5918 					argv[0]);
5919 				exit(1);
5920 			}
5921 			if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') {
5922 				if(global_uid < 0 || global_uid >
5923 						(((long long) 1 << 32) - 1)) {
5924 					ERROR("%s: -force-uid uid out of range"
5925 						"\n", argv[0]);
5926 					exit(1);
5927 				}
5928 			} else {
5929 				struct passwd *uid = getpwnam(argv[i]);
5930 				if(uid)
5931 					global_uid = uid->pw_uid;
5932 				else {
5933 					ERROR("%s: -force-uid invalid uid or "
5934 						"unknown user\n", argv[0]);
5935 					exit(1);
5936 				}
5937 			}
5938 		} else if(strcmp(argv[i], "-force-gid") == 0) {
5939 			if(++i == argc) {
5940 				ERROR("%s: -force-gid missing gid or group\n",
5941 					argv[0]);
5942 				exit(1);
5943 			}
5944 			if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') {
5945 				if(global_gid < 0 || global_gid >
5946 						(((long long) 1 << 32) - 1)) {
5947 					ERROR("%s: -force-gid gid out of range"
5948 						"\n", argv[0]);
5949 					exit(1);
5950 				}
5951 			} else {
5952 				struct group *gid = getgrnam(argv[i]);
5953 				if(gid)
5954 					global_gid = gid->gr_gid;
5955 				else {
5956 					ERROR("%s: -force-gid invalid gid or "
5957 						"unknown group\n", argv[0]);
5958 					exit(1);
5959 				}
5960 			}
5961 		} else if(strcmp(argv[i], "-noI") == 0 ||
5962 				strcmp(argv[i], "-noInodeCompression") == 0)
5963 			noI = TRUE;
5964 
5965 		else if(strcmp(argv[i], "-noD") == 0 ||
5966 				strcmp(argv[i], "-noDataCompression") == 0)
5967 			noD = TRUE;
5968 
5969 		else if(strcmp(argv[i], "-noF") == 0 ||
5970 				strcmp(argv[i], "-noFragmentCompression") == 0)
5971 			noF = TRUE;
5972 
5973 		else if(strcmp(argv[i], "-noX") == 0 ||
5974 				strcmp(argv[i], "-noXattrCompression") == 0)
5975 			noX = TRUE;
5976 
5977 		else if(strcmp(argv[i], "-no-xattrs") == 0)
5978 			no_xattrs = TRUE;
5979 
5980 		else if(strcmp(argv[i], "-xattrs") == 0)
5981 			no_xattrs = FALSE;
5982 
5983 /* ANDROID CHANGES START*/
5984 #ifdef ANDROID
5985 		else if(strcmp(argv[i], "-context-file") == 0) {
5986 			if(++i == argc) {
5987 				ERROR("%s: -context-file: missing file name\n",
5988 					argv[0]);
5989 				exit(1);
5990 			}
5991 			context_file = argv[i];
5992 		}
5993 		else if(strcmp(argv[i], "-fs-config-file") == 0) {
5994 			if(++i == argc) {
5995 				ERROR("%s: -fs-config-file: missing file name\n",
5996 					argv[0]);
5997 				exit(1);
5998 			}
5999 			fs_config_file = argv[i];
6000 		} else if(strcmp(argv[i], "-whitelist") == 0) {
6001 			if(++i == argc) {
6002 				ERROR("%s: -whitelist missing filename\n", argv[0]);
6003 				exit(1);
6004 			}
6005 			whitelist_filename = argv[i];
6006 		}
6007 		else if(strcmp(argv[i], "-t") == 0) {
6008 			if(++i == argc) {
6009 				ERROR("%s: -t missing compression threshold percentage\n", argv[0]);
6010 				exit(1);
6011 			}
6012 			if(!parse_number(argv[i], &compress_thresh_per, 1)) {
6013 				ERROR("%s: -t invalid compression threshold percentage\n", argv[0]);
6014 				exit(1);
6015 			}
6016 			if(compress_thresh_per > 100 || compress_thresh_per < 0) {
6017 				ERROR("%s: -t compression threshold percentage not between 0 and 100\n",
6018 					argv[0]);
6019 				exit(1);
6020 			}
6021 		}
6022 #endif
6023 /* ANDROID CHANGES END */
6024 		else if(strcmp(argv[i], "-nopad") == 0)
6025 			nopad = TRUE;
6026 
6027 		else if(strcmp(argv[i], "-info") == 0)
6028 			silent = FALSE;
6029 
6030 		else if(strcmp(argv[i], "-e") == 0)
6031 			break;
6032 
6033 		else if(strcmp(argv[i], "-noappend") == 0)
6034 			delete = TRUE;
6035 
6036 		else if(strcmp(argv[i], "-keep-as-directory") == 0)
6037 			keep_as_directory = TRUE;
6038 /* ANDROID CHANGES START*/
6039 #ifdef ANDROID
6040 		else if(strcmp(argv[i], "-android-fs-config") == 0)
6041 			android_config = TRUE;
6042 		else if(strcmp(argv[i], "-mount-point") == 0) {
6043 			if(++i == argc) {
6044 				ERROR("%s: -mount-point: missing mount point name\n",
6045 					argv[0]);
6046 				exit(1);
6047 			}
6048 			mount_point = argv[i];
6049 		}
6050 		else if(strcmp(argv[i], "-product-out") == 0) {
6051 			if(++i == argc) {
6052 				ERROR("%s: -product-out: missing path name\n",
6053 					argv[0]);
6054 				exit(1);
6055 			}
6056 			target_out_path = argv[i];
6057 		}
6058 		else if(strcmp(argv[i], "-disable-4k-align") == 0)
6059 			align_4k_blocks = FALSE;
6060 		else if(strcmp(argv[i], "-block-map") == 0) {
6061 			if(++i == argc) {
6062 				ERROR("%s: -block-map: missing path name\n",
6063 					argv[0]);
6064 				exit(1);
6065 			}
6066 			block_map_file = fopen(argv[i], "w");
6067 			if (block_map_file == NULL) {
6068 				ERROR("%s: -block-map: failed to open %s\n",
6069 					argv[0], argv[i]);
6070 				exit(1);
6071 			}
6072 			if (!align_4k_blocks) {
6073 				ERROR("WARNING: Using block maps with unaligned 4k blocks "
6074 					  "is not ideal as block map offsets are multiples of 4k, "
6075 					  "consider not passing -disable-4k-align\n");
6076 			}
6077 		}
6078 #endif
6079 /* ANDROID CHANGES END */
6080 
6081 		else if(strcmp(argv[i], "-exit-on-error") == 0)
6082 			exit_on_error = TRUE;
6083 
6084 		else if(strcmp(argv[i], "-root-becomes") == 0) {
6085 			if(++i == argc) {
6086 				ERROR("%s: -root-becomes: missing name\n",
6087 					argv[0]);
6088 				exit(1);
6089 			}
6090 			root_name = argv[i];
6091 		} else if (strcmp(argv[i], "-uid-map") == 0) {
6092 			if (++i == argc) {
6093 				ERROR("%s: -uid-map: missing mapping\n",
6094 					argv[0]);
6095 				exit(1);
6096 			}
6097 			if (parse_ugid_map(argv[i], uid_mapping,
6098 				&uid_map_count) != 0) {
6099 				ERROR("%s: -uid-map: invalid mapping\n",
6100 					argv[0]);
6101 				exit(1);
6102 			}
6103 		} else if (strcmp(argv[i], "-gid-map") == 0) {
6104 			if (++i == argc) {
6105 				ERROR("%s: -gid-map: missing mapping\n",
6106 					argv[0]);
6107 				exit(1);
6108 			}
6109 			if (parse_ugid_map(argv[i], gid_mapping,
6110 				&gid_map_count) != 0) {
6111 				ERROR("%s: -gid-map: invalid mapping\n",
6112 					argv[0]);
6113 				exit(1);
6114 			}
6115 		} else if(strcmp(argv[i], "-version") == 0) {
6116 			VERSION();
6117 		} else {
6118 			ERROR("%s: invalid option\n\n", argv[0]);
6119 printOptions:
6120 			ERROR("SYNTAX:%s source1 source2 ...  dest [options] "
6121 				"[-e list of exclude\ndirs/files]\n", argv[0]);
6122 			ERROR("\nFilesystem build options:\n");
6123 			ERROR("-comp <comp>\t\tselect <comp> compression\n");
6124 			ERROR("\t\t\tCompressors available:\n");
6125 			display_compressors("\t\t\t", COMP_DEFAULT);
6126 			ERROR("-b <block_size>\t\tset data block to "
6127 				"<block_size>.  Default 128 Kbytes\n");
6128 			ERROR("\t\t\tOptionally a suffix of K or M can be"
6129 				" given to specify\n\t\t\tKbytes or Mbytes"
6130 				" respectively\n");
6131 			ERROR("-no-exports\t\tdon't make the filesystem "
6132 				"exportable via NFS\n");
6133 			ERROR("-no-sparse\t\tdon't detect sparse files\n");
6134 			ERROR("-no-xattrs\t\tdon't store extended attributes"
6135 				NOXOPT_STR "\n");
6136 			ERROR("-xattrs\t\t\tstore extended attributes" XOPT_STR
6137 				"\n");
6138 /* ANDROID CHANGES START*/
6139 #ifdef ANDROID
6140 			ERROR("-context-file <file>\tApply selinux security "
6141 				"xattrs from context-file instead\n\t\t\t"
6142 				"of reading xattrs from file system\n");
6143 			ERROR("-fs-config-file <file>\tAndroid specific "
6144 				"filesystem config file\n");
6145 			ERROR("-t <compress_thresh>\tset minimum "
6146 				"acceptable compression ratio of a block to\n\t\t\t"
6147 				"<compress_thresh_per> otherwise don't compress. "
6148 				"Default 0%\n");
6149 			ERROR("-whitelist <file>\tAndroid specific whitelist "
6150 			      "one entry per line (no wildcards)\n");
6151 #endif
6152 /* ANDROID CHANGES END */
6153 			ERROR("-noI\t\t\tdo not compress inode table\n");
6154 			ERROR("-noD\t\t\tdo not compress data blocks\n");
6155 			ERROR("-noF\t\t\tdo not compress fragment blocks\n");
6156 			ERROR("-noX\t\t\tdo not compress extended "
6157 				"attributes\n");
6158 			ERROR("-no-fragments\t\tdo not use fragments\n");
6159 			ERROR("-always-use-fragments\tuse fragment blocks for "
6160 				"files larger than block size\n");
6161 			ERROR("-no-duplicates\t\tdo not perform duplicate "
6162 				"checking\n");
6163 			ERROR("-all-root\t\tmake all files owned by root\n");
6164 			ERROR("-force-uid uid\t\tset all file uids to uid\n");
6165 			ERROR("-force-gid gid\t\tset all file gids to gid\n");
6166 			ERROR("-nopad\t\t\tdo not pad filesystem to a multiple "
6167 				"of 4K\n");
6168 			ERROR("-keep-as-directory\tif one source directory is "
6169 				"specified, create a root\n");
6170 			ERROR("\t\t\tdirectory containing that directory, "
6171 				"rather than the\n");
6172 			ERROR("\t\t\tcontents of the directory\n");
6173 /* ANDROID CHANGES START*/
6174 #ifdef ANDROID
6175 			ERROR("-android-fs-config\tuse android fs config "
6176 				"for mode, uid, and gids of inodes\n");
6177 			ERROR("-mount-point <name>\tNeed to be provided when "
6178 				"android-fs-config or context-file\n\t\t\tare "
6179 				"enabled and source directory is not mount point\n");
6180 			ERROR("-product-out <path>\tPRODUCT_OUT directory to "
6181 				"read device specific FS rules files from\n");
6182 			ERROR("-disable-4k-align \tDon't 4k align data blocks. Default is false\n");
6183 			ERROR("-block-map <path>\tGenerate a block map for non-fragment files\n");
6184 #endif
6185 /* ANDROID CHANGES END */
6186 			ERROR("\nFilesystem filter options:\n");
6187 			ERROR("-p <pseudo-definition>\tAdd pseudo file "
6188 				"definition\n");
6189 			ERROR("-pf <pseudo-file>\tAdd list of pseudo file "
6190 				"definitions\n");
6191 			ERROR("-sort <sort_file>\tsort files according to "
6192 				"priorities in <sort_file>.  One\n");
6193 			ERROR("\t\t\tfile or dir with priority per line.  "
6194 				"Priority -32768 to\n");
6195 			ERROR("\t\t\t32767, default priority 0\n");
6196 			ERROR("-ef <exclude_file>\tlist of exclude dirs/files."
6197 				"  One per line\n");
6198 			ERROR("-wildcards\t\tAllow extended shell wildcards "
6199 				"(globbing) to be used in\n\t\t\texclude "
6200 				"dirs/files\n");
6201 			ERROR("-regex\t\t\tAllow POSIX regular expressions to "
6202 				"be used in exclude\n\t\t\tdirs/files\n");
6203 			ERROR("-uid-map <mapping>\tUser ID mapping.\n");
6204 			ERROR("\t\t\tFollows the format described in "
6205 				"user_namespaces(7).\n");
6206 			ERROR("-gid-map <mapping>\tGroup ID mapping.\n");
6207 			ERROR("\t\t\tFollows the format described in "
6208 				"user_namespaces(7).\n");
6209 			ERROR("\nFilesystem append options:\n");
6210 			ERROR("-noappend\t\tdo not append to existing "
6211 				"filesystem\n");
6212 			ERROR("-root-becomes <name>\twhen appending source "
6213 				"files/directories, make the\n");
6214 			ERROR("\t\t\toriginal root become a subdirectory in "
6215 				"the new root\n");
6216 			ERROR("\t\t\tcalled <name>, rather than adding the new "
6217 				"source items\n");
6218 			ERROR("\t\t\tto the original root\n");
6219 			ERROR("\nMksquashfs runtime options:\n");
6220 			ERROR("-version\t\tprint version, licence and "
6221 				"copyright message\n");
6222 			ERROR("-exit-on-error\t\ttreat normally ignored errors "
6223 				"as fatal\n");
6224 			ERROR("-recover <name>\t\trecover filesystem data "
6225 				"using recovery file <name>\n");
6226 			ERROR("-no-recovery\t\tdon't generate a recovery "
6227 				"file\n");
6228 			ERROR("-info\t\t\tprint files written to filesystem\n");
6229 			ERROR("-no-progress\t\tdon't display the progress "
6230 				"bar\n");
6231 			ERROR("-progress\t\tdisplay progress bar when using "
6232 				"the -info option\n");
6233 			ERROR("-processors <number>\tUse <number> processors."
6234 				"  By default will use number of\n");
6235 			ERROR("\t\t\tprocessors available\n");
6236 			ERROR("-mem <size>\t\tUse <size> physical memory.  "
6237 				"Currently set to %dM\n", total_mem);
6238 			ERROR("\t\t\tOptionally a suffix of K, M or G can be"
6239 				" given to specify\n\t\t\tKbytes, Mbytes or"
6240 				" Gbytes respectively\n");
6241 			ERROR("\nMiscellaneous options:\n");
6242 			ERROR("-root-owned\t\talternative name for -all-root"
6243 				"\n");
6244 			ERROR("-noInodeCompression\talternative name for -noI"
6245 				"\n");
6246 			ERROR("-noDataCompression\talternative name for -noD"
6247 				"\n");
6248 			ERROR("-noFragmentCompression\talternative name for "
6249 				"-noF\n");
6250 			ERROR("-noXattrCompression\talternative name for "
6251 				"-noX\n");
6252 			ERROR("\n-Xhelp\t\t\tprint compressor options for"
6253 				" selected compressor\n");
6254 			ERROR("\nCompressors available and compressor specific "
6255 				"options:\n");
6256 			display_compressor_usage(COMP_DEFAULT);
6257 			exit(1);
6258 		}
6259 	}
6260 
6261 	if (!uid_map_count) {
6262 		uid_mapping[0].child_id = 0;
6263 		uid_mapping[0].parent_id = 0;
6264 		uid_mapping[0].length = 4294967295u;
6265 		uid_map_count = 1;
6266 	}
6267 	if (!gid_map_count) {
6268 		gid_mapping[0].child_id = 0;
6269 		gid_mapping[0].parent_id = 0;
6270 		gid_mapping[0].length = 4294967295u;
6271 		gid_map_count = 1;
6272 	}
6273 
6274 /* ANDROID CHANGES START*/
6275 #ifdef ANDROID
6276 	if (fs_config_file) {
6277 		if (load_canned_fs_config(fs_config_file) < 0) {
6278 			fprintf(stderr, "failed to load %s\n", fs_config_file);
6279 			exit(1);
6280 		}
6281 		fs_config_func = canned_fs_config;
6282 	} else if (mount_point) {
6283 		fs_config_func = fs_config;
6284 	}
6285 	if (whitelist_filename)
6286 		process_whitelist_file(whitelist_filename);
6287 #endif
6288 /* ANDROID CHANGES END */
6289 
6290 	/*
6291 	 * Some compressors may need the options to be checked for validity
6292 	 * once all the options have been processed
6293 	 */
6294 	res = compressor_options_post(comp, block_size);
6295 	if(res)
6296 		EXIT_MKSQUASHFS();
6297 
6298 	/*
6299 	 * If the -info option has been selected then disable the
6300 	 * progress bar unless it has been explicitly enabled with
6301 	 * the -progress option
6302 	 */
6303 	if(!silent)
6304 		progress = force_progress;
6305 
6306 #ifdef SQUASHFS_TRACE
6307 	/*
6308 	 * Disable progress bar if full debug tracing is enabled.
6309 	 * The progress bar in this case just gets in the way of the
6310 	 * debug trace output
6311 	 */
6312 	progress = FALSE;
6313 #endif
6314 
6315 	for(i = 0; i < source; i++)
6316 		if(lstat(source_path[i], &source_buf) == -1) {
6317 			fprintf(stderr, "Cannot stat source directory \"%s\" "
6318 				"because %s\n", source_path[i],
6319 				strerror(errno));
6320 			EXIT_MKSQUASHFS();
6321 		}
6322 
6323 	destination_file = argv[source + 1];
6324 	if(stat(argv[source + 1], &buf) == -1) {
6325 		if(errno == ENOENT) { /* Does not exist */
6326 			fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR,
6327 				S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
6328 			if(fd == -1) {
6329 				perror("Could not create destination file");
6330 				exit(1);
6331 			}
6332 			delete = TRUE;
6333 		} else {
6334 			perror("Could not stat destination file");
6335 			exit(1);
6336 		}
6337 
6338 	} else {
6339 		if(S_ISBLK(buf.st_mode)) {
6340 			if((fd = open(argv[source + 1], O_RDWR)) == -1) {
6341 				perror("Could not open block device as "
6342 					"destination");
6343 				exit(1);
6344 			}
6345 			block_device = 1;
6346 
6347 		} else if(S_ISREG(buf.st_mode))	 {
6348 			fd = open(argv[source + 1], (delete ? O_TRUNC : 0) |
6349 				O_RDWR);
6350 			if(fd == -1) {
6351 				perror("Could not open regular file for "
6352 					"writing as destination");
6353 				exit(1);
6354 			}
6355 		}
6356 		else {
6357 			ERROR("Destination not block device or regular file\n");
6358 			exit(1);
6359 		}
6360 
6361 	}
6362 
6363 	/*
6364 	 * process the exclude files - must be done afer destination file has
6365 	 * been possibly created
6366 	 */
6367 	for(i = source + 2; i < argc; i++)
6368 		if(strcmp(argv[i], "-ef") == 0)
6369 			/*
6370 			 * Note presence of filename arg has already
6371 			 * been checked
6372 			 */
6373 			process_exclude_file(argv[++i]);
6374 		else if(strcmp(argv[i], "-e") == 0)
6375 			break;
6376 		else if(strcmp(argv[i], "-root-becomes") == 0 ||
6377 				strcmp(argv[i], "-sort") == 0 ||
6378 				strcmp(argv[i], "-pf") == 0 ||
6379 				strcmp(argv[i], "-af") == 0 ||
6380 				strcmp(argv[i], "-vaf") == 0 ||
6381 				strcmp(argv[i], "-comp") == 0)
6382 			i++;
6383 
6384 	if(i != argc) {
6385 		if(++i == argc) {
6386 			ERROR("%s: -e missing arguments\n", argv[0]);
6387 			EXIT_MKSQUASHFS();
6388 		}
6389 		while(i < argc)
6390 			if(old_exclude)
6391 				old_add_exclude(argv[i++]);
6392 			else
6393 				add_exclude(argv[i++]);
6394 	}
6395 
6396 	/* process the sort files - must be done afer the exclude files  */
6397 	for(i = source + 2; i < argc; i++)
6398 		if(strcmp(argv[i], "-sort") == 0) {
6399 			int res = read_sort_file(argv[++i], source,
6400 								source_path);
6401 			if(res == FALSE)
6402 				BAD_ERROR("Failed to read sort file\n");
6403 			sorted ++;
6404 		} else if(strcmp(argv[i], "-e") == 0)
6405 			break;
6406 		else if(strcmp(argv[i], "-root-becomes") == 0 ||
6407 				strcmp(argv[i], "-ef") == 0 ||
6408 				strcmp(argv[i], "-pf") == 0 ||
6409 				strcmp(argv[i], "-af") == 0 ||
6410 				strcmp(argv[i], "-vaf") == 0 ||
6411 				strcmp(argv[i], "-comp") == 0)
6412 			i++;
6413 
6414 	if(!delete) {
6415 	        comp = read_super(fd, &sBlk, argv[source + 1]);
6416 	        if(comp == NULL) {
6417 			ERROR("Failed to read existing filesystem - will not "
6418 				"overwrite - ABORTING!\n");
6419 			ERROR("To force Mksquashfs to write to this block "
6420 				"device or file use -noappend\n");
6421 			EXIT_MKSQUASHFS();
6422 		}
6423 
6424 		block_log = slog(block_size = sBlk.block_size);
6425 		noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags);
6426 		noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags);
6427 		noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags);
6428 		noX = SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.flags);
6429 		no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags);
6430 		always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags);
6431 		duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags);
6432 		exportable = SQUASHFS_EXPORTABLE(sBlk.flags);
6433 		no_xattrs = SQUASHFS_NO_XATTRS(sBlk.flags);
6434 		comp_opts = SQUASHFS_COMP_OPTS(sBlk.flags);
6435 	}
6436 
6437 	initialise_threads(readq, fragq, bwriteq, fwriteq, delete,
6438 		destination_file);
6439 
6440 	res = compressor_init(comp, &stream, SQUASHFS_METADATA_SIZE, 0);
6441 	if(res)
6442 		BAD_ERROR("compressor_init failed\n");
6443 
6444 	if(delete) {
6445 		int size;
6446 		void *comp_data = compressor_dump_options(comp, block_size,
6447 			&size);
6448 
6449 		printf("Creating %d.%d filesystem on %s, block size %d.\n",
6450 			SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size);
6451 
6452 		/*
6453 		 * store any compressor specific options after the superblock,
6454 		 * and set the COMP_OPT flag to show that the filesystem has
6455 		 * compressor specfic options
6456 		 */
6457 		if(comp_data) {
6458 			unsigned short c_byte = size | SQUASHFS_COMPRESSED_BIT;
6459 
6460 			SQUASHFS_INSWAP_SHORTS(&c_byte, 1);
6461 			write_destination(fd, sizeof(struct squashfs_super_block),
6462 				sizeof(c_byte), &c_byte);
6463 			write_destination(fd, sizeof(struct squashfs_super_block) +
6464 				sizeof(c_byte), size, comp_data);
6465 			bytes = sizeof(struct squashfs_super_block) + sizeof(c_byte)
6466 				+ size;
6467 			comp_opts = TRUE;
6468 		} else
6469 			bytes = sizeof(struct squashfs_super_block);
6470 	} else {
6471 		unsigned int last_directory_block, inode_dir_offset,
6472 			inode_dir_file_size, root_inode_size,
6473 			inode_dir_start_block, uncompressed_data,
6474 			compressed_data, inode_dir_inode_number,
6475 			inode_dir_parent_inode;
6476 		unsigned int root_inode_start =
6477 			SQUASHFS_INODE_BLK(sBlk.root_inode),
6478 			root_inode_offset =
6479 			SQUASHFS_INODE_OFFSET(sBlk.root_inode);
6480 
6481 		if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table,
6482 				&data_cache, &directory_table,
6483 				&directory_data_cache, &last_directory_block,
6484 				&inode_dir_offset, &inode_dir_file_size,
6485 				&root_inode_size, &inode_dir_start_block,
6486 				&file_count, &sym_count, &dev_count, &dir_count,
6487 				&fifo_count, &sock_count, &total_bytes,
6488 				&total_inode_bytes, &total_directory_bytes,
6489 				&inode_dir_inode_number,
6490 				&inode_dir_parent_inode, add_old_root_entry,
6491 				&fragment_table, &inode_lookup_table)) == 0) {
6492 			ERROR("Failed to read existing filesystem - will not "
6493 				"overwrite - ABORTING!\n");
6494 			ERROR("To force Mksquashfs to write to this block "
6495 				"device or file use -noappend\n");
6496 			EXIT_MKSQUASHFS();
6497 		}
6498 		if((append_fragments = fragments = sBlk.fragments)) {
6499 			fragment_table = realloc((char *) fragment_table,
6500 				((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1))
6501 				 * sizeof(struct squashfs_fragment_entry));
6502 			if(fragment_table == NULL)
6503 				BAD_ERROR("Out of memory in save filesystem state\n");
6504 		}
6505 
6506 		printf("Appending to existing %d.%d filesystem on %s, block "
6507 			"size %d\n", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1],
6508 			block_size);
6509 		printf("All -b, -noI, -noD, -noF, -noX, no-duplicates, no-fragments, "
6510 			"-always-use-fragments,\n-exportable and -comp options "
6511 			"ignored\n");
6512 		printf("\nIf appending is not wanted, please re-run with "
6513 			"-noappend specified!\n\n");
6514 
6515 		compressed_data = (inode_dir_offset + inode_dir_file_size) &
6516 			~(SQUASHFS_METADATA_SIZE - 1);
6517 		uncompressed_data = (inode_dir_offset + inode_dir_file_size) &
6518 			(SQUASHFS_METADATA_SIZE - 1);
6519 
6520 		/* save original filesystem state for restoring ... */
6521 		sfragments = fragments;
6522 		sbytes = bytes;
6523 		sinode_count = sBlk.inodes;
6524 		scache_bytes = root_inode_offset + root_inode_size;
6525 		sdirectory_cache_bytes = uncompressed_data;
6526 		sdata_cache = malloc(scache_bytes);
6527 		if(sdata_cache == NULL)
6528 			BAD_ERROR("Out of memory in save filesystem state\n");
6529 		sdirectory_data_cache = malloc(sdirectory_cache_bytes);
6530 		if(sdirectory_data_cache == NULL)
6531 			BAD_ERROR("Out of memory in save filesystem state\n");
6532 		memcpy(sdata_cache, data_cache, scache_bytes);
6533 		memcpy(sdirectory_data_cache, directory_data_cache +
6534 			compressed_data, sdirectory_cache_bytes);
6535 		sinode_bytes = root_inode_start;
6536 		stotal_bytes = total_bytes;
6537 		stotal_inode_bytes = total_inode_bytes;
6538 		stotal_directory_bytes = total_directory_bytes +
6539 			compressed_data;
6540 		sfile_count = file_count;
6541 		ssym_count = sym_count;
6542 		sdev_count = dev_count;
6543 		sdir_count = dir_count + 1;
6544 		sfifo_count = fifo_count;
6545 		ssock_count = sock_count;
6546 		sdup_files = dup_files;
6547 		sid_count = id_count;
6548 		write_recovery_data(&sBlk);
6549 		save_xattrs();
6550 		appending = TRUE;
6551 
6552 		/*
6553 		 * set the filesystem state up to be able to append to the
6554 		 * original filesystem.  The filesystem state differs depending
6555 		 * on whether we're appending to the original root directory, or
6556 		 * if the original root directory becomes a sub-directory
6557 		 * (root-becomes specified on command line, here root_name !=
6558 		 * NULL)
6559 		 */
6560 		inode_bytes = inode_size = root_inode_start;
6561 		directory_size = last_directory_block;
6562 		cache_size = root_inode_offset + root_inode_size;
6563 		directory_cache_size = inode_dir_offset + inode_dir_file_size;
6564 		if(root_name) {
6565 			sdirectory_bytes = last_directory_block;
6566 			sdirectory_compressed_bytes = 0;
6567 			root_inode_number = inode_dir_parent_inode;
6568 			inode_no = sBlk.inodes + 2;
6569 			directory_bytes = last_directory_block;
6570 			directory_cache_bytes = uncompressed_data;
6571 			memmove(directory_data_cache, directory_data_cache +
6572 				compressed_data, uncompressed_data);
6573 			cache_bytes = root_inode_offset + root_inode_size;
6574 			add_old_root_entry(root_name, sBlk.root_inode,
6575 				inode_dir_inode_number, SQUASHFS_DIR_TYPE);
6576 			total_directory_bytes += compressed_data;
6577 			dir_count ++;
6578 		} else {
6579 			sdirectory_compressed_bytes = last_directory_block -
6580 				inode_dir_start_block;
6581 			sdirectory_compressed =
6582 				malloc(sdirectory_compressed_bytes);
6583 			if(sdirectory_compressed == NULL)
6584 				BAD_ERROR("Out of memory in save filesystem "
6585 					"state\n");
6586 			memcpy(sdirectory_compressed, directory_table +
6587 				inode_dir_start_block,
6588 				sdirectory_compressed_bytes);
6589 			sdirectory_bytes = inode_dir_start_block;
6590 			root_inode_number = inode_dir_inode_number;
6591 			inode_no = sBlk.inodes + 1;
6592 			directory_bytes = inode_dir_start_block;
6593 			directory_cache_bytes = inode_dir_offset;
6594 			cache_bytes = root_inode_offset;
6595 		}
6596 
6597 		inode_count = file_count + dir_count + sym_count + dev_count +
6598 			fifo_count + sock_count;
6599 	}
6600 
6601 	if(path)
6602 		paths = add_subdir(paths, path);
6603 
6604 	dump_actions();
6605 	dump_pseudos();
6606 
6607 	if(delete && !keep_as_directory && source == 1 &&
6608 			S_ISDIR(source_buf.st_mode))
6609 		dir_scan(&inode, source_path[0], scan1_readdir, progress);
6610 	else if(!keep_as_directory && source == 1 &&
6611 			S_ISDIR(source_buf.st_mode))
6612 		dir_scan(&inode, source_path[0], scan1_single_readdir, progress);
6613 	else
6614 		dir_scan(&inode, "", scan1_encomp_readdir, progress);
6615 	sBlk.root_inode = inode;
6616 	sBlk.inodes = inode_count;
6617 	sBlk.s_magic = SQUASHFS_MAGIC;
6618 	sBlk.s_major = SQUASHFS_MAJOR;
6619 	sBlk.s_minor = SQUASHFS_MINOR;
6620 	sBlk.block_size = block_size;
6621 	sBlk.block_log = block_log;
6622 	sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, noX, no_fragments,
6623 		always_use_fragments, duplicate_checking, exportable,
6624 		no_xattrs, comp_opts);
6625 	sBlk.mkfs_time = time(NULL);
6626 
6627 	disable_info();
6628 
6629 	while((fragment = get_frag_action(fragment)))
6630 		write_fragment(*fragment);
6631 	unlock_fragments();
6632 	pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex);
6633 	pthread_mutex_lock(&fragment_mutex);
6634 	while(fragments_outstanding) {
6635 		pthread_mutex_unlock(&fragment_mutex);
6636 		sched_yield();
6637 		pthread_mutex_lock(&fragment_mutex);
6638 	}
6639 	pthread_cleanup_pop(1);
6640 
6641 	queue_put(to_writer, NULL);
6642 	if(queue_get(from_writer) != 0)
6643 		EXIT_MKSQUASHFS();
6644 
6645 	set_progressbar_state(FALSE);
6646 	write_filesystem_tables(&sBlk, nopad);
6647 
6648 /* ANDROID CHANGES START*/
6649 #ifdef ANDROID
6650 	if (block_map_file)
6651 		fclose(block_map_file);
6652 #endif
6653 /* ANDROID CHANGES END */
6654 
6655 	return 0;
6656 }
6657