1/*
2 * Unsquash 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
6 * Phillip Lougher <phillip@lougher.demon.co.uk>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * unsquashfs.c
23 */
24
25#include "unsquashfs.h"
26#include "squashfs_swap.h"
27#include "squashfs_compat.h"
28#include "read_fs.h"
29#include "compressor.h"
30#include "xattr.h"
31
32#include <sys/sysinfo.h>
33#include <sys/types.h>
34
35struct cache *fragment_cache, *data_cache;
36struct queue *to_reader, *to_deflate, *to_writer, *from_writer;
37pthread_t *thread, *deflator_thread;
38pthread_mutex_t	fragment_mutex;
39
40/* user options that control parallelisation */
41int processors = -1;
42
43struct super_block sBlk;
44squashfs_operations s_ops;
45struct compressor *comp;
46
47int bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0,
48	dev_count = 0, fifo_count = 0;
49char *inode_table = NULL, *directory_table = NULL;
50struct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536];
51int fd;
52unsigned int *uid_table, *guid_table;
53unsigned int cached_frag = SQUASHFS_INVALID_FRAG;
54char *fragment_data;
55char *file_data;
56char *data;
57unsigned int block_size;
58unsigned int block_log;
59int lsonly = FALSE, info = FALSE, force = FALSE, short_ls = TRUE;
60int use_regex = FALSE;
61char **created_inode;
62int root_process;
63int columns;
64int rotate = 0;
65pthread_mutex_t	screen_mutex;
66pthread_cond_t progress_wait;
67int progress = TRUE, progress_enabled = FALSE;
68unsigned int total_blocks = 0, total_files = 0, total_inodes = 0;
69unsigned int cur_blocks = 0;
70int inode_number = 1;
71int no_xattrs = XATTR_DEF;
72
73int lookup_type[] = {
74	0,
75	S_IFDIR,
76	S_IFREG,
77	S_IFLNK,
78	S_IFBLK,
79	S_IFCHR,
80	S_IFIFO,
81	S_IFSOCK,
82	S_IFDIR,
83	S_IFREG,
84	S_IFLNK,
85	S_IFBLK,
86	S_IFCHR,
87	S_IFIFO,
88	S_IFSOCK
89};
90
91struct test table[] = {
92	{ S_IFMT, S_IFSOCK, 0, 's' },
93	{ S_IFMT, S_IFLNK, 0, 'l' },
94	{ S_IFMT, S_IFBLK, 0, 'b' },
95	{ S_IFMT, S_IFDIR, 0, 'd' },
96	{ S_IFMT, S_IFCHR, 0, 'c' },
97	{ S_IFMT, S_IFIFO, 0, 'p' },
98	{ S_IRUSR, S_IRUSR, 1, 'r' },
99	{ S_IWUSR, S_IWUSR, 2, 'w' },
100	{ S_IRGRP, S_IRGRP, 4, 'r' },
101	{ S_IWGRP, S_IWGRP, 5, 'w' },
102	{ S_IROTH, S_IROTH, 7, 'r' },
103	{ S_IWOTH, S_IWOTH, 8, 'w' },
104	{ S_IXUSR | S_ISUID, S_IXUSR | S_ISUID, 3, 's' },
105	{ S_IXUSR | S_ISUID, S_ISUID, 3, 'S' },
106	{ S_IXUSR | S_ISUID, S_IXUSR, 3, 'x' },
107	{ S_IXGRP | S_ISGID, S_IXGRP | S_ISGID, 6, 's' },
108	{ S_IXGRP | S_ISGID, S_ISGID, 6, 'S' },
109	{ S_IXGRP | S_ISGID, S_IXGRP, 6, 'x' },
110	{ S_IXOTH | S_ISVTX, S_IXOTH | S_ISVTX, 9, 't' },
111	{ S_IXOTH | S_ISVTX, S_ISVTX, 9, 'T' },
112	{ S_IXOTH | S_ISVTX, S_IXOTH, 9, 'x' },
113	{ 0, 0, 0, 0}
114};
115
116void progress_bar(long long current, long long max, int columns);
117void update_progress_bar();
118
119void sigwinch_handler()
120{
121	struct winsize winsize;
122
123	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
124		if(isatty(STDOUT_FILENO))
125			ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
126				"columns\n");
127		columns = 80;
128	} else
129		columns = winsize.ws_col;
130}
131
132
133void sigalrm_handler()
134{
135	rotate = (rotate + 1) % 4;
136}
137
138
139struct queue *queue_init(int size)
140{
141	struct queue *queue = malloc(sizeof(struct queue));
142
143	if(queue == NULL)
144		EXIT_UNSQUASH("Out of memory in queue_init\n");
145
146	queue->data = malloc(sizeof(void *) * (size + 1));
147	if(queue->data == NULL)
148		EXIT_UNSQUASH("Out of memory in queue_init\n");
149
150	queue->size = size + 1;
151	queue->readp = queue->writep = 0;
152	pthread_mutex_init(&queue->mutex, NULL);
153	pthread_cond_init(&queue->empty, NULL);
154	pthread_cond_init(&queue->full, NULL);
155
156	return queue;
157}
158
159
160void queue_put(struct queue *queue, void *data)
161{
162	int nextp;
163
164	pthread_mutex_lock(&queue->mutex);
165
166	while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
167		pthread_cond_wait(&queue->full, &queue->mutex);
168
169	queue->data[queue->writep] = data;
170	queue->writep = nextp;
171	pthread_cond_signal(&queue->empty);
172	pthread_mutex_unlock(&queue->mutex);
173}
174
175
176void *queue_get(struct queue *queue)
177{
178	void *data;
179	pthread_mutex_lock(&queue->mutex);
180
181	while(queue->readp == queue->writep)
182		pthread_cond_wait(&queue->empty, &queue->mutex);
183
184	data = queue->data[queue->readp];
185	queue->readp = (queue->readp + 1) % queue->size;
186	pthread_cond_signal(&queue->full);
187	pthread_mutex_unlock(&queue->mutex);
188
189	return data;
190}
191
192
193/* Called with the cache mutex held */
194void insert_hash_table(struct cache *cache, struct cache_entry *entry)
195{
196	int hash = CALCULATE_HASH(entry->block);
197
198	entry->hash_next = cache->hash_table[hash];
199	cache->hash_table[hash] = entry;
200	entry->hash_prev = NULL;
201	if(entry->hash_next)
202		entry->hash_next->hash_prev = entry;
203}
204
205
206/* Called with the cache mutex held */
207void remove_hash_table(struct cache *cache, struct cache_entry *entry)
208{
209	if(entry->hash_prev)
210		entry->hash_prev->hash_next = entry->hash_next;
211	else
212		cache->hash_table[CALCULATE_HASH(entry->block)] =
213			entry->hash_next;
214	if(entry->hash_next)
215		entry->hash_next->hash_prev = entry->hash_prev;
216
217	entry->hash_prev = entry->hash_next = NULL;
218}
219
220
221/* Called with the cache mutex held */
222void insert_free_list(struct cache *cache, struct cache_entry *entry)
223{
224	if(cache->free_list) {
225		entry->free_next = cache->free_list;
226		entry->free_prev = cache->free_list->free_prev;
227		cache->free_list->free_prev->free_next = entry;
228		cache->free_list->free_prev = entry;
229	} else {
230		cache->free_list = entry;
231		entry->free_prev = entry->free_next = entry;
232	}
233}
234
235
236/* Called with the cache mutex held */
237void remove_free_list(struct cache *cache, struct cache_entry *entry)
238{
239	if(entry->free_prev == NULL && entry->free_next == NULL)
240		/* not in free list */
241		return;
242	else if(entry->free_prev == entry && entry->free_next == entry) {
243		/* only this entry in the free list */
244		cache->free_list = NULL;
245	} else {
246		/* more than one entry in the free list */
247		entry->free_next->free_prev = entry->free_prev;
248		entry->free_prev->free_next = entry->free_next;
249		if(cache->free_list == entry)
250			cache->free_list = entry->free_next;
251	}
252
253	entry->free_prev = entry->free_next = NULL;
254}
255
256
257struct cache *cache_init(int buffer_size, int max_buffers)
258{
259	struct cache *cache = malloc(sizeof(struct cache));
260
261	if(cache == NULL)
262		EXIT_UNSQUASH("Out of memory in cache_init\n");
263
264	cache->max_buffers = max_buffers;
265	cache->buffer_size = buffer_size;
266	cache->count = 0;
267	cache->free_list = NULL;
268	memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536);
269	cache->wait_free = FALSE;
270	cache->wait_pending = FALSE;
271	pthread_mutex_init(&cache->mutex, NULL);
272	pthread_cond_init(&cache->wait_for_free, NULL);
273	pthread_cond_init(&cache->wait_for_pending, NULL);
274
275	return cache;
276}
277
278
279struct cache_entry *cache_get(struct cache *cache, long long block, int size)
280{
281	/*
282	 * Get a block out of the cache.  If the block isn't in the cache
283 	 * it is added and queued to the reader() and deflate() threads for
284 	 * reading off disk and decompression.  The cache grows until max_blocks
285 	 * is reached, once this occurs existing discarded blocks on the free
286 	 * list are reused
287 	 */
288	int hash = CALCULATE_HASH(block);
289	struct cache_entry *entry;
290
291	pthread_mutex_lock(&cache->mutex);
292
293	for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
294		if(entry->block == block)
295			break;
296
297	if(entry) {
298		/*
299 		 * found the block in the cache, increment used count and
300 		 * if necessary remove from free list so it won't disappear
301 		 */
302		entry->used ++;
303		remove_free_list(cache, entry);
304		pthread_mutex_unlock(&cache->mutex);
305	} else {
306		/*
307 		 * not in the cache
308		 *
309		 * first try to allocate new block
310		 */
311		if(cache->count < cache->max_buffers) {
312			entry = malloc(sizeof(struct cache_entry));
313			if(entry == NULL)
314				EXIT_UNSQUASH("Out of memory in cache_get\n");
315			entry->data = malloc(cache->buffer_size);
316			if(entry->data == NULL)
317				EXIT_UNSQUASH("Out of memory in cache_get\n");
318			entry->cache = cache;
319			entry->free_prev = entry->free_next = NULL;
320			cache->count ++;
321		} else {
322			/*
323			 * try to get from free list
324			 */
325			while(cache->free_list == NULL) {
326				cache->wait_free = TRUE;
327				pthread_cond_wait(&cache->wait_for_free,
328					&cache->mutex);
329			}
330			entry = cache->free_list;
331			remove_free_list(cache, entry);
332			remove_hash_table(cache, entry);
333		}
334
335		/*
336		 * initialise block and insert into the hash table
337		 */
338		entry->block = block;
339		entry->size = size;
340		entry->used = 1;
341		entry->error = FALSE;
342		entry->pending = TRUE;
343		insert_hash_table(cache, entry);
344
345		/*
346		 * queue to read thread to read and ultimately (via the
347		 * decompress threads) decompress the buffer
348 		 */
349		pthread_mutex_unlock(&cache->mutex);
350		queue_put(to_reader, entry);
351	}
352
353	return entry;
354}
355
356
357void cache_block_ready(struct cache_entry *entry, int error)
358{
359	/*
360	 * mark cache entry as being complete, reading and (if necessary)
361 	 * decompression has taken place, and the buffer is valid for use.
362 	 * If an error occurs reading or decompressing, the buffer also
363 	 * becomes ready but with an error...
364 	 */
365	pthread_mutex_lock(&entry->cache->mutex);
366	entry->pending = FALSE;
367	entry->error = error;
368
369	/*
370	 * if the wait_pending flag is set, one or more threads may be waiting
371	 * on this buffer
372	 */
373	if(entry->cache->wait_pending) {
374		entry->cache->wait_pending = FALSE;
375		pthread_cond_broadcast(&entry->cache->wait_for_pending);
376	}
377
378	pthread_mutex_unlock(&entry->cache->mutex);
379}
380
381
382void cache_block_wait(struct cache_entry *entry)
383{
384	/*
385	 * wait for this cache entry to become ready, when reading and (if
386	 * necessary) decompression has taken place
387	 */
388	pthread_mutex_lock(&entry->cache->mutex);
389
390	while(entry->pending) {
391		entry->cache->wait_pending = TRUE;
392		pthread_cond_wait(&entry->cache->wait_for_pending,
393			&entry->cache->mutex);
394	}
395
396	pthread_mutex_unlock(&entry->cache->mutex);
397}
398
399
400void cache_block_put(struct cache_entry *entry)
401{
402	/*
403	 * finished with this cache entry, once the usage count reaches zero it
404 	 * can be reused and is put onto the free list.  As it remains
405 	 * accessible via the hash table it can be found getting a new lease of
406 	 * life before it is reused.
407 	 */
408	pthread_mutex_lock(&entry->cache->mutex);
409
410	entry->used --;
411	if(entry->used == 0) {
412		insert_free_list(entry->cache, entry);
413
414		/*
415		 * if the wait_free flag is set, one or more threads may be
416		 * waiting on this buffer
417		 */
418		if(entry->cache->wait_free) {
419			entry->cache->wait_free = FALSE;
420			pthread_cond_broadcast(&entry->cache->wait_for_free);
421		}
422	}
423
424	pthread_mutex_unlock(&entry->cache->mutex);
425}
426
427
428char *modestr(char *str, int mode)
429{
430	int i;
431
432	strcpy(str, "----------");
433
434	for(i = 0; table[i].mask != 0; i++) {
435		if((mode & table[i].mask) == table[i].value)
436			str[table[i].position] = table[i].mode;
437	}
438
439	return str;
440}
441
442
443#define TOTALCHARS  25
444int print_filename(char *pathname, struct inode *inode)
445{
446	char str[11], dummy[100], dummy2[100], *userstr, *groupstr;
447	int padchars;
448	struct passwd *user;
449	struct group *group;
450	struct tm *t;
451
452	if(short_ls) {
453		printf("%s\n", pathname);
454		return 1;
455	}
456
457	user = getpwuid(inode->uid);
458	if(user == NULL) {
459		sprintf(dummy, "%d", inode->uid);
460		userstr = dummy;
461	} else
462		userstr = user->pw_name;
463
464	group = getgrgid(inode->gid);
465	if(group == NULL) {
466		sprintf(dummy2, "%d", inode->gid);
467		groupstr = dummy2;
468	} else
469		groupstr = group->gr_name;
470
471	printf("%s %s/%s ", modestr(str, inode->mode), userstr, groupstr);
472
473	switch(inode->mode & S_IFMT) {
474		case S_IFREG:
475		case S_IFDIR:
476		case S_IFSOCK:
477		case S_IFIFO:
478		case S_IFLNK:
479			padchars = TOTALCHARS - strlen(userstr) -
480				strlen(groupstr);
481
482			printf("%*lld ", padchars > 0 ? padchars : 0,
483				inode->data);
484			break;
485		case S_IFCHR:
486		case S_IFBLK:
487			padchars = TOTALCHARS - strlen(userstr) -
488				strlen(groupstr) - 7;
489
490			printf("%*s%3d,%3d ", padchars > 0 ? padchars : 0, " ",
491				(int) inode->data >> 8, (int) inode->data &
492				0xff);
493			break;
494	}
495
496	t = localtime(&inode->time);
497
498	printf("%d-%02d-%02d %02d:%02d %s", t->tm_year + 1900, t->tm_mon + 1,
499		t->tm_mday, t->tm_hour, t->tm_min, pathname);
500	if((inode->mode & S_IFMT) == S_IFLNK)
501		printf(" -> %s", inode->symlink);
502	printf("\n");
503
504	return 1;
505}
506
507
508void add_entry(struct hash_table_entry *hash_table[], long long start,
509	int bytes)
510{
511	int hash = CALCULATE_HASH(start);
512	struct hash_table_entry *hash_table_entry;
513
514	hash_table_entry = malloc(sizeof(struct hash_table_entry));
515	if(hash_table_entry == NULL)
516		EXIT_UNSQUASH("Out of memory in add_entry\n");
517
518	hash_table_entry->start = start;
519	hash_table_entry->bytes = bytes;
520	hash_table_entry->next = hash_table[hash];
521	hash_table[hash] = hash_table_entry;
522}
523
524
525int lookup_entry(struct hash_table_entry *hash_table[], long long start)
526{
527	int hash = CALCULATE_HASH(start);
528	struct hash_table_entry *hash_table_entry;
529
530	for(hash_table_entry = hash_table[hash]; hash_table_entry;
531				hash_table_entry = hash_table_entry->next)
532
533		if(hash_table_entry->start == start)
534			return hash_table_entry->bytes;
535
536	return -1;
537}
538
539
540int read_fs_bytes(int fd, long long byte, int bytes, void *buff)
541{
542	off_t off = byte;
543	int res, count;
544
545	TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte,
546		bytes);
547
548	if(lseek(fd, off, SEEK_SET) == -1) {
549		ERROR("Lseek failed because %s\n", strerror(errno));
550		return FALSE;
551	}
552
553	for(count = 0; count < bytes; count += res) {
554		res = read(fd, buff + count, bytes - count);
555		if(res < 1) {
556			if(res == 0) {
557				ERROR("Read on filesystem failed because "
558					"EOF\n");
559				return FALSE;
560			} else if(errno != EINTR) {
561				ERROR("Read on filesystem failed because %s\n",
562						strerror(errno));
563				return FALSE;
564			} else
565				res = 0;
566		}
567	}
568
569	return TRUE;
570}
571
572
573int read_block(int fd, long long start, long long *next, void *block)
574{
575	unsigned short c_byte;
576	int offset = 2;
577
578	if(swap) {
579		if(read_fs_bytes(fd, start, 2, &c_byte) == FALSE)
580			goto failed;
581		c_byte = (c_byte >> 8) | ((c_byte & 0xff) << 8);
582	} else
583		if(read_fs_bytes(fd, start, 2, &c_byte) == FALSE)
584			goto failed;
585
586	TRACE("read_block: block @0x%llx, %d %s bytes\n", start,
587		SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ?
588		"compressed" : "uncompressed");
589
590	if(SQUASHFS_CHECK_DATA(sBlk.s.flags))
591		offset = 3;
592	if(SQUASHFS_COMPRESSED(c_byte)) {
593		char buffer[SQUASHFS_METADATA_SIZE];
594		int error, res;
595
596		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
597		if(read_fs_bytes(fd, start + offset, c_byte, buffer) == FALSE)
598			goto failed;
599
600		res = compressor_uncompress(comp, block, buffer, c_byte,
601			SQUASHFS_METADATA_SIZE, &error);
602
603		if(res == -1) {
604			ERROR("%s uncompress failed with error code %d\n",
605				comp->name, error);
606			goto failed;
607		}
608		if(next)
609			*next = start + offset + c_byte;
610		return res;
611	} else {
612		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
613		if(read_fs_bytes(fd, start + offset, c_byte, block) == FALSE)
614			goto failed;
615		if(next)
616			*next = start + offset + c_byte;
617		return c_byte;
618	}
619
620failed:
621	ERROR("read_block: failed to read block @0x%llx\n", start);
622	return FALSE;
623}
624
625
626int read_data_block(long long start, unsigned int size, char *block)
627{
628	int error, res;
629	int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
630
631	TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start,
632		c_byte, SQUASHFS_COMPRESSED_BLOCK(size) ? "compressed" :
633		"uncompressed");
634
635	if(SQUASHFS_COMPRESSED_BLOCK(size)) {
636		if(read_fs_bytes(fd, start, c_byte, data) == FALSE)
637			goto failed;
638
639		res = compressor_uncompress(comp, block, data, c_byte,
640			block_size, &error);
641
642		if(res == -1) {
643			ERROR("%s uncompress failed with error code %d\n",
644				comp->name, error);
645			goto failed;
646		}
647
648		return res;
649	} else {
650		if(read_fs_bytes(fd, start, c_byte, block) == FALSE)
651			goto failed;
652
653		return c_byte;
654	}
655
656failed:
657	ERROR("read_data_block: failed to read block @0x%llx, size %d\n", start,
658		c_byte);
659	return FALSE;
660}
661
662
663void uncompress_inode_table(long long start, long long end)
664{
665	int size = 0, bytes = 0, res;
666
667	TRACE("uncompress_inode_table: start %lld, end %lld\n", start, end);
668	while(start < end) {
669		if(size - bytes < SQUASHFS_METADATA_SIZE) {
670			inode_table = realloc(inode_table, size +=
671				SQUASHFS_METADATA_SIZE);
672			if(inode_table == NULL)
673				EXIT_UNSQUASH("Out of memory in "
674					"uncompress_inode_table");
675		}
676		TRACE("uncompress_inode_table: reading block 0x%llx\n", start);
677		add_entry(inode_table_hash, start, bytes);
678		res = read_block(fd, start, &start, inode_table + bytes);
679		if(res == 0) {
680			free(inode_table);
681			EXIT_UNSQUASH("uncompress_inode_table: failed to read "
682				"block \n");
683		}
684		bytes += res;
685	}
686}
687
688
689int set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time,
690	unsigned int xattr, unsigned int set_mode)
691{
692	struct utimbuf times = { time, time };
693
694	write_xattr(pathname, xattr);
695
696	if(utime(pathname, &times) == -1) {
697		ERROR("set_attributes: failed to set time on %s, because %s\n",
698			pathname, strerror(errno));
699		return FALSE;
700	}
701
702	if(root_process) {
703		if(chown(pathname, uid, guid) == -1) {
704			ERROR("set_attributes: failed to change uid and gids "
705				"on %s, because %s\n", pathname,
706				strerror(errno));
707			return FALSE;
708		}
709	} else
710		mode &= ~07000;
711
712	if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) {
713		ERROR("set_attributes: failed to change mode %s, because %s\n",
714			pathname, strerror(errno));
715		return FALSE;
716	}
717
718	return TRUE;
719}
720
721
722int write_bytes(int fd, char *buff, int bytes)
723{
724	int res, count;
725
726	for(count = 0; count < bytes; count += res) {
727		res = write(fd, buff + count, bytes - count);
728		if(res == -1) {
729			if(errno != EINTR) {
730				ERROR("Write on output file failed because "
731					"%s\n", strerror(errno));
732				return -1;
733			}
734			res = 0;
735		}
736	}
737
738	return 0;
739}
740
741
742int lseek_broken = FALSE;
743char *zero_data = NULL;
744
745int write_block(int file_fd, char *buffer, int size, long long hole, int sparse)
746{
747	off_t off = hole;
748
749	if(hole) {
750		if(sparse && lseek_broken == FALSE) {
751			 int error = lseek(file_fd, off, SEEK_CUR);
752			 if(error == -1)
753				/* failed to seek beyond end of file */
754				lseek_broken = TRUE;
755		}
756
757		if((sparse == FALSE || lseek_broken) && zero_data == NULL) {
758			if((zero_data = malloc(block_size)) == NULL)
759				EXIT_UNSQUASH("write_block: failed to alloc "
760					"zero data block\n");
761			memset(zero_data, 0, block_size);
762		}
763
764		if(sparse == FALSE || lseek_broken) {
765			int blocks = (hole + block_size -1) / block_size;
766			int avail_bytes, i;
767			for(i = 0; i < blocks; i++, hole -= avail_bytes) {
768				avail_bytes = hole > block_size ? block_size :
769					hole;
770				if(write_bytes(file_fd, zero_data, avail_bytes)
771						== -1)
772					goto failure;
773			}
774		}
775	}
776
777	if(write_bytes(file_fd, buffer, size) == -1)
778		goto failure;
779
780	return TRUE;
781
782failure:
783	return FALSE;
784}
785
786
787int write_file(struct inode *inode, char *pathname)
788{
789	unsigned int file_fd, i;
790	unsigned int *block_list;
791	int file_end = inode->data / block_size;
792	long long start = inode->start;
793	struct squashfs_file *file;
794
795	TRACE("write_file: regular file, blocks %d\n", inode->blocks);
796
797	file_fd = open(pathname, O_CREAT | O_WRONLY | (force ? O_TRUNC : 0),
798		(mode_t) inode->mode & 0777);
799	if(file_fd == -1) {
800		ERROR("write_file: failed to create file %s, because %s\n",
801			pathname, strerror(errno));
802		return FALSE;
803	}
804
805	block_list = malloc(inode->blocks * sizeof(unsigned int));
806	if(block_list == NULL)
807		EXIT_UNSQUASH("write_file: unable to malloc block list\n");
808
809	s_ops.read_block_list(block_list, inode->block_ptr, inode->blocks);
810
811	file = malloc(sizeof(struct squashfs_file));
812	if(file == NULL)
813		EXIT_UNSQUASH("write_file: unable to malloc file\n");
814
815	/*
816	 * the writer thread is queued a squashfs_file structure describing the
817 	 * file.  If the file has one or more blocks or a fragments they are
818 	 * queued separately (references to blocks in the cache).
819 	 */
820	file->fd = file_fd;
821	file->file_size = inode->data;
822	file->mode = inode->mode;
823	file->gid = inode->gid;
824	file->uid = inode->uid;
825	file->time = inode->time;
826	file->pathname = strdup(pathname);
827	file->blocks = inode->blocks + (inode->frag_bytes > 0);
828	file->sparse = inode->sparse;
829	file->xattr = inode->xattr;
830	queue_put(to_writer, file);
831
832	for(i = 0; i < inode->blocks; i++) {
833		int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
834		struct file_entry *block = malloc(sizeof(struct file_entry));
835
836		if(block == NULL)
837			EXIT_UNSQUASH("write_file: unable to malloc file\n");
838		block->offset = 0;
839		block->size = i == file_end ? inode->data & (block_size - 1) :
840			block_size;
841		if(block_list[i] == 0) /* sparse file */
842			block->buffer = NULL;
843		else {
844			block->buffer = cache_get(data_cache, start,
845				block_list[i]);
846			start += c_byte;
847		}
848		queue_put(to_writer, block);
849	}
850
851	if(inode->frag_bytes) {
852		int size;
853		long long start;
854		struct file_entry *block = malloc(sizeof(struct file_entry));
855
856		if(block == NULL)
857			EXIT_UNSQUASH("write_file: unable to malloc file\n");
858		s_ops.read_fragment(inode->fragment, &start, &size);
859		block->buffer = cache_get(fragment_cache, start, size);
860		block->offset = inode->offset;
861		block->size = inode->frag_bytes;
862		queue_put(to_writer, block);
863	}
864
865	free(block_list);
866	return TRUE;
867}
868
869
870int create_inode(char *pathname, struct inode *i)
871{
872	TRACE("create_inode: pathname %s\n", pathname);
873
874	if(created_inode[i->inode_number - 1]) {
875		TRACE("create_inode: hard link\n");
876		if(force)
877			unlink(pathname);
878
879		if(link(created_inode[i->inode_number - 1], pathname) == -1) {
880			ERROR("create_inode: failed to create hardlink, "
881				"because %s\n", strerror(errno));
882			return FALSE;
883		}
884
885		return TRUE;
886	}
887
888	switch(i->type) {
889		case SQUASHFS_FILE_TYPE:
890		case SQUASHFS_LREG_TYPE:
891			TRACE("create_inode: regular file, file_size %lld, "
892				"blocks %d\n", i->data, i->blocks);
893
894			if(write_file(i, pathname))
895				file_count ++;
896			break;
897		case SQUASHFS_SYMLINK_TYPE:
898		case SQUASHFS_LSYMLINK_TYPE:
899			TRACE("create_inode: symlink, symlink_size %lld\n",
900				i->data);
901
902			if(force)
903				unlink(pathname);
904
905			if(symlink(i->symlink, pathname) == -1) {
906				ERROR("create_inode: failed to create symlink "
907					"%s, because %s\n", pathname,
908					strerror(errno));
909				break;
910			}
911
912			write_xattr(pathname, i->xattr);
913
914			if(root_process) {
915				if(lchown(pathname, i->uid, i->gid) == -1)
916					ERROR("create_inode: failed to change "
917						"uid and gids on %s, because "
918						"%s\n", pathname,
919						strerror(errno));
920			}
921
922			sym_count ++;
923			break;
924 		case SQUASHFS_BLKDEV_TYPE:
925	 	case SQUASHFS_CHRDEV_TYPE:
926 		case SQUASHFS_LBLKDEV_TYPE:
927	 	case SQUASHFS_LCHRDEV_TYPE: {
928			int chrdev = i->type == SQUASHFS_CHRDEV_TYPE;
929			TRACE("create_inode: dev, rdev 0x%llx\n", i->data);
930
931			if(root_process) {
932				if(force)
933					unlink(pathname);
934
935				if(mknod(pathname, chrdev ? S_IFCHR : S_IFBLK,
936						makedev((i->data >> 8) & 0xff,
937						i->data & 0xff)) == -1) {
938					ERROR("create_inode: failed to create "
939						"%s device %s, because %s\n",
940						chrdev ? "character" : "block",
941						pathname, strerror(errno));
942					break;
943				}
944				set_attributes(pathname, i->mode, i->uid,
945					i->gid, i->time, i->xattr, TRUE);
946				dev_count ++;
947			} else
948				ERROR("create_inode: could not create %s "
949					"device %s, because you're not "
950					"superuser!\n", chrdev ? "character" :
951					"block", pathname);
952			break;
953		}
954		case SQUASHFS_FIFO_TYPE:
955		case SQUASHFS_LFIFO_TYPE:
956			TRACE("create_inode: fifo\n");
957
958			if(force)
959				unlink(pathname);
960
961			if(mknod(pathname, S_IFIFO, 0) == -1) {
962				ERROR("create_inode: failed to create fifo %s, "
963					"because %s\n", pathname,
964					strerror(errno));
965				break;
966			}
967			set_attributes(pathname, i->mode, i->uid, i->gid,
968				i->time, i->xattr, TRUE);
969			fifo_count ++;
970			break;
971		case SQUASHFS_SOCKET_TYPE:
972		case SQUASHFS_LSOCKET_TYPE:
973			TRACE("create_inode: socket\n");
974			ERROR("create_inode: socket %s ignored\n", pathname);
975			break;
976		default:
977			ERROR("Unknown inode type %d in create_inode_table!\n",
978				i->type);
979			return FALSE;
980	}
981
982	created_inode[i->inode_number - 1] = strdup(pathname);
983
984	return TRUE;
985}
986
987
988void uncompress_directory_table(long long start, long long end)
989{
990	int bytes = 0, size = 0, res;
991
992	TRACE("uncompress_directory_table: start %lld, end %lld\n", start, end);
993
994	while(start < end) {
995		if(size - bytes < SQUASHFS_METADATA_SIZE) {
996			directory_table = realloc(directory_table, size +=
997				SQUASHFS_METADATA_SIZE);
998			if(directory_table == NULL)
999				EXIT_UNSQUASH("Out of memory in "
1000					"uncompress_directory_table\n");
1001		}
1002		TRACE("uncompress_directory_table: reading block 0x%llx\n",
1003				start);
1004		add_entry(directory_table_hash, start, bytes);
1005		res = read_block(fd, start, &start, directory_table + bytes);
1006		if(res == 0)
1007			EXIT_UNSQUASH("uncompress_directory_table: failed to "
1008				"read block\n");
1009		bytes += res;
1010	}
1011}
1012
1013
1014int squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block,
1015unsigned int *offset, unsigned int *type)
1016{
1017	if(dir->cur_entry == dir->dir_count)
1018		return FALSE;
1019
1020	*name = dir->dirs[dir->cur_entry].name;
1021	*start_block = dir->dirs[dir->cur_entry].start_block;
1022	*offset = dir->dirs[dir->cur_entry].offset;
1023	*type = dir->dirs[dir->cur_entry].type;
1024	dir->cur_entry ++;
1025
1026	return TRUE;
1027}
1028
1029
1030void squashfs_closedir(struct dir *dir)
1031{
1032	free(dir->dirs);
1033	free(dir);
1034}
1035
1036
1037char *get_component(char *target, char *targname)
1038{
1039	while(*target == '/')
1040		target ++;
1041
1042	while(*target != '/' && *target!= '\0')
1043		*targname ++ = *target ++;
1044
1045	*targname = '\0';
1046
1047	return target;
1048}
1049
1050
1051void free_path(struct pathname *paths)
1052{
1053	int i;
1054
1055	for(i = 0; i < paths->names; i++) {
1056		if(paths->name[i].paths)
1057			free_path(paths->name[i].paths);
1058		free(paths->name[i].name);
1059		if(paths->name[i].preg) {
1060			regfree(paths->name[i].preg);
1061			free(paths->name[i].preg);
1062		}
1063	}
1064
1065	free(paths);
1066}
1067
1068
1069struct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
1070{
1071	char targname[1024];
1072	int i, error;
1073
1074	TRACE("add_path: adding \"%s\" extract file\n", target);
1075
1076	target = get_component(target, targname);
1077
1078	if(paths == NULL) {
1079		paths = malloc(sizeof(struct pathname));
1080		if(paths == NULL)
1081			EXIT_UNSQUASH("failed to allocate paths\n");
1082
1083		paths->names = 0;
1084		paths->name = NULL;
1085	}
1086
1087	for(i = 0; i < paths->names; i++)
1088		if(strcmp(paths->name[i].name, targname) == 0)
1089			break;
1090
1091	if(i == paths->names) {
1092		/*
1093		 * allocate new name entry
1094		 */
1095		paths->names ++;
1096		paths->name = realloc(paths->name, (i + 1) *
1097			sizeof(struct path_entry));
1098		if(paths->name == NULL)
1099			EXIT_UNSQUASH("Out of memory in add_path\n");
1100		paths->name[i].name = strdup(targname);
1101		paths->name[i].paths = NULL;
1102		if(use_regex) {
1103			paths->name[i].preg = malloc(sizeof(regex_t));
1104			if(paths->name[i].preg == NULL)
1105				EXIT_UNSQUASH("Out of memory in add_path\n");
1106			error = regcomp(paths->name[i].preg, targname,
1107				REG_EXTENDED|REG_NOSUB);
1108			if(error) {
1109				char str[1024];
1110
1111				regerror(error, paths->name[i].preg, str, 1024);
1112				EXIT_UNSQUASH("invalid regex %s in export %s, "
1113					"because %s\n", targname, alltarget,
1114					str);
1115			}
1116		} else
1117			paths->name[i].preg = NULL;
1118
1119		if(target[0] == '\0')
1120			/*
1121			 * at leaf pathname component
1122			*/
1123			paths->name[i].paths = NULL;
1124		else
1125			/*
1126			 * recurse adding child components
1127			 */
1128			paths->name[i].paths = add_path(NULL, target, alltarget);
1129	} else {
1130		/*
1131		 * existing matching entry
1132		 */
1133		if(paths->name[i].paths == NULL) {
1134			/*
1135			 * No sub-directory which means this is the leaf
1136			 * component of a pre-existing extract which subsumes
1137			 * the extract currently being added, in which case stop
1138			 * adding components
1139			 */
1140		} else if(target[0] == '\0') {
1141			/*
1142			 * at leaf pathname component and child components exist
1143			 * from more specific extracts, delete as they're
1144			 * subsumed by this extract
1145			 */
1146			free_path(paths->name[i].paths);
1147			paths->name[i].paths = NULL;
1148		} else
1149			/*
1150			 * recurse adding child components
1151			 */
1152			add_path(paths->name[i].paths, target, alltarget);
1153	}
1154
1155	return paths;
1156}
1157
1158
1159struct pathnames *init_subdir()
1160{
1161	struct pathnames *new = malloc(sizeof(struct pathnames));
1162	if(new == NULL)
1163		EXIT_UNSQUASH("Out of memory in init_subdir\n");
1164	new->count = 0;
1165	return new;
1166}
1167
1168
1169struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
1170{
1171	if(paths->count % PATHS_ALLOC_SIZE == 0) {
1172		paths = realloc(paths, sizeof(struct pathnames *) +
1173			(paths->count + PATHS_ALLOC_SIZE) *
1174			sizeof(struct pathname *));
1175		if(paths == NULL)
1176			EXIT_UNSQUASH("Out of memory in add_subdir\n");
1177	}
1178
1179	paths->path[paths->count++] = path;
1180	return paths;
1181}
1182
1183
1184void free_subdir(struct pathnames *paths)
1185{
1186	free(paths);
1187}
1188
1189
1190int matches(struct pathnames *paths, char *name, struct pathnames **new)
1191{
1192	int i, n;
1193
1194	if(paths == NULL) {
1195		*new = NULL;
1196		return TRUE;
1197	}
1198
1199	*new = init_subdir();
1200
1201	for(n = 0; n < paths->count; n++) {
1202		struct pathname *path = paths->path[n];
1203		for(i = 0; i < path->names; i++) {
1204			int match = use_regex ?
1205				regexec(path->name[i].preg, name, (size_t) 0,
1206				NULL, 0) == 0 : fnmatch(path->name[i].name,
1207				name, FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) ==
1208				0;
1209			if(match && path->name[i].paths == NULL)
1210				/*
1211				 * match on a leaf component, any subdirectories
1212				 * will implicitly match, therefore return an
1213				 * empty new search set
1214				 */
1215				goto empty_set;
1216
1217			if(match)
1218				/*
1219				 * match on a non-leaf component, add any
1220				 * subdirectories to the new set of
1221				 * subdirectories to scan for this name
1222				 */
1223				*new = add_subdir(*new, path->name[i].paths);
1224		}
1225	}
1226
1227	if((*new)->count == 0) {
1228		/*
1229		 * no matching names found, delete empty search set, and return
1230		 * FALSE
1231		 */
1232		free_subdir(*new);
1233		*new = NULL;
1234		return FALSE;
1235	}
1236
1237	/*
1238	 * one or more matches with sub-directories found (no leaf matches),
1239	 * return new search set and return TRUE
1240	 */
1241	return TRUE;
1242
1243empty_set:
1244	/*
1245	 * found matching leaf exclude, return empty search set and return TRUE
1246	 */
1247	free_subdir(*new);
1248	*new = NULL;
1249	return TRUE;
1250}
1251
1252
1253void pre_scan(char *parent_name, unsigned int start_block, unsigned int offset,
1254	struct pathnames *paths)
1255{
1256	unsigned int type;
1257	char *name, pathname[1024];
1258	struct pathnames *new;
1259	struct inode *i;
1260	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1261
1262	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
1263		struct inode *i;
1264
1265		TRACE("pre_scan: name %s, start_block %d, offset %d, type %d\n",
1266			name, start_block, offset, type);
1267
1268		if(!matches(paths, name, &new))
1269			continue;
1270
1271		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
1272
1273		if(type == SQUASHFS_DIR_TYPE)
1274			pre_scan(parent_name, start_block, offset, new);
1275		else if(new == NULL) {
1276			if(type == SQUASHFS_FILE_TYPE ||
1277					type == SQUASHFS_LREG_TYPE) {
1278				i = s_ops.read_inode(start_block, offset);
1279				if(created_inode[i->inode_number - 1] == NULL) {
1280					created_inode[i->inode_number - 1] =
1281						(char *) i;
1282					total_blocks += (i->data +
1283						(block_size - 1)) >> block_log;
1284				}
1285				total_files ++;
1286			}
1287			total_inodes ++;
1288		}
1289
1290		free_subdir(new);
1291	}
1292
1293	squashfs_closedir(dir);
1294}
1295
1296
1297void dir_scan(char *parent_name, unsigned int start_block, unsigned int offset,
1298	struct pathnames *paths)
1299{
1300	unsigned int type;
1301	char *name, pathname[1024];
1302	struct pathnames *new;
1303	struct inode *i;
1304	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1305
1306	if(lsonly || info)
1307		print_filename(parent_name, i);
1308
1309	if(!lsonly && mkdir(parent_name, (mode_t) dir->mode) == -1 &&
1310			(!force || errno != EEXIST)) {
1311		ERROR("dir_scan: failed to make directory %s, because %s\n",
1312			parent_name, strerror(errno));
1313		squashfs_closedir(dir);
1314		return;
1315	}
1316
1317	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
1318		TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n",
1319			name, start_block, offset, type);
1320
1321
1322		if(!matches(paths, name, &new))
1323			continue;
1324
1325		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
1326
1327		if(type == SQUASHFS_DIR_TYPE)
1328			dir_scan(pathname, start_block, offset, new);
1329		else if(new == NULL) {
1330			i = s_ops.read_inode(start_block, offset);
1331
1332			if(lsonly || info)
1333				print_filename(pathname, i);
1334
1335			if(!lsonly) {
1336				create_inode(pathname, i);
1337				update_progress_bar();
1338				}
1339
1340			if(i->type == SQUASHFS_SYMLINK_TYPE ||
1341					i->type == SQUASHFS_LSYMLINK_TYPE)
1342				free(i->symlink);
1343		}
1344
1345		free_subdir(new);
1346	}
1347
1348	if(!lsonly)
1349		set_attributes(parent_name, dir->mode, dir->uid, dir->guid,
1350			dir->mtime, dir->xattr, force);
1351
1352	squashfs_closedir(dir);
1353	dir_count ++;
1354}
1355
1356
1357void squashfs_stat(char *source)
1358{
1359	time_t mkfs_time = (time_t) sBlk.s.mkfs_time;
1360	char *mkfs_str = ctime(&mkfs_time);
1361
1362#if __BYTE_ORDER == __BIG_ENDIAN
1363	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n",
1364		sBlk.s.s_major == 4 ? "" : swap ? "little endian " :
1365		"big endian ", sBlk.s.s_major, sBlk.s.s_minor, source);
1366#else
1367	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n",
1368		sBlk.s.s_major == 4 ? "" : swap ? "big endian " :
1369		"little endian ", sBlk.s.s_major, sBlk.s.s_minor, source);
1370#endif
1371
1372	printf("Creation or last append time %s", mkfs_str ? mkfs_str :
1373		"failed to get time\n");
1374	printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n",
1375		sBlk.s.bytes_used / 1024.0, sBlk.s.bytes_used /
1376		(1024.0 * 1024.0));
1377
1378	if(sBlk.s.s_major == 4)
1379		printf("Compression %s\n", comp->name);
1380
1381	printf("Block size %d\n", sBlk.s.block_size);
1382	printf("Filesystem is %sexportable via NFS\n",
1383		SQUASHFS_EXPORTABLE(sBlk.s.flags) ? "" : "not ");
1384	printf("Inodes are %scompressed\n",
1385		SQUASHFS_UNCOMPRESSED_INODES(sBlk.s.flags) ? "un" : "");
1386	printf("Data is %scompressed\n",
1387		SQUASHFS_UNCOMPRESSED_DATA(sBlk.s.flags) ? "un" : "");
1388
1389	if(sBlk.s.s_major > 1) {
1390		if(SQUASHFS_NO_FRAGMENTS(sBlk.s.flags))
1391			printf("Fragments are not stored\n");
1392		else {
1393			printf("Fragments are %scompressed\n",
1394				SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.s.flags) ?
1395				"un" : "");
1396			printf("Always_use_fragments option is %sspecified\n",
1397				SQUASHFS_ALWAYS_FRAGMENTS(sBlk.s.flags) ? "" :
1398				"not ");
1399		}
1400	}
1401
1402	if(sBlk.s.s_major == 4) {
1403		if(SQUASHFS_NO_XATTRS(sBlk.s.flags))
1404			printf("Xattrs are not stored\n");
1405		else
1406			printf("Xattrs are %scompressed\n",
1407				SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.s.flags) ?
1408				"un" : "");
1409	}
1410
1411	if(sBlk.s.s_major < 4)
1412			printf("Check data is %spresent in the filesystem\n",
1413				SQUASHFS_CHECK_DATA(sBlk.s.flags) ? "" :
1414				"not ");
1415
1416	if(sBlk.s.s_major > 1)
1417		printf("Duplicates are %sremoved\n",
1418			SQUASHFS_DUPLICATES(sBlk.s.flags) ? "" : "not ");
1419	else
1420		printf("Duplicates are removed\n");
1421
1422	if(sBlk.s.s_major > 1)
1423		printf("Number of fragments %d\n", sBlk.s.fragments);
1424
1425	printf("Number of inodes %d\n", sBlk.s.inodes);
1426
1427	if(sBlk.s.s_major == 4)
1428		printf("Number of ids %d\n", sBlk.s.no_ids);
1429	else {
1430		printf("Number of uids %d\n", sBlk.no_uids);
1431		printf("Number of gids %d\n", sBlk.no_guids);
1432	}
1433
1434	TRACE("sBlk.s.inode_table_start 0x%llx\n", sBlk.s.inode_table_start);
1435	TRACE("sBlk.s.directory_table_start 0x%llx\n",
1436		sBlk.s.directory_table_start);
1437
1438	if(sBlk.s.s_major == 4) {
1439		TRACE("sBlk.s.id_table_start 0x%llx\n", sBlk.s.id_table_start);
1440		TRACE("sBlk.s.xattr_id_table_start 0x%llx\n",
1441			sBlk.s.xattr_id_table_start);
1442	} else {
1443		TRACE("sBlk.uid_start 0x%llx\n", sBlk.uid_start);
1444		TRACE("sBlk.guid_start 0x%llx\n", sBlk.guid_start);
1445	}
1446
1447	if(sBlk.s.s_major > 1)
1448		TRACE("sBlk.s.fragment_table_start 0x%llx\n\n",
1449			sBlk.s.fragment_table_start);
1450}
1451
1452
1453int read_super(char *source)
1454{
1455	squashfs_super_block_3 sBlk_3;
1456	struct squashfs_super_block sBlk_4;
1457
1458	/*
1459	 * Try to read a Squashfs 4 superblock
1460	 */
1461	read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
1462		&sBlk_4);
1463	swap = sBlk_4.s_magic != SQUASHFS_MAGIC;
1464	SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4);
1465
1466	if(sBlk_4.s_magic == SQUASHFS_MAGIC && sBlk_4.s_major == 4 &&
1467			sBlk_4.s_minor == 0) {
1468		s_ops.squashfs_opendir = squashfs_opendir_4;
1469		s_ops.read_fragment = read_fragment_4;
1470		s_ops.read_fragment_table = read_fragment_table_4;
1471		s_ops.read_block_list = read_block_list_2;
1472		s_ops.read_inode = read_inode_4;
1473		s_ops.read_uids_guids = read_uids_guids_4;
1474		memcpy(&sBlk, &sBlk_4, sizeof(sBlk_4));
1475
1476		/*
1477		 * Check the compression type
1478		 */
1479		comp = lookup_compressor_id(sBlk.s.compression);
1480		return TRUE;
1481	}
1482
1483	/*
1484 	 * Not a Squashfs 4 superblock, try to read a squashfs 3 superblock
1485 	 * (compatible with 1 and 2 filesystems)
1486 	 */
1487	read_fs_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block_3),
1488		&sBlk_3);
1489
1490	/*
1491	 * Check it is a SQUASHFS superblock
1492	 */
1493	swap = 0;
1494	if(sBlk_3.s_magic != SQUASHFS_MAGIC) {
1495		if(sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP) {
1496			squashfs_super_block_3 sblk;
1497			ERROR("Reading a different endian SQUASHFS filesystem "
1498				"on %s\n", source);
1499			SQUASHFS_SWAP_SUPER_BLOCK_3(&sblk, &sBlk_3);
1500			memcpy(&sBlk_3, &sblk, sizeof(squashfs_super_block_3));
1501			swap = 1;
1502		} else  {
1503			ERROR("Can't find a SQUASHFS superblock on %s\n",
1504				source);
1505			goto failed_mount;
1506		}
1507	}
1508
1509	sBlk.s.s_magic = sBlk_3.s_magic;
1510	sBlk.s.inodes = sBlk_3.inodes;
1511	sBlk.s.mkfs_time = sBlk_3.mkfs_time;
1512	sBlk.s.block_size = sBlk_3.block_size;
1513	sBlk.s.fragments = sBlk_3.fragments;
1514	sBlk.s.block_log = sBlk_3.block_log;
1515	sBlk.s.flags = sBlk_3.flags;
1516	sBlk.s.s_major = sBlk_3.s_major;
1517	sBlk.s.s_minor = sBlk_3.s_minor;
1518	sBlk.s.root_inode = sBlk_3.root_inode;
1519	sBlk.s.bytes_used = sBlk_3.bytes_used;
1520	sBlk.s.inode_table_start = sBlk_3.inode_table_start;
1521	sBlk.s.directory_table_start = sBlk_3.directory_table_start;
1522	sBlk.s.fragment_table_start = sBlk_3.fragment_table_start;
1523	sBlk.s.lookup_table_start = sBlk_3.lookup_table_start;
1524	sBlk.no_uids = sBlk_3.no_uids;
1525	sBlk.no_guids = sBlk_3.no_guids;
1526	sBlk.uid_start = sBlk_3.uid_start;
1527	sBlk.guid_start = sBlk_3.guid_start;
1528	sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK;
1529
1530	/* Check the MAJOR & MINOR versions */
1531	if(sBlk.s.s_major == 1 || sBlk.s.s_major == 2) {
1532		sBlk.s.bytes_used = sBlk_3.bytes_used_2;
1533		sBlk.uid_start = sBlk_3.uid_start_2;
1534		sBlk.guid_start = sBlk_3.guid_start_2;
1535		sBlk.s.inode_table_start = sBlk_3.inode_table_start_2;
1536		sBlk.s.directory_table_start = sBlk_3.directory_table_start_2;
1537
1538		if(sBlk.s.s_major == 1) {
1539			sBlk.s.block_size = sBlk_3.block_size_1;
1540			sBlk.s.fragment_table_start = sBlk.uid_start;
1541			s_ops.squashfs_opendir = squashfs_opendir_1;
1542			s_ops.read_fragment_table = read_fragment_table_1;
1543			s_ops.read_block_list = read_block_list_1;
1544			s_ops.read_inode = read_inode_1;
1545			s_ops.read_uids_guids = read_uids_guids_1;
1546		} else {
1547			sBlk.s.fragment_table_start =
1548				sBlk_3.fragment_table_start_2;
1549			s_ops.squashfs_opendir = squashfs_opendir_1;
1550			s_ops.read_fragment = read_fragment_2;
1551			s_ops.read_fragment_table = read_fragment_table_2;
1552			s_ops.read_block_list = read_block_list_2;
1553			s_ops.read_inode = read_inode_2;
1554			s_ops.read_uids_guids = read_uids_guids_1;
1555		}
1556	} else if(sBlk.s.s_major == 3) {
1557		s_ops.squashfs_opendir = squashfs_opendir_3;
1558		s_ops.read_fragment = read_fragment_3;
1559		s_ops.read_fragment_table = read_fragment_table_3;
1560		s_ops.read_block_list = read_block_list_2;
1561		s_ops.read_inode = read_inode_3;
1562		s_ops.read_uids_guids = read_uids_guids_1;
1563	} else {
1564		ERROR("Filesystem on %s is (%d:%d), ", source, sBlk.s.s_major,
1565			sBlk.s.s_minor);
1566		ERROR("which is a later filesystem version than I support!\n");
1567		goto failed_mount;
1568	}
1569
1570	/*
1571	 * 1.x, 2.x and 3.x filesystems use gzip compression.
1572	 */
1573	comp = lookup_compressor("gzip");
1574	return TRUE;
1575
1576failed_mount:
1577	return FALSE;
1578}
1579
1580
1581struct pathname *process_extract_files(struct pathname *path, char *filename)
1582{
1583	FILE *fd;
1584	char name[16384];
1585
1586	fd = fopen(filename, "r");
1587	if(fd == NULL)
1588		EXIT_UNSQUASH("Could not open %s, because %s\n", filename,
1589			strerror(errno));
1590
1591	while(fscanf(fd, "%16384[^\n]\n", name) != EOF)
1592		path = add_path(path, name, name);
1593
1594	fclose(fd);
1595	return path;
1596}
1597
1598
1599/*
1600 * reader thread.  This thread processes read requests queued by the
1601 * cache_get() routine.
1602 */
1603void *reader(void *arg)
1604{
1605	while(1) {
1606		struct cache_entry *entry = queue_get(to_reader);
1607		int res = read_fs_bytes(fd, entry->block,
1608			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size),
1609			entry->data);
1610
1611		if(res && SQUASHFS_COMPRESSED_BLOCK(entry->size))
1612			/*
1613			 * queue successfully read block to the deflate
1614			 * thread(s) for further processing
1615 			 */
1616			queue_put(to_deflate, entry);
1617		else
1618			/*
1619			 * block has either been successfully read and is
1620			 * uncompressed, or an error has occurred, clear pending
1621			 * flag, set error appropriately, and wake up any
1622			 * threads waiting on this buffer
1623			 */
1624			cache_block_ready(entry, !res);
1625	}
1626}
1627
1628
1629/*
1630 * writer thread.  This processes file write requests queued by the
1631 * write_file() routine.
1632 */
1633void *writer(void *arg)
1634{
1635	int i;
1636
1637	while(1) {
1638		struct squashfs_file *file = queue_get(to_writer);
1639		int file_fd;
1640		long long hole = 0;
1641		int failed = FALSE;
1642		int error;
1643
1644		if(file == NULL) {
1645			queue_put(from_writer, NULL);
1646			continue;
1647		}
1648
1649		TRACE("writer: regular file, blocks %d\n", file->blocks);
1650
1651		file_fd = file->fd;
1652
1653		for(i = 0; i < file->blocks; i++, cur_blocks ++) {
1654			struct file_entry *block = queue_get(to_writer);
1655
1656			if(block->buffer == 0) { /* sparse file */
1657				hole += block->size;
1658				free(block);
1659				continue;
1660			}
1661
1662			cache_block_wait(block->buffer);
1663
1664			if(block->buffer->error)
1665				failed = TRUE;
1666
1667			if(failed)
1668				continue;
1669
1670			error = write_block(file_fd, block->buffer->data +
1671				block->offset, block->size, hole, file->sparse);
1672
1673			if(error == FALSE) {
1674				ERROR("writer: failed to write data block %d\n",
1675					i);
1676				failed = TRUE;
1677			}
1678
1679			hole = 0;
1680			cache_block_put(block->buffer);
1681			free(block);
1682		}
1683
1684		if(hole && failed == FALSE) {
1685			/*
1686			 * corner case for hole extending to end of file
1687			 */
1688			if(file->sparse == FALSE ||
1689					lseek(file_fd, hole, SEEK_CUR) == -1) {
1690				/*
1691				 * for files which we don't want to write
1692				 * sparsely, or for broken lseeks which cannot
1693				 * seek beyond end of file, write_block will do
1694				 * the right thing
1695				 */
1696				hole --;
1697				if(write_block(file_fd, "\0", 1, hole,
1698						file->sparse) == FALSE) {
1699					ERROR("writer: failed to write sparse "
1700						"data block\n");
1701					failed = TRUE;
1702				}
1703			} else if(ftruncate(file_fd, file->file_size) == -1) {
1704				ERROR("writer: failed to write sparse data "
1705					"block\n");
1706				failed = TRUE;
1707			}
1708		}
1709
1710		close(file_fd);
1711		if(failed == FALSE)
1712			set_attributes(file->pathname, file->mode, file->uid,
1713				file->gid, file->time, file->xattr, force);
1714		else {
1715			ERROR("Failed to write %s, skipping\n", file->pathname);
1716			unlink(file->pathname);
1717		}
1718		free(file->pathname);
1719		free(file);
1720
1721	}
1722}
1723
1724
1725/*
1726 * decompress thread.  This decompresses buffers queued by the read thread
1727 */
1728void *deflator(void *arg)
1729{
1730	char tmp[block_size];
1731
1732	while(1) {
1733		struct cache_entry *entry = queue_get(to_deflate);
1734		int error, res;
1735
1736		res = compressor_uncompress(comp, tmp, entry->data,
1737			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size), block_size,
1738			&error);
1739
1740		if(res == -1)
1741			ERROR("%s uncompress failed with error code %d\n",
1742				comp->name, error);
1743		else
1744			memcpy(entry->data, tmp, res);
1745
1746		/*
1747		 * block has been either successfully decompressed, or an error
1748 		 * occurred, clear pending flag, set error appropriately and
1749 		 * wake up any threads waiting on this block
1750 		 */
1751		cache_block_ready(entry, res == -1);
1752	}
1753}
1754
1755
1756void *progress_thread(void *arg)
1757{
1758	struct timeval timeval;
1759	struct timespec timespec;
1760	struct itimerval itimerval;
1761	struct winsize winsize;
1762
1763	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
1764		if(isatty(STDOUT_FILENO))
1765			ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
1766				"columns\n");
1767		columns = 80;
1768	} else
1769		columns = winsize.ws_col;
1770	signal(SIGWINCH, sigwinch_handler);
1771	signal(SIGALRM, sigalrm_handler);
1772
1773	itimerval.it_value.tv_sec = 0;
1774	itimerval.it_value.tv_usec = 250000;
1775	itimerval.it_interval.tv_sec = 0;
1776	itimerval.it_interval.tv_usec = 250000;
1777	setitimer(ITIMER_REAL, &itimerval, NULL);
1778
1779	pthread_cond_init(&progress_wait, NULL);
1780
1781	pthread_mutex_lock(&screen_mutex);
1782	while(1) {
1783		gettimeofday(&timeval, NULL);
1784		timespec.tv_sec = timeval.tv_sec;
1785		if(timeval.tv_usec + 250000 > 999999)
1786			timespec.tv_sec++;
1787		timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) *
1788			1000;
1789		pthread_cond_timedwait(&progress_wait, &screen_mutex,
1790			&timespec);
1791		if(progress_enabled)
1792			progress_bar(sym_count + dev_count +
1793				fifo_count + cur_blocks, total_inodes -
1794				total_files + total_blocks, columns);
1795	}
1796}
1797
1798
1799void initialise_threads(int fragment_buffer_size, int data_buffer_size)
1800{
1801	int i;
1802	sigset_t sigmask, old_mask;
1803	int all_buffers_size = fragment_buffer_size + data_buffer_size;
1804
1805	sigemptyset(&sigmask);
1806	sigaddset(&sigmask, SIGINT);
1807	sigaddset(&sigmask, SIGQUIT);
1808	if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
1809		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
1810			"\n");
1811
1812	if(processors == -1) {
1813#ifndef linux
1814		int mib[2];
1815		size_t len = sizeof(processors);
1816
1817		mib[0] = CTL_HW;
1818#ifdef HW_AVAILCPU
1819		mib[1] = HW_AVAILCPU;
1820#else
1821		mib[1] = HW_NCPU;
1822#endif
1823
1824		if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
1825			ERROR("Failed to get number of available processors.  "
1826				"Defaulting to 1\n");
1827			processors = 1;
1828		}
1829#else
1830		processors = sysconf(_SC_NPROCESSORS_ONLN);
1831#endif
1832	}
1833
1834	thread = malloc((3 + processors) * sizeof(pthread_t));
1835	if(thread == NULL)
1836		EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
1837	deflator_thread = &thread[3];
1838
1839	to_reader = queue_init(all_buffers_size);
1840	to_deflate = queue_init(all_buffers_size);
1841	to_writer = queue_init(1000);
1842	from_writer = queue_init(1);
1843	fragment_cache = cache_init(block_size, fragment_buffer_size);
1844	data_cache = cache_init(block_size, data_buffer_size);
1845	pthread_create(&thread[0], NULL, reader, NULL);
1846	pthread_create(&thread[1], NULL, writer, NULL);
1847	pthread_create(&thread[2], NULL, progress_thread, NULL);
1848	pthread_mutex_init(&fragment_mutex, NULL);
1849
1850	for(i = 0; i < processors; i++) {
1851		if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
1852				 0)
1853			EXIT_UNSQUASH("Failed to create thread\n");
1854	}
1855
1856	printf("Parallel unsquashfs: Using %d processor%s\n", processors,
1857			processors == 1 ? "" : "s");
1858
1859	if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
1860		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
1861			"\n");
1862}
1863
1864
1865void enable_progress_bar()
1866{
1867	pthread_mutex_lock(&screen_mutex);
1868	progress_enabled = TRUE;
1869	pthread_mutex_unlock(&screen_mutex);
1870}
1871
1872
1873void disable_progress_bar()
1874{
1875	pthread_mutex_lock(&screen_mutex);
1876	progress_enabled = FALSE;
1877	pthread_mutex_unlock(&screen_mutex);
1878}
1879
1880
1881void update_progress_bar()
1882{
1883	pthread_mutex_lock(&screen_mutex);
1884	pthread_cond_signal(&progress_wait);
1885	pthread_mutex_unlock(&screen_mutex);
1886}
1887
1888
1889void progress_bar(long long current, long long max, int columns)
1890{
1891	char rotate_list[] = { '|', '/', '-', '\\' };
1892	int max_digits, used, hashes, spaces;
1893	static int tty = -1;
1894
1895	if(max == 0)
1896		return;
1897
1898	max_digits = floor(log10(max)) + 1;
1899	used = max_digits * 2 + 11;
1900	hashes = (current * (columns - used)) / max;
1901	spaces = columns - used - hashes;
1902
1903	if((current > max) || (columns - used < 0))
1904		return;
1905
1906	if(tty == -1)
1907		tty = isatty(STDOUT_FILENO);
1908	if(!tty) {
1909		static long long previous = -1;
1910
1911		/*
1912		 * Updating much more frequently than this results in huge
1913		 * log files.
1914		 */
1915		if((current % 100) != 0 && current != max)
1916			return;
1917		/* Don't update just to rotate the spinner. */
1918		if(current == previous)
1919			return;
1920		previous = current;
1921	}
1922
1923	printf("\r[");
1924
1925	while (hashes --)
1926		putchar('=');
1927
1928	putchar(rotate_list[rotate]);
1929
1930	while(spaces --)
1931		putchar(' ');
1932
1933	printf("] %*lld/%*lld", max_digits, current, max_digits, max);
1934	printf(" %3lld%%", current * 100 / max);
1935	fflush(stdout);
1936}
1937
1938
1939#define VERSION() \
1940	printf("unsquashfs version 4.2 (2011/02/28)\n");\
1941	printf("copyright (C) 2011 Phillip Lougher "\
1942		"<phillip@lougher.demon.co.uk>\n\n");\
1943    	printf("This program is free software; you can redistribute it and/or"\
1944		"\n");\
1945	printf("modify it under the terms of the GNU General Public License"\
1946		"\n");\
1947	printf("as published by the Free Software Foundation; either version "\
1948		"2,\n");\
1949	printf("or (at your option) any later version.\n\n");\
1950	printf("This program is distributed in the hope that it will be "\
1951		"useful,\n");\
1952	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of"\
1953		"\n");\
1954	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the"\
1955		"\n");\
1956	printf("GNU General Public License for more details.\n");
1957int main(int argc, char *argv[])
1958{
1959	char *dest = "squashfs-root";
1960	int i, stat_sys = FALSE, version = FALSE;
1961	int n;
1962	struct pathnames *paths = NULL;
1963	struct pathname *path = NULL;
1964	int fragment_buffer_size = FRAGMENT_BUFFER_DEFAULT;
1965	int data_buffer_size = DATA_BUFFER_DEFAULT;
1966	char *b;
1967
1968	pthread_mutex_init(&screen_mutex, NULL);
1969	root_process = geteuid() == 0;
1970	if(root_process)
1971		umask(0);
1972
1973	for(i = 1; i < argc; i++) {
1974		if(*argv[i] != '-')
1975			break;
1976		if(strcmp(argv[i], "-version") == 0 ||
1977				strcmp(argv[i], "-v") == 0) {
1978			VERSION();
1979			version = TRUE;
1980		} else if(strcmp(argv[i], "-info") == 0 ||
1981				strcmp(argv[i], "-i") == 0)
1982			info = TRUE;
1983		else if(strcmp(argv[i], "-ls") == 0 ||
1984				strcmp(argv[i], "-l") == 0)
1985			lsonly = TRUE;
1986		else if(strcmp(argv[i], "-no-progress") == 0 ||
1987				strcmp(argv[i], "-n") == 0)
1988			progress = FALSE;
1989		else if(strcmp(argv[i], "-no-xattrs") == 0 ||
1990				strcmp(argv[i], "-no") == 0)
1991			no_xattrs = TRUE;
1992		else if(strcmp(argv[i], "-xattrs") == 0 ||
1993				strcmp(argv[i], "-x") == 0)
1994			no_xattrs = FALSE;
1995		else if(strcmp(argv[i], "-dest") == 0 ||
1996				strcmp(argv[i], "-d") == 0) {
1997			if(++i == argc) {
1998				fprintf(stderr, "%s: -dest missing filename\n",
1999					argv[0]);
2000				exit(1);
2001			}
2002			dest = argv[i];
2003		} else if(strcmp(argv[i], "-processors") == 0 ||
2004				strcmp(argv[i], "-p") == 0) {
2005			if((++i == argc) ||
2006					(processors = strtol(argv[i], &b, 10),
2007					*b != '\0')) {
2008				ERROR("%s: -processors missing or invalid "
2009					"processor number\n", argv[0]);
2010				exit(1);
2011			}
2012			if(processors < 1) {
2013				ERROR("%s: -processors should be 1 or larger\n",
2014					argv[0]);
2015				exit(1);
2016			}
2017		} else if(strcmp(argv[i], "-data-queue") == 0 ||
2018					 strcmp(argv[i], "-da") == 0) {
2019			if((++i == argc) ||
2020					(data_buffer_size = strtol(argv[i], &b,
2021					 10), *b != '\0')) {
2022				ERROR("%s: -data-queue missing or invalid "
2023					"queue size\n", argv[0]);
2024				exit(1);
2025			}
2026			if(data_buffer_size < 1) {
2027				ERROR("%s: -data-queue should be 1 Mbyte or "
2028					"larger\n", argv[0]);
2029				exit(1);
2030			}
2031		} else if(strcmp(argv[i], "-frag-queue") == 0 ||
2032					strcmp(argv[i], "-fr") == 0) {
2033			if((++i == argc) ||
2034					(fragment_buffer_size = strtol(argv[i],
2035					 &b, 10), *b != '\0')) {
2036				ERROR("%s: -frag-queue missing or invalid "
2037					"queue size\n", argv[0]);
2038				exit(1);
2039			}
2040			if(fragment_buffer_size < 1) {
2041				ERROR("%s: -frag-queue should be 1 Mbyte or "
2042					"larger\n", argv[0]);
2043				exit(1);
2044			}
2045		} else if(strcmp(argv[i], "-force") == 0 ||
2046				strcmp(argv[i], "-f") == 0)
2047			force = TRUE;
2048		else if(strcmp(argv[i], "-stat") == 0 ||
2049				strcmp(argv[i], "-s") == 0)
2050			stat_sys = TRUE;
2051		else if(strcmp(argv[i], "-lls") == 0 ||
2052				strcmp(argv[i], "-ll") == 0) {
2053			lsonly = TRUE;
2054			short_ls = FALSE;
2055		} else if(strcmp(argv[i], "-linfo") == 0 ||
2056				strcmp(argv[i], "-li") == 0) {
2057			info = TRUE;
2058			short_ls = FALSE;
2059		} else if(strcmp(argv[i], "-ef") == 0 ||
2060				strcmp(argv[i], "-e") == 0) {
2061			if(++i == argc) {
2062				fprintf(stderr, "%s: -ef missing filename\n",
2063					argv[0]);
2064				exit(1);
2065			}
2066			path = process_extract_files(path, argv[i]);
2067		} else if(strcmp(argv[i], "-regex") == 0 ||
2068				strcmp(argv[i], "-r") == 0)
2069			use_regex = TRUE;
2070		else
2071			goto options;
2072	}
2073
2074	if(lsonly || info)
2075		progress = FALSE;
2076
2077#ifdef SQUASHFS_TRACE
2078	progress = FALSE;
2079#endif
2080
2081	if(i == argc) {
2082		if(!version) {
2083options:
2084			ERROR("SYNTAX: %s [options] filesystem [directories or "
2085				"files to extract]\n", argv[0]);
2086			ERROR("\t-v[ersion]\t\tprint version, licence and "
2087				"copyright information\n");
2088			ERROR("\t-d[est] <pathname>\tunsquash to <pathname>, "
2089				"default \"squashfs-root\"\n");
2090			ERROR("\t-n[o-progress]\t\tdon't display the progress "
2091				"bar\n");
2092			ERROR("\t-no[-xattrs]\t\tdon't extract xattrs in file system"
2093				NOXOPT_STR"\n");
2094			ERROR("\t-x[attrs]\t\textract xattrs in file system"
2095				XOPT_STR "\n");
2096			ERROR("\t-p[rocessors] <number>\tuse <number> "
2097				"processors.  By default will use\n");
2098			ERROR("\t\t\t\tnumber of processors available\n");
2099			ERROR("\t-i[nfo]\t\t\tprint files as they are "
2100				"unsquashed\n");
2101			ERROR("\t-li[nfo]\t\tprint files as they are "
2102				"unsquashed with file\n");
2103			ERROR("\t\t\t\tattributes (like ls -l output)\n");
2104			ERROR("\t-l[s]\t\t\tlist filesystem, but don't unsquash"
2105				"\n");
2106			ERROR("\t-ll[s]\t\t\tlist filesystem with file "
2107				"attributes (like\n");
2108			ERROR("\t\t\t\tls -l output), but don't unsquash\n");
2109			ERROR("\t-f[orce]\t\tif file already exists then "
2110				"overwrite\n");
2111			ERROR("\t-s[tat]\t\t\tdisplay filesystem superblock "
2112				"information\n");
2113			ERROR("\t-e[f] <extract file>\tlist of directories or "
2114				"files to extract.\n\t\t\t\tOne per line\n");
2115			ERROR("\t-da[ta-queue] <size>\tSet data queue to "
2116				"<size> Mbytes.  Default %d\n\t\t\t\tMbytes\n",
2117				DATA_BUFFER_DEFAULT);
2118			ERROR("\t-fr[ag-queue] <size>\tSet fragment queue to "
2119				"<size> Mbytes.  Default\n\t\t\t\t%d Mbytes\n",
2120				FRAGMENT_BUFFER_DEFAULT);
2121			ERROR("\t-r[egex]\t\ttreat extract names as POSIX "
2122				"regular expressions\n");
2123			ERROR("\t\t\t\trather than use the default shell "
2124				"wildcard\n\t\t\t\texpansion (globbing)\n");
2125			ERROR("\nDecompressors available:\n");
2126			display_compressors("", "");
2127		}
2128		exit(1);
2129	}
2130
2131	for(n = i + 1; n < argc; n++)
2132		path = add_path(path, argv[n], argv[n]);
2133
2134	if((fd = open(argv[i], O_RDONLY)) == -1) {
2135		ERROR("Could not open %s, because %s\n", argv[i],
2136			strerror(errno));
2137		exit(1);
2138	}
2139
2140	if(read_super(argv[i]) == FALSE)
2141		exit(1);
2142
2143	if(stat_sys) {
2144		squashfs_stat(argv[i]);
2145		exit(0);
2146	}
2147
2148	if(!comp->supported) {
2149		ERROR("Filesystem uses %s compression, this is "
2150			"unsupported by this version\n", comp->name);
2151		ERROR("Decompressors available:\n");
2152		display_compressors("", "");
2153		exit(1);
2154	}
2155
2156	block_size = sBlk.s.block_size;
2157	block_log = sBlk.s.block_log;
2158
2159	fragment_buffer_size <<= 20 - block_log;
2160	data_buffer_size <<= 20 - block_log;
2161	initialise_threads(fragment_buffer_size, data_buffer_size);
2162
2163	fragment_data = malloc(block_size);
2164	if(fragment_data == NULL)
2165		EXIT_UNSQUASH("failed to allocate fragment_data\n");
2166
2167	file_data = malloc(block_size);
2168	if(file_data == NULL)
2169		EXIT_UNSQUASH("failed to allocate file_data");
2170
2171	data = malloc(block_size);
2172	if(data == NULL)
2173		EXIT_UNSQUASH("failed to allocate data\n");
2174
2175	created_inode = malloc(sBlk.s.inodes * sizeof(char *));
2176	if(created_inode == NULL)
2177		EXIT_UNSQUASH("failed to allocate created_inode\n");
2178
2179	memset(created_inode, 0, sBlk.s.inodes * sizeof(char *));
2180
2181	if(s_ops.read_uids_guids() == FALSE)
2182		EXIT_UNSQUASH("failed to uid/gid table\n");
2183
2184	if(s_ops.read_fragment_table() == FALSE)
2185		EXIT_UNSQUASH("failed to read fragment table\n");
2186
2187	uncompress_inode_table(sBlk.s.inode_table_start,
2188		sBlk.s.directory_table_start);
2189
2190	uncompress_directory_table(sBlk.s.directory_table_start,
2191		sBlk.s.fragment_table_start);
2192
2193	if(no_xattrs)
2194		sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK;
2195
2196	if(read_xattrs_from_disk(fd, &sBlk.s) == 0)
2197		EXIT_UNSQUASH("failed to read the xattr table\n");
2198
2199	if(path) {
2200		paths = init_subdir();
2201		paths = add_subdir(paths, path);
2202	}
2203
2204	pre_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode),
2205		SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths);
2206
2207	memset(created_inode, 0, sBlk.s.inodes * sizeof(char *));
2208	inode_number = 1;
2209
2210	printf("%d inodes (%d blocks) to write\n\n", total_inodes,
2211		total_inodes - total_files + total_blocks);
2212
2213	if(progress)
2214		enable_progress_bar();
2215
2216	dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode),
2217		SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths);
2218
2219	queue_put(to_writer, NULL);
2220	queue_get(from_writer);
2221
2222	if(progress) {
2223		disable_progress_bar();
2224		progress_bar(sym_count + dev_count + fifo_count + cur_blocks,
2225			total_inodes - total_files + total_blocks, columns);
2226	}
2227
2228	if(!lsonly) {
2229		printf("\n");
2230		printf("created %d files\n", file_count);
2231		printf("created %d directories\n", dir_count);
2232		printf("created %d symlinks\n", sym_count);
2233		printf("created %d devices\n", dev_count);
2234		printf("created %d fifos\n", fifo_count);
2235	}
2236
2237	return 0;
2238}
2239