unsquashfs.c revision 0ca44ca7b28597911258e0c27bd82feef73f2256
12f60990fb0352f7a30e0281a066458dbf033618bplougher/*
2e3206fad5b70e7e0527db2a627ad26616a8a2429plougher * Unsquash a squashfs filesystem.  This is a highly compressed read only
3e3206fad5b70e7e0527db2a627ad26616a8a2429plougher * filesystem.
4443c15812032991c98b33b5424b17bcd55fe3575plougher *
50ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
60ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher * 2012
779df93becb68081effabebba3006c794be308598plougher * Phillip Lougher <phillip@lougher.demon.co.uk>
8443c15812032991c98b33b5424b17bcd55fe3575plougher *
9443c15812032991c98b33b5424b17bcd55fe3575plougher * This program is free software; you can redistribute it and/or
10443c15812032991c98b33b5424b17bcd55fe3575plougher * modify it under the terms of the GNU General Public License
11443c15812032991c98b33b5424b17bcd55fe3575plougher * as published by the Free Software Foundation; either version 2,
12443c15812032991c98b33b5424b17bcd55fe3575plougher * or (at your option) any later version.
13443c15812032991c98b33b5424b17bcd55fe3575plougher *
14443c15812032991c98b33b5424b17bcd55fe3575plougher * This program is distributed in the hope that it will be useful,
15443c15812032991c98b33b5424b17bcd55fe3575plougher * but WITHOUT ANY WARRANTY; without even the implied warranty of
16443c15812032991c98b33b5424b17bcd55fe3575plougher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17443c15812032991c98b33b5424b17bcd55fe3575plougher * GNU General Public License for more details.
18443c15812032991c98b33b5424b17bcd55fe3575plougher *
19443c15812032991c98b33b5424b17bcd55fe3575plougher * You should have received a copy of the GNU General Public License
20443c15812032991c98b33b5424b17bcd55fe3575plougher * along with this program; if not, write to the Free Software
21443c15812032991c98b33b5424b17bcd55fe3575plougher * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22443c15812032991c98b33b5424b17bcd55fe3575plougher *
23ed5124f016834932db2c63d60d259d846171c216plougher * unsquashfs.c
24443c15812032991c98b33b5424b17bcd55fe3575plougher */
25443c15812032991c98b33b5424b17bcd55fe3575plougher
26ed5124f016834932db2c63d60d259d846171c216plougher#include "unsquashfs.h"
276490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "squashfs_swap.h"
286490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "squashfs_compat.h"
296490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "read_fs.h"
30efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher#include "compressor.h"
312ef25cb004cc6995bd36f781863aa844fe8c358dplougher#include "xattr.h"
328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
33cdebd2b8ae4b1ac39eefb5f0c556f0d2e3dc3d24plougher#include <sys/sysinfo.h>
342ef25cb004cc6995bd36f781863aa844fe8c358dplougher#include <sys/types.h>
35cdebd2b8ae4b1ac39eefb5f0c556f0d2e3dc3d24plougher
368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *fragment_cache, *data_cache;
378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *to_reader, *to_deflate, *to_writer, *from_writer;
388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherpthread_t *thread, *deflator_thread;
398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherpthread_mutex_t	fragment_mutex;
408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* user options that control parallelisation */
428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherint processors = -1;
438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
446490378e5b5e8dc058daf28423a7465699a6ba7bplougherstruct super_block sBlk;
4502bc3bcabf2b219f63961f07293b83629948f026ploughersquashfs_operations s_ops;
46efda88fd6fbb19543a86b5f8d15b437bba8c4674plougherstruct compressor *comp;
4702bc3bcabf2b219f63961f07293b83629948f026plougher
489dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0,
499dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	dev_count = 0, fifo_count = 0;
50443c15812032991c98b33b5424b17bcd55fe3575plougherchar *inode_table = NULL, *directory_table = NULL;
51443c15812032991c98b33b5424b17bcd55fe3575plougherstruct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536];
52443c15812032991c98b33b5424b17bcd55fe3575plougherint fd;
53443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int *uid_table, *guid_table;
54443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int cached_frag = SQUASHFS_INVALID_FRAG;
55443c15812032991c98b33b5424b17bcd55fe3575plougherchar *fragment_data;
56443c15812032991c98b33b5424b17bcd55fe3575plougherchar *file_data;
57443c15812032991c98b33b5424b17bcd55fe3575plougherchar *data;
58443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int block_size;
59ae271cc93e3684d5314bcdc45b631e497ae43166plougherunsigned int block_log;
60d4204758f77acb5a371fa1487a755b76a05d5476plougherint lsonly = FALSE, info = FALSE, force = FALSE, short_ls = TRUE;
61d4204758f77acb5a371fa1487a755b76a05d5476plougherint use_regex = FALSE;
62443c15812032991c98b33b5424b17bcd55fe3575plougherchar **created_inode;
639dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint root_process;
64eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint columns;
65eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint rotate = 0;
661b42101056befe25b5f19d5b099e806a2ecee9cdplougherpthread_mutex_t	screen_mutex;
67eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherpthread_cond_t progress_wait;
681b42101056befe25b5f19d5b099e806a2ecee9cdplougherint progress = TRUE, progress_enabled = FALSE;
69eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int total_blocks = 0, total_files = 0, total_inodes = 0;
70eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int cur_blocks = 0;
71ed5124f016834932db2c63d60d259d846171c216plougherint inode_number = 1;
72df9d38a515489c2c573754ad81abd230dfd8b1f0plougherint no_xattrs = XATTR_DEF;
73443c15812032991c98b33b5424b17bcd55fe3575plougher
74476dcb48b24efff22caa970f000e151f1b28918dplougherint lookup_type[] = {
75476dcb48b24efff22caa970f000e151f1b28918dplougher	0,
76476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
77476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFREG,
78476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFLNK,
79476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFBLK,
80476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFCHR,
81476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFIFO,
82476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFSOCK,
83476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
84eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFREG,
85eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFLNK,
86eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFBLK,
87eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFCHR,
88eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFIFO,
89eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFSOCK
90476dcb48b24efff22caa970f000e151f1b28918dplougher};
91476dcb48b24efff22caa970f000e151f1b28918dplougher
92476dcb48b24efff22caa970f000e151f1b28918dplougherstruct test table[] = {
93476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFSOCK, 0, 's' },
94476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFLNK, 0, 'l' },
95476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFBLK, 0, 'b' },
96476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFDIR, 0, 'd' },
97476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFCHR, 0, 'c' },
98476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFIFO, 0, 'p' },
99476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRUSR, S_IRUSR, 1, 'r' },
100476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWUSR, S_IWUSR, 2, 'w' },
101476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRGRP, S_IRGRP, 4, 'r' },
102476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWGRP, S_IWGRP, 5, 'w' },
103476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IROTH, S_IROTH, 7, 'r' },
104476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWOTH, S_IWOTH, 8, 'w' },
105476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR | S_ISUID, 3, 's' },
106476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_ISUID, 3, 'S' },
107476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR, 3, 'x' },
108476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP | S_ISGID, 6, 's' },
109476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_ISGID, 6, 'S' },
110476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP, 6, 'x' },
111476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH | S_ISVTX, 9, 't' },
112476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_ISVTX, 9, 'T' },
113476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH, 9, 'x' },
1148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	{ 0, 0, 0, 0}
1158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher};
1168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
117eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns);
118eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar();
119eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
120eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid sigwinch_handler()
121eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
122eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct winsize winsize;
123eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
124eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
125c27a3d72b339d80d38623a4ee5a42601338fb4c9plougher		if(isatty(STDOUT_FILENO))
126d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
127d4204758f77acb5a371fa1487a755b76a05d5476plougher				"columns\n");
128eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = 80;
129eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	} else
130eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = winsize.ws_col;
131eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
132eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1341b5f6c5145f284683a2628b73ab5f8a0e37dd7b4ploughervoid sigalrm_handler()
1351b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher{
1361b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	rotate = (rotate + 1) % 4;
1371b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher}
1381b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
1391b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
1408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *queue_init(int size)
1418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct queue *queue = malloc(sizeof(struct queue));
1438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(queue == NULL)
14562b2d7649ad84234afd928a43f9a2c1612eef361plougher		EXIT_UNSQUASH("Out of memory in queue_init\n");
1468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1477b53be8c83b949517c343d9c6d88243578753c3aplougher	queue->data = malloc(sizeof(void *) * (size + 1));
1487b53be8c83b949517c343d9c6d88243578753c3aplougher	if(queue->data == NULL)
1490e0cc6f6dccdc5460c292b0a5accc1184a07f3f5plougher		EXIT_UNSQUASH("Out of memory in queue_init\n");
1508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->size = size + 1;
1528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = queue->writep = 0;
1538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&queue->mutex, NULL);
1548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->empty, NULL);
1558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->full, NULL);
1568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return queue;
1588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1618888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid queue_put(struct queue *queue, void *data)
1628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int nextp;
1648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
1668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
1688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->full, &queue->mutex);
1698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->data[queue->writep] = data;
1718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->writep = nextp;
1728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->empty);
1738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
1748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1778888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *queue_get(struct queue *queue)
1788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	void *data;
1808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
1818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(queue->readp == queue->writep)
1838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->empty, &queue->mutex);
1848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data = queue->data[queue->readp];
1868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = (queue->readp + 1) % queue->size;
1878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->full);
1888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
1898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return data;
1918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
1958888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_hash_table(struct cache *cache, struct cache_entry *entry)
1968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(entry->block);
1988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_next = cache->hash_table[hash];
2008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->hash_table[hash] = entry;
2018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = NULL;
2028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
2038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry;
2048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2088888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_hash_table(struct cache *cache, struct cache_entry *entry)
2098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_prev)
2118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_prev->hash_next = entry->hash_next;
2128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	else
213c435240f52b78b0ef498118727ba8dad186db26bplougher		cache->hash_table[CALCULATE_HASH(entry->block)] =
214c435240f52b78b0ef498118727ba8dad186db26bplougher			entry->hash_next;
2158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
2168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry->hash_prev;
2178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = entry->hash_next = NULL;
2198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2238888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_free_list(struct cache *cache, struct cache_entry *entry)
2248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache->free_list) {
2268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next = cache->free_list;
2278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = cache->free_list->free_prev;
2288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev->free_next = entry;
2298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev = entry;
2308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
2318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = entry;
2328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = entry->free_next = entry;
2338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
2348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2388888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_free_list(struct cache *cache, struct cache_entry *entry)
2398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->free_prev == NULL && entry->free_next == NULL)
2418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* not in free list */
2428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return;
243222e49e257bccb10c0e608f071778f26fce28f01plougher	else if(entry->free_prev == entry && entry->free_next == entry) {
2448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* only this entry in the free list */
2458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = NULL;
2468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
2478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* more than one entry in the free list */
2488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next->free_prev = entry->free_prev;
2498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev->free_next = entry->free_next;
2508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->free_list == entry)
2518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->free_list = entry->free_next;
2528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
2538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->free_prev = entry->free_next = NULL;
2558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *cache_init(int buffer_size, int max_buffers)
2598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache *cache = malloc(sizeof(struct cache));
2618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache == NULL)
263360570574b8f7786728d91d5fe4a0a4aa291fa03plougher		EXIT_UNSQUASH("Out of memory in cache_init\n");
2648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->max_buffers = max_buffers;
2668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->buffer_size = buffer_size;
2678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->count = 0;
2688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->free_list = NULL;
2698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536);
2708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_free = FALSE;
2718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_pending = FALSE;
2728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&cache->mutex, NULL);
2738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_free, NULL);
2748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_pending, NULL);
2758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return cache;
2778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache_entry *cache_get(struct cache *cache, long long block, int size)
2818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
282d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
283d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * Get a block out of the cache.  If the block isn't in the cache
284d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * it is added and queued to the reader() and deflate() threads for
285c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * reading off disk and decompression.  The cache grows until max_blocks
286c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * is reached, once this occurs existing discarded blocks on the free
287c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * list are reused
288d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
2898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(block);
2908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *entry;
2918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&cache->mutex);
2938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
2958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->block == block)
2968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			break;
2978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry) {
299d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
3000a0d045642e8e413f90b770539193d3fd1522786plougher 		 * found the block in the cache, increment used count and
3018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * if necessary remove from free list so it won't disappear
3028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
3038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used ++;
3048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		remove_free_list(cache, entry);
3058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
3068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
307d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
308d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 * not in the cache
309d4204758f77acb5a371fa1487a755b76a05d5476plougher		 *
310d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * first try to allocate new block
311d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
3128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->count < cache->max_buffers) {
3138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = malloc(sizeof(struct cache_entry));
3148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(entry == NULL)
3157227416360c2f249a0783dffef6725ad03b61c99plougher				EXIT_UNSQUASH("Out of memory in cache_get\n");
3168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data = malloc(cache->buffer_size);
3177227416360c2f249a0783dffef6725ad03b61c99plougher			if(entry->data == NULL)
3187227416360c2f249a0783dffef6725ad03b61c99plougher				EXIT_UNSQUASH("Out of memory in cache_get\n");
3198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache = cache;
3208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->free_prev = entry->free_next = NULL;
3218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->count ++;
3228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		} else {
323d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
324d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * try to get from free list
325d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
3268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			while(cache->free_list == NULL) {
3278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				cache->wait_free = TRUE;
328d4204758f77acb5a371fa1487a755b76a05d5476plougher				pthread_cond_wait(&cache->wait_for_free,
329d4204758f77acb5a371fa1487a755b76a05d5476plougher					&cache->mutex);
3308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
3318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = cache->free_list;
3328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_free_list(cache, entry);
3338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_hash_table(cache, entry);
3348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
3358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
336d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
337d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * initialise block and insert into the hash table
338d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
3398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->block = block;
3408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->size = size;
3418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used = 1;
3428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->error = FALSE;
3438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->pending = TRUE;
3448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_hash_table(cache, entry);
3458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
346d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
347c435240f52b78b0ef498118727ba8dad186db26bplougher		 * queue to read thread to read and ultimately (via the
348c435240f52b78b0ef498118727ba8dad186db26bplougher		 * decompress threads) decompress the buffer
3498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
3508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
3518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_reader, entry);
3528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return entry;
3558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3588888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_ready(struct cache_entry *entry, int error)
3598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
360d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
361d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * mark cache entry as being complete, reading and (if necessary)
3628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * decompression has taken place, and the buffer is valid for use.
3638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * If an error occurs reading or decompressing, the buffer also
364d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * becomes ready but with an error...
365d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
3668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
3678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->pending = FALSE;
3688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->error = error;
3698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
370d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
371c435240f52b78b0ef498118727ba8dad186db26bplougher	 * if the wait_pending flag is set, one or more threads may be waiting
372c435240f52b78b0ef498118727ba8dad186db26bplougher	 * on this buffer
373d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
3748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->cache->wait_pending) {
3758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = FALSE;
3768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_broadcast(&entry->cache->wait_for_pending);
3778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
3808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3838888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_wait(struct cache_entry *entry)
3848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
385d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
386d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * wait for this cache entry to become ready, when reading and (if
387d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * necessary) decompression has taken place
388d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
3898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
3908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(entry->pending) {
3928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = TRUE;
393d4204758f77acb5a371fa1487a755b76a05d5476plougher		pthread_cond_wait(&entry->cache->wait_for_pending,
394d4204758f77acb5a371fa1487a755b76a05d5476plougher			&entry->cache->mutex);
3958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
3988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4018888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_put(struct cache_entry *entry)
4028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
403d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
404d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * finished with this cache entry, once the usage count reaches zero it
405c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * can be reused and is put onto the free list.  As it remains
406c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * accessible via the hash table it can be found getting a new lease of
407c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * life before it is reused.
408d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
4098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
4108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->used --;
4128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->used == 0) {
4138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_free_list(entry->cache, entry);
4148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
415d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
416c435240f52b78b0ef498118727ba8dad186db26bplougher		 * if the wait_free flag is set, one or more threads may be
417c435240f52b78b0ef498118727ba8dad186db26bplougher		 * waiting on this buffer
418d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
4198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->cache->wait_free) {
4208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache->wait_free = FALSE;
4218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			pthread_cond_broadcast(&entry->cache->wait_for_free);
4228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
4238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
4248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
4268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
427476dcb48b24efff22caa970f000e151f1b28918dplougher
428476dcb48b24efff22caa970f000e151f1b28918dplougher
429476dcb48b24efff22caa970f000e151f1b28918dplougherchar *modestr(char *str, int mode)
430476dcb48b24efff22caa970f000e151f1b28918dplougher{
431476dcb48b24efff22caa970f000e151f1b28918dplougher	int i;
432476dcb48b24efff22caa970f000e151f1b28918dplougher
433476dcb48b24efff22caa970f000e151f1b28918dplougher	strcpy(str, "----------");
434476dcb48b24efff22caa970f000e151f1b28918dplougher
435476dcb48b24efff22caa970f000e151f1b28918dplougher	for(i = 0; table[i].mask != 0; i++) {
436476dcb48b24efff22caa970f000e151f1b28918dplougher		if((mode & table[i].mask) == table[i].value)
437476dcb48b24efff22caa970f000e151f1b28918dplougher			str[table[i].position] = table[i].mode;
438476dcb48b24efff22caa970f000e151f1b28918dplougher	}
439476dcb48b24efff22caa970f000e151f1b28918dplougher
440476dcb48b24efff22caa970f000e151f1b28918dplougher	return str;
441476dcb48b24efff22caa970f000e151f1b28918dplougher}
442476dcb48b24efff22caa970f000e151f1b28918dplougher
443476dcb48b24efff22caa970f000e151f1b28918dplougher
4443edfa57b6a463f7d441d995559143f4861d62e98plougher#define TOTALCHARS  25
4456f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint print_filename(char *pathname, struct inode *inode)
446476dcb48b24efff22caa970f000e151f1b28918dplougher{
4476f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	char str[11], dummy[100], dummy2[100], *userstr, *groupstr;
4486f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int padchars;
449476dcb48b24efff22caa970f000e151f1b28918dplougher	struct passwd *user;
450476dcb48b24efff22caa970f000e151f1b28918dplougher	struct group *group;
45188facddfd83e48a907b82210ddccbb4f84d80aecplougher	struct tm *t;
452476dcb48b24efff22caa970f000e151f1b28918dplougher
453476dcb48b24efff22caa970f000e151f1b28918dplougher	if(short_ls) {
454476dcb48b24efff22caa970f000e151f1b28918dplougher		printf("%s\n", pathname);
455476dcb48b24efff22caa970f000e151f1b28918dplougher		return 1;
456476dcb48b24efff22caa970f000e151f1b28918dplougher	}
457476dcb48b24efff22caa970f000e151f1b28918dplougher
458266b83c3b162a6764407753909712fcaade951f2plougher	user = getpwuid(inode->uid);
459266b83c3b162a6764407753909712fcaade951f2plougher	if(user == NULL) {
4606f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		sprintf(dummy, "%d", inode->uid);
4613edfa57b6a463f7d441d995559143f4861d62e98plougher		userstr = dummy;
4623edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
4633edfa57b6a463f7d441d995559143f4861d62e98plougher		userstr = user->pw_name;
4643edfa57b6a463f7d441d995559143f4861d62e98plougher
465266b83c3b162a6764407753909712fcaade951f2plougher	group = getgrgid(inode->gid);
466266b83c3b162a6764407753909712fcaade951f2plougher	if(group == NULL) {
4676f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		sprintf(dummy2, "%d", inode->gid);
4683edfa57b6a463f7d441d995559143f4861d62e98plougher		groupstr = dummy2;
4693edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
4703edfa57b6a463f7d441d995559143f4861d62e98plougher		groupstr = group->gr_name;
4713edfa57b6a463f7d441d995559143f4861d62e98plougher
4726f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	printf("%s %s/%s ", modestr(str, inode->mode), userstr, groupstr);
4733edfa57b6a463f7d441d995559143f4861d62e98plougher
4746f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(inode->mode & S_IFMT) {
4753edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFREG:
4763edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFDIR:
4773edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFSOCK:
4783edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFIFO:
4793edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFLNK:
480c435240f52b78b0ef498118727ba8dad186db26bplougher			padchars = TOTALCHARS - strlen(userstr) -
481c435240f52b78b0ef498118727ba8dad186db26bplougher				strlen(groupstr);
4823edfa57b6a463f7d441d995559143f4861d62e98plougher
483c435240f52b78b0ef498118727ba8dad186db26bplougher			printf("%*lld ", padchars > 0 ? padchars : 0,
484c435240f52b78b0ef498118727ba8dad186db26bplougher				inode->data);
4853edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
4863edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFCHR:
4873edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFBLK:
488c435240f52b78b0ef498118727ba8dad186db26bplougher			padchars = TOTALCHARS - strlen(userstr) -
489c435240f52b78b0ef498118727ba8dad186db26bplougher				strlen(groupstr) - 7;
4903edfa57b6a463f7d441d995559143f4861d62e98plougher
491d4204758f77acb5a371fa1487a755b76a05d5476plougher			printf("%*s%3d,%3d ", padchars > 0 ? padchars : 0, " ",
492c435240f52b78b0ef498118727ba8dad186db26bplougher				(int) inode->data >> 8, (int) inode->data &
493c435240f52b78b0ef498118727ba8dad186db26bplougher				0xff);
4943edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
4953edfa57b6a463f7d441d995559143f4861d62e98plougher	}
496476dcb48b24efff22caa970f000e151f1b28918dplougher
4976f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	t = localtime(&inode->time);
49888facddfd83e48a907b82210ddccbb4f84d80aecplougher
499d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("%d-%02d-%02d %02d:%02d %s", t->tm_year + 1900, t->tm_mon + 1,
500d4204758f77acb5a371fa1487a755b76a05d5476plougher		t->tm_mday, t->tm_hour, t->tm_min, pathname);
5016f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((inode->mode & S_IFMT) == S_IFLNK)
5026f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		printf(" -> %s", inode->symlink);
5033edfa57b6a463f7d441d995559143f4861d62e98plougher	printf("\n");
5043edfa57b6a463f7d441d995559143f4861d62e98plougher
505476dcb48b24efff22caa970f000e151f1b28918dplougher	return 1;
506476dcb48b24efff22caa970f000e151f1b28918dplougher}
507476dcb48b24efff22caa970f000e151f1b28918dplougher
508443c15812032991c98b33b5424b17bcd55fe3575plougher
509e3206fad5b70e7e0527db2a627ad26616a8a2429ploughervoid add_entry(struct hash_table_entry *hash_table[], long long start,
510e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	int bytes)
511443c15812032991c98b33b5424b17bcd55fe3575plougher{
512443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
513443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
514443c15812032991c98b33b5424b17bcd55fe3575plougher
515cb2cff9a58d8d92fc6edb95049469188ee49c6c9plougher	hash_table_entry = malloc(sizeof(struct hash_table_entry));
516cb2cff9a58d8d92fc6edb95049469188ee49c6c9plougher	if(hash_table_entry == NULL)
5174a39fa82d4614c18d2977be7898d78d20ba01a49plougher		EXIT_UNSQUASH("Out of memory in add_entry\n");
518443c15812032991c98b33b5424b17bcd55fe3575plougher
519443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->start = start;
520443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->bytes = bytes;
521443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->next = hash_table[hash];
522443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table[hash] = hash_table_entry;
523443c15812032991c98b33b5424b17bcd55fe3575plougher}
524443c15812032991c98b33b5424b17bcd55fe3575plougher
525443c15812032991c98b33b5424b17bcd55fe3575plougher
526f404f4914fdb272a70e18664e8963d793cc90f44plougherint lookup_entry(struct hash_table_entry *hash_table[], long long start)
527443c15812032991c98b33b5424b17bcd55fe3575plougher{
528443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
529443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
530443c15812032991c98b33b5424b17bcd55fe3575plougher
5319dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	for(hash_table_entry = hash_table[hash]; hash_table_entry;
5329dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				hash_table_entry = hash_table_entry->next)
5337a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher
534443c15812032991c98b33b5424b17bcd55fe3575plougher		if(hash_table_entry->start == start)
535443c15812032991c98b33b5424b17bcd55fe3575plougher			return hash_table_entry->bytes;
536443c15812032991c98b33b5424b17bcd55fe3575plougher
537443c15812032991c98b33b5424b17bcd55fe3575plougher	return -1;
538443c15812032991c98b33b5424b17bcd55fe3575plougher}
539443c15812032991c98b33b5424b17bcd55fe3575plougher
540443c15812032991c98b33b5424b17bcd55fe3575plougher
5413306cb2b54a60a32664617118336ac141e1471b6plougherint read_fs_bytes(int fd, long long byte, int bytes, void *buff)
542443c15812032991c98b33b5424b17bcd55fe3575plougher{
543443c15812032991c98b33b5424b17bcd55fe3575plougher	off_t off = byte;
544d7f3de3408089ce187d8bc26f6072730c77628daplougher	int res, count;
545443c15812032991c98b33b5424b17bcd55fe3575plougher
546c435240f52b78b0ef498118727ba8dad186db26bplougher	TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte,
547c435240f52b78b0ef498118727ba8dad186db26bplougher		bytes);
548fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
549443c15812032991c98b33b5424b17bcd55fe3575plougher	if(lseek(fd, off, SEEK_SET) == -1) {
5505d415c6659faaa7a69c9baa7175610d889747142plougher		ERROR("Lseek failed because %s\n", strerror(errno));
551443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
552443c15812032991c98b33b5424b17bcd55fe3575plougher	}
553443c15812032991c98b33b5424b17bcd55fe3575plougher
554d7f3de3408089ce187d8bc26f6072730c77628daplougher	for(count = 0; count < bytes; count += res) {
555d7f3de3408089ce187d8bc26f6072730c77628daplougher		res = read(fd, buff + count, bytes - count);
556d7f3de3408089ce187d8bc26f6072730c77628daplougher		if(res < 1) {
557d7f3de3408089ce187d8bc26f6072730c77628daplougher			if(res == 0) {
558e3206fad5b70e7e0527db2a627ad26616a8a2429plougher				ERROR("Read on filesystem failed because "
559e3206fad5b70e7e0527db2a627ad26616a8a2429plougher					"EOF\n");
560d7f3de3408089ce187d8bc26f6072730c77628daplougher				return FALSE;
561d7f3de3408089ce187d8bc26f6072730c77628daplougher			} else if(errno != EINTR) {
562d7f3de3408089ce187d8bc26f6072730c77628daplougher				ERROR("Read on filesystem failed because %s\n",
563d7f3de3408089ce187d8bc26f6072730c77628daplougher						strerror(errno));
564d7f3de3408089ce187d8bc26f6072730c77628daplougher				return FALSE;
565d7f3de3408089ce187d8bc26f6072730c77628daplougher			} else
566d7f3de3408089ce187d8bc26f6072730c77628daplougher				res = 0;
567d7f3de3408089ce187d8bc26f6072730c77628daplougher		}
568443c15812032991c98b33b5424b17bcd55fe3575plougher	}
569443c15812032991c98b33b5424b17bcd55fe3575plougher
570443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
571443c15812032991c98b33b5424b17bcd55fe3575plougher}
572443c15812032991c98b33b5424b17bcd55fe3575plougher
573443c15812032991c98b33b5424b17bcd55fe3575plougher
574923b301e304637fd5e587eb05a6f44558abae2bdplougherint read_block(int fd, long long start, long long *next, void *block)
575443c15812032991c98b33b5424b17bcd55fe3575plougher{
576443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned short c_byte;
577443c15812032991c98b33b5424b17bcd55fe3575plougher	int offset = 2;
578443c15812032991c98b33b5424b17bcd55fe3575plougher
579443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
580923b301e304637fd5e587eb05a6f44558abae2bdplougher		if(read_fs_bytes(fd, start, 2, &c_byte) == FALSE)
581fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
582923b301e304637fd5e587eb05a6f44558abae2bdplougher		c_byte = (c_byte >> 8) | ((c_byte & 0xff) << 8);
583443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
5843306cb2b54a60a32664617118336ac141e1471b6plougher		if(read_fs_bytes(fd, start, 2, &c_byte) == FALSE)
585fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
586fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
587d4204758f77acb5a371fa1487a755b76a05d5476plougher	TRACE("read_block: block @0x%llx, %d %s bytes\n", start,
588d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ?
589d4204758f77acb5a371fa1487a755b76a05d5476plougher		"compressed" : "uncompressed");
590443c15812032991c98b33b5424b17bcd55fe3575plougher
59127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(SQUASHFS_CHECK_DATA(sBlk.s.flags))
592443c15812032991c98b33b5424b17bcd55fe3575plougher		offset = 3;
593443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED(c_byte)) {
594443c15812032991c98b33b5424b17bcd55fe3575plougher		char buffer[SQUASHFS_METADATA_SIZE];
595efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		int error, res;
596443c15812032991c98b33b5424b17bcd55fe3575plougher
597443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
59886561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		if(read_fs_bytes(fd, start + offset, c_byte, buffer) == FALSE)
599fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
600443c15812032991c98b33b5424b17bcd55fe3575plougher
601b48442b2e37b3cb7efbffb032968f115eec7963cplougher		res = compressor_uncompress(comp, block, buffer, c_byte,
602efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			SQUASHFS_METADATA_SIZE, &error);
603efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
604efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		if(res == -1) {
605efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			ERROR("%s uncompress failed with error code %d\n",
606efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher				comp->name, error);
607fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
608443c15812032991c98b33b5424b17bcd55fe3575plougher		}
609443c15812032991c98b33b5424b17bcd55fe3575plougher		if(next)
610443c15812032991c98b33b5424b17bcd55fe3575plougher			*next = start + offset + c_byte;
611efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		return res;
612443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
613443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
61486561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		if(read_fs_bytes(fd, start + offset, c_byte, block) == FALSE)
615fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
616443c15812032991c98b33b5424b17bcd55fe3575plougher		if(next)
617443c15812032991c98b33b5424b17bcd55fe3575plougher			*next = start + offset + c_byte;
618443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
619443c15812032991c98b33b5424b17bcd55fe3575plougher	}
620fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
621fe3ca0609d02d78bcd11637c1220b2ff428f466aplougherfailed:
62268ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher	ERROR("read_block: failed to read block @0x%llx\n", start);
623fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	return FALSE;
624443c15812032991c98b33b5424b17bcd55fe3575plougher}
625443c15812032991c98b33b5424b17bcd55fe3575plougher
626443c15812032991c98b33b5424b17bcd55fe3575plougher
627443c15812032991c98b33b5424b17bcd55fe3575plougherint read_data_block(long long start, unsigned int size, char *block)
628443c15812032991c98b33b5424b17bcd55fe3575plougher{
629efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	int error, res;
630443c15812032991c98b33b5424b17bcd55fe3575plougher	int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
631443c15812032991c98b33b5424b17bcd55fe3575plougher
632d4204758f77acb5a371fa1487a755b76a05d5476plougher	TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start,
633c6ab26edb0c0da6b276281960d9c8748a70886feplougher		c_byte, SQUASHFS_COMPRESSED_BLOCK(size) ? "compressed" :
634c435240f52b78b0ef498118727ba8dad186db26bplougher		"uncompressed");
635fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
636443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED_BLOCK(size)) {
63786561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		if(read_fs_bytes(fd, start, c_byte, data) == FALSE)
63868ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
639443c15812032991c98b33b5424b17bcd55fe3575plougher
640b48442b2e37b3cb7efbffb032968f115eec7963cplougher		res = compressor_uncompress(comp, block, data, c_byte,
641b48442b2e37b3cb7efbffb032968f115eec7963cplougher			block_size, &error);
642efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
643efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		if(res == -1) {
644efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			ERROR("%s uncompress failed with error code %d\n",
645efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher				comp->name, error);
64668ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
647443c15812032991c98b33b5424b17bcd55fe3575plougher		}
648443c15812032991c98b33b5424b17bcd55fe3575plougher
649efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		return res;
650443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
65186561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		if(read_fs_bytes(fd, start, c_byte, block) == FALSE)
65268ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
653443c15812032991c98b33b5424b17bcd55fe3575plougher
654443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
655443c15812032991c98b33b5424b17bcd55fe3575plougher	}
65668ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher
65768ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougherfailed:
658d4204758f77acb5a371fa1487a755b76a05d5476plougher	ERROR("read_data_block: failed to read block @0x%llx, size %d\n", start,
659c6ab26edb0c0da6b276281960d9c8748a70886feplougher		c_byte);
66068ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher	return FALSE;
661443c15812032991c98b33b5424b17bcd55fe3575plougher}
662443c15812032991c98b33b5424b17bcd55fe3575plougher
663443c15812032991c98b33b5424b17bcd55fe3575plougher
66402bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_inode_table(long long start, long long end)
665443c15812032991c98b33b5424b17bcd55fe3575plougher{
666443c15812032991c98b33b5424b17bcd55fe3575plougher	int size = 0, bytes = 0, res;
667443c15812032991c98b33b5424b17bcd55fe3575plougher
66841da3230b2ac91a73f9190676f66b3d80b21c270plougher	TRACE("uncompress_inode_table: start %lld, end %lld\n", start, end);
669443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
670c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher		if(size - bytes < SQUASHFS_METADATA_SIZE) {
671c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher			inode_table = realloc(inode_table, size +=
672c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher				SQUASHFS_METADATA_SIZE);
673c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher			if(inode_table == NULL)
674c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher				EXIT_UNSQUASH("Out of memory in "
675c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher					"uncompress_inode_table");
676c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher		}
677443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("uncompress_inode_table: reading block 0x%llx\n", start);
678443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(inode_table_hash, start, bytes);
679176b325add10f6b9846f771f75d8543364d4c121plougher		res = read_block(fd, start, &start, inode_table + bytes);
680c435240f52b78b0ef498118727ba8dad186db26bplougher		if(res == 0) {
681443c15812032991c98b33b5424b17bcd55fe3575plougher			free(inode_table);
682d4204758f77acb5a371fa1487a755b76a05d5476plougher			EXIT_UNSQUASH("uncompress_inode_table: failed to read "
683d4204758f77acb5a371fa1487a755b76a05d5476plougher				"block \n");
684443c15812032991c98b33b5424b17bcd55fe3575plougher		}
685443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
686443c15812032991c98b33b5424b17bcd55fe3575plougher	}
687443c15812032991c98b33b5424b17bcd55fe3575plougher}
688443c15812032991c98b33b5424b17bcd55fe3575plougher
689443c15812032991c98b33b5424b17bcd55fe3575plougher
690d4204758f77acb5a371fa1487a755b76a05d5476plougherint set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time,
691fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher	unsigned int xattr, unsigned int set_mode)
692443c15812032991c98b33b5424b17bcd55fe3575plougher{
6936f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	struct utimbuf times = { time, time };
694443c15812032991c98b33b5424b17bcd55fe3575plougher
6952ef25cb004cc6995bd36f781863aa844fe8c358dplougher	write_xattr(pathname, xattr);
6962ef25cb004cc6995bd36f781863aa844fe8c358dplougher
697443c15812032991c98b33b5424b17bcd55fe3575plougher	if(utime(pathname, &times) == -1) {
698d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("set_attributes: failed to set time on %s, because %s\n",
699d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
700443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
701443c15812032991c98b33b5424b17bcd55fe3575plougher	}
702443c15812032991c98b33b5424b17bcd55fe3575plougher
7039dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if(root_process) {
7046f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(chown(pathname, uid, guid) == -1) {
705c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("set_attributes: failed to change uid and gids "
706c435240f52b78b0ef498118727ba8dad186db26bplougher				"on %s, because %s\n", pathname,
707c435240f52b78b0ef498118727ba8dad186db26bplougher				strerror(errno));
708443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
709443c15812032991c98b33b5424b17bcd55fe3575plougher		}
7109dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	} else
7119dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		mode &= ~07000;
7129dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
7139dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) {
714d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("set_attributes: failed to change mode %s, because %s\n",
715d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
7169dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		return FALSE;
717443c15812032991c98b33b5424b17bcd55fe3575plougher	}
718443c15812032991c98b33b5424b17bcd55fe3575plougher
719443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
720443c15812032991c98b33b5424b17bcd55fe3575plougher}
721443c15812032991c98b33b5424b17bcd55fe3575plougher
722443c15812032991c98b33b5424b17bcd55fe3575plougher
7231c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougherint write_bytes(int fd, char *buff, int bytes)
7241c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher{
7251c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	int res, count;
7261c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
7271c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	for(count = 0; count < bytes; count += res) {
7281c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		res = write(fd, buff + count, bytes - count);
7291c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		if(res == -1) {
7301c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			if(errno != EINTR) {
731c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("Write on output file failed because "
732c435240f52b78b0ef498118727ba8dad186db26bplougher					"%s\n", strerror(errno));
7331c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher				return -1;
7341c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			}
7351c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			res = 0;
7361c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		}
7371c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	}
7381c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
7391c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	return 0;
7401c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher}
7411c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
7421c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
743b9cee889506e674726856035dba52d5e1cceeb99plougherint lseek_broken = FALSE;
744c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougherchar *zero_data = NULL;
745b9cee889506e674726856035dba52d5e1cceeb99plougher
74687f5e0e29e5f56516daaa51b1d36cde3d86a0f1fplougherint write_block(int file_fd, char *buffer, int size, long long hole, int sparse)
747b9cee889506e674726856035dba52d5e1cceeb99plougher{
748b9cee889506e674726856035dba52d5e1cceeb99plougher	off_t off = hole;
749b9cee889506e674726856035dba52d5e1cceeb99plougher
750b9cee889506e674726856035dba52d5e1cceeb99plougher	if(hole) {
751c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if(sparse && lseek_broken == FALSE) {
752c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			 int error = lseek(file_fd, off, SEEK_CUR);
753c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			 if(error == -1)
754c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				/* failed to seek beyond end of file */
755c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				lseek_broken = TRUE;
756c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		}
757c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
758c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if((sparse == FALSE || lseek_broken) && zero_data == NULL) {
759b9cee889506e674726856035dba52d5e1cceeb99plougher			if((zero_data = malloc(block_size)) == NULL)
760c435240f52b78b0ef498118727ba8dad186db26bplougher				EXIT_UNSQUASH("write_block: failed to alloc "
761c435240f52b78b0ef498118727ba8dad186db26bplougher					"zero data block\n");
762b9cee889506e674726856035dba52d5e1cceeb99plougher			memset(zero_data, 0, block_size);
763b9cee889506e674726856035dba52d5e1cceeb99plougher		}
764c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
765c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if(sparse == FALSE || lseek_broken) {
766b9cee889506e674726856035dba52d5e1cceeb99plougher			int blocks = (hole + block_size -1) / block_size;
767b9cee889506e674726856035dba52d5e1cceeb99plougher			int avail_bytes, i;
768b9cee889506e674726856035dba52d5e1cceeb99plougher			for(i = 0; i < blocks; i++, hole -= avail_bytes) {
769d4204758f77acb5a371fa1487a755b76a05d5476plougher				avail_bytes = hole > block_size ? block_size :
770d4204758f77acb5a371fa1487a755b76a05d5476plougher					hole;
771d4204758f77acb5a371fa1487a755b76a05d5476plougher				if(write_bytes(file_fd, zero_data, avail_bytes)
772d4204758f77acb5a371fa1487a755b76a05d5476plougher						== -1)
773b9cee889506e674726856035dba52d5e1cceeb99plougher					goto failure;
774b9cee889506e674726856035dba52d5e1cceeb99plougher			}
775b9cee889506e674726856035dba52d5e1cceeb99plougher		}
776b9cee889506e674726856035dba52d5e1cceeb99plougher	}
777b9cee889506e674726856035dba52d5e1cceeb99plougher
7781c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	if(write_bytes(file_fd, buffer, size) == -1)
779b9cee889506e674726856035dba52d5e1cceeb99plougher		goto failure;
780b9cee889506e674726856035dba52d5e1cceeb99plougher
781b9cee889506e674726856035dba52d5e1cceeb99plougher	return TRUE;
782b9cee889506e674726856035dba52d5e1cceeb99plougher
783b9cee889506e674726856035dba52d5e1cceeb99plougherfailure:
784b9cee889506e674726856035dba52d5e1cceeb99plougher	return FALSE;
785b9cee889506e674726856035dba52d5e1cceeb99plougher}
786b9cee889506e674726856035dba52d5e1cceeb99plougher
7878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
78879df93becb68081effabebba3006c794be308598plougherint write_file(struct inode *inode, char *pathname)
789443c15812032991c98b33b5424b17bcd55fe3575plougher{
7908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	unsigned int file_fd, i;
791f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher	unsigned int *block_list;
79279df93becb68081effabebba3006c794be308598plougher	int file_end = inode->data / block_size;
79379df93becb68081effabebba3006c794be308598plougher	long long start = inode->start;
7948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct squashfs_file *file;
795443c15812032991c98b33b5424b17bcd55fe3575plougher
79679df93becb68081effabebba3006c794be308598plougher	TRACE("write_file: regular file, blocks %d\n", inode->blocks);
797443c15812032991c98b33b5424b17bcd55fe3575plougher
798d4204758f77acb5a371fa1487a755b76a05d5476plougher	file_fd = open(pathname, O_CREAT | O_WRONLY | (force ? O_TRUNC : 0),
799d4204758f77acb5a371fa1487a755b76a05d5476plougher		(mode_t) inode->mode & 0777);
800d4204758f77acb5a371fa1487a755b76a05d5476plougher	if(file_fd == -1) {
801d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("write_file: failed to create file %s, because %s\n",
802d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
803443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
804443c15812032991c98b33b5424b17bcd55fe3575plougher	}
805443c15812032991c98b33b5424b17bcd55fe3575plougher
8066037584bc3e861ff932f5244105959c56c8560e3plougher	block_list = malloc(inode->blocks * sizeof(unsigned int));
8076037584bc3e861ff932f5244105959c56c8560e3plougher	if(block_list == NULL)
8088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("write_file: unable to malloc block list\n");
809443c15812032991c98b33b5424b17bcd55fe3575plougher
81079df93becb68081effabebba3006c794be308598plougher	s_ops.read_block_list(block_list, inode->block_ptr, inode->blocks);
811443c15812032991c98b33b5424b17bcd55fe3575plougher
8126037584bc3e861ff932f5244105959c56c8560e3plougher	file = malloc(sizeof(struct squashfs_file));
8136037584bc3e861ff932f5244105959c56c8560e3plougher	if(file == NULL)
8148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("write_file: unable to malloc file\n");
815443c15812032991c98b33b5424b17bcd55fe3575plougher
816d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
817d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * the writer thread is queued a squashfs_file structure describing the
818c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * file.  If the file has one or more blocks or a fragments they are
819c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * queued separately (references to blocks in the cache).
820d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
8218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	file->fd = file_fd;
82279df93becb68081effabebba3006c794be308598plougher	file->file_size = inode->data;
82379df93becb68081effabebba3006c794be308598plougher	file->mode = inode->mode;
82479df93becb68081effabebba3006c794be308598plougher	file->gid = inode->gid;
82579df93becb68081effabebba3006c794be308598plougher	file->uid = inode->uid;
82679df93becb68081effabebba3006c794be308598plougher	file->time = inode->time;
82779df93becb68081effabebba3006c794be308598plougher	file->pathname = strdup(pathname);
82879df93becb68081effabebba3006c794be308598plougher	file->blocks = inode->blocks + (inode->frag_bytes > 0);
8297f6692575a1b1c8d7d55afac647b72b84b79e378plougher	file->sparse = inode->sparse;
830fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher	file->xattr = inode->xattr;
8318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_put(to_writer, file);
832443c15812032991c98b33b5424b17bcd55fe3575plougher
83379df93becb68081effabebba3006c794be308598plougher	for(i = 0; i < inode->blocks; i++) {
8348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
8358372232d2460411adaa2299c32a0a88665e44902plougher		struct file_entry *block = malloc(sizeof(struct file_entry));
8368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
8378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
8388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
8398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->offset = 0;
840d4204758f77acb5a371fa1487a755b76a05d5476plougher		block->size = i == file_end ? inode->data & (block_size - 1) :
841d4204758f77acb5a371fa1487a755b76a05d5476plougher			block_size;
8428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block_list[i] == 0) /* sparse file */
8438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			block->buffer = NULL;
8448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else {
845d4204758f77acb5a371fa1487a755b76a05d5476plougher			block->buffer = cache_get(data_cache, start,
846d4204758f77acb5a371fa1487a755b76a05d5476plougher				block_list[i]);
8478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			start += c_byte;
848443c15812032991c98b33b5424b17bcd55fe3575plougher		}
8498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
850443c15812032991c98b33b5424b17bcd55fe3575plougher	}
851443c15812032991c98b33b5424b17bcd55fe3575plougher
85279df93becb68081effabebba3006c794be308598plougher	if(inode->frag_bytes) {
8538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int size;
8548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		long long start;
8558372232d2460411adaa2299c32a0a88665e44902plougher		struct file_entry *block = malloc(sizeof(struct file_entry));
8568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
8578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
8588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
85979df93becb68081effabebba3006c794be308598plougher		s_ops.read_fragment(inode->fragment, &start, &size);
8608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->buffer = cache_get(fragment_cache, start, size);
86179df93becb68081effabebba3006c794be308598plougher		block->offset = inode->offset;
86279df93becb68081effabebba3006c794be308598plougher		block->size = inode->frag_bytes;
8638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
864b9cee889506e674726856035dba52d5e1cceeb99plougher	}
865b9cee889506e674726856035dba52d5e1cceeb99plougher
866b9cee889506e674726856035dba52d5e1cceeb99plougher	free(block_list);
867443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
868443c15812032991c98b33b5424b17bcd55fe3575plougher}
869476dcb48b24efff22caa970f000e151f1b28918dplougher
870476dcb48b24efff22caa970f000e151f1b28918dplougher
8716f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint create_inode(char *pathname, struct inode *i)
872443c15812032991c98b33b5424b17bcd55fe3575plougher{
8736f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	TRACE("create_inode: pathname %s\n", pathname);
874443c15812032991c98b33b5424b17bcd55fe3575plougher
8756f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if(created_inode[i->inode_number - 1]) {
876443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("create_inode: hard link\n");
8776013a30bd39550decc2546a47e5168e57bfcfde8plougher		if(force)
8786013a30bd39550decc2546a47e5168e57bfcfde8plougher			unlink(pathname);
8796013a30bd39550decc2546a47e5168e57bfcfde8plougher
8806f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(link(created_inode[i->inode_number - 1], pathname) == -1) {
881c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("create_inode: failed to create hardlink, "
882c435240f52b78b0ef498118727ba8dad186db26bplougher				"because %s\n", strerror(errno));
883443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
884443c15812032991c98b33b5424b17bcd55fe3575plougher		}
885443c15812032991c98b33b5424b17bcd55fe3575plougher
886443c15812032991c98b33b5424b17bcd55fe3575plougher		return TRUE;
887443c15812032991c98b33b5424b17bcd55fe3575plougher	}
888443c15812032991c98b33b5424b17bcd55fe3575plougher
8896f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(i->type) {
8906f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_FILE_TYPE:
8916f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_LREG_TYPE:
892c435240f52b78b0ef498118727ba8dad186db26bplougher			TRACE("create_inode: regular file, file_size %lld, "
893c435240f52b78b0ef498118727ba8dad186db26bplougher				"blocks %d\n", i->data, i->blocks);
894443c15812032991c98b33b5424b17bcd55fe3575plougher
89579df93becb68081effabebba3006c794be308598plougher			if(write_file(i, pathname))
896443c15812032991c98b33b5424b17bcd55fe3575plougher				file_count ++;
897443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
8986f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_SYMLINK_TYPE:
89999ec5405b480bf852a0d9eed20693b750ed68943plougher		case SQUASHFS_LSYMLINK_TYPE:
900d4204758f77acb5a371fa1487a755b76a05d5476plougher			TRACE("create_inode: symlink, symlink_size %lld\n",
901d4204758f77acb5a371fa1487a755b76a05d5476plougher				i->data);
902443c15812032991c98b33b5424b17bcd55fe3575plougher
903a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
904a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
905a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
9066f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(symlink(i->symlink, pathname) == -1) {
907c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("create_inode: failed to create symlink "
908c435240f52b78b0ef498118727ba8dad186db26bplougher					"%s, because %s\n", pathname,
909c435240f52b78b0ef498118727ba8dad186db26bplougher					strerror(errno));
910443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
911443c15812032991c98b33b5424b17bcd55fe3575plougher			}
912443c15812032991c98b33b5424b17bcd55fe3575plougher
9132ef25cb004cc6995bd36f781863aa844fe8c358dplougher			write_xattr(pathname, i->xattr);
9142ef25cb004cc6995bd36f781863aa844fe8c358dplougher
9159dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
9166f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(lchown(pathname, i->uid, i->gid) == -1)
917c435240f52b78b0ef498118727ba8dad186db26bplougher					ERROR("create_inode: failed to change "
918c435240f52b78b0ef498118727ba8dad186db26bplougher						"uid and gids on %s, because "
919c435240f52b78b0ef498118727ba8dad186db26bplougher						"%s\n", pathname,
920c435240f52b78b0ef498118727ba8dad186db26bplougher						strerror(errno));
921443c15812032991c98b33b5424b17bcd55fe3575plougher			}
922443c15812032991c98b33b5424b17bcd55fe3575plougher
923443c15812032991c98b33b5424b17bcd55fe3575plougher			sym_count ++;
924443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
925443c15812032991c98b33b5424b17bcd55fe3575plougher 		case SQUASHFS_BLKDEV_TYPE:
92699ec5405b480bf852a0d9eed20693b750ed68943plougher	 	case SQUASHFS_CHRDEV_TYPE:
92799ec5405b480bf852a0d9eed20693b750ed68943plougher 		case SQUASHFS_LBLKDEV_TYPE:
92899ec5405b480bf852a0d9eed20693b750ed68943plougher	 	case SQUASHFS_LCHRDEV_TYPE: {
9296f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			int chrdev = i->type == SQUASHFS_CHRDEV_TYPE;
930545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			TRACE("create_inode: dev, rdev 0x%llx\n", i->data);
931443c15812032991c98b33b5424b17bcd55fe3575plougher
9329dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
933a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				if(force)
934a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher					unlink(pathname);
935a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
9366f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(mknod(pathname, chrdev ? S_IFCHR : S_IFBLK,
937d4204758f77acb5a371fa1487a755b76a05d5476plougher						makedev((i->data >> 8) & 0xff,
938d4204758f77acb5a371fa1487a755b76a05d5476plougher						i->data & 0xff)) == -1) {
939c435240f52b78b0ef498118727ba8dad186db26bplougher					ERROR("create_inode: failed to create "
940c435240f52b78b0ef498118727ba8dad186db26bplougher						"%s device %s, because %s\n",
941d4204758f77acb5a371fa1487a755b76a05d5476plougher						chrdev ? "character" : "block",
942d4204758f77acb5a371fa1487a755b76a05d5476plougher						pathname, strerror(errno));
943443c15812032991c98b33b5424b17bcd55fe3575plougher					break;
944443c15812032991c98b33b5424b17bcd55fe3575plougher				}
945c435240f52b78b0ef498118727ba8dad186db26bplougher				set_attributes(pathname, i->mode, i->uid,
946fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher					i->gid, i->time, i->xattr, TRUE);
947443c15812032991c98b33b5424b17bcd55fe3575plougher				dev_count ++;
948443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
949c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("create_inode: could not create %s "
950c435240f52b78b0ef498118727ba8dad186db26bplougher					"device %s, because you're not "
951c435240f52b78b0ef498118727ba8dad186db26bplougher					"superuser!\n", chrdev ? "character" :
952c435240f52b78b0ef498118727ba8dad186db26bplougher					"block", pathname);
953443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
9546f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		}
955443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_FIFO_TYPE:
95699ec5405b480bf852a0d9eed20693b750ed68943plougher		case SQUASHFS_LFIFO_TYPE:
957443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: fifo\n");
958443c15812032991c98b33b5424b17bcd55fe3575plougher
959a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
960a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
961a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
962443c15812032991c98b33b5424b17bcd55fe3575plougher			if(mknod(pathname, S_IFIFO, 0) == -1) {
963d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("create_inode: failed to create fifo %s, "
964d4204758f77acb5a371fa1487a755b76a05d5476plougher					"because %s\n", pathname,
965d4204758f77acb5a371fa1487a755b76a05d5476plougher					strerror(errno));
966443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
967443c15812032991c98b33b5424b17bcd55fe3575plougher			}
968c435240f52b78b0ef498118727ba8dad186db26bplougher			set_attributes(pathname, i->mode, i->uid, i->gid,
969fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher				i->time, i->xattr, TRUE);
970443c15812032991c98b33b5424b17bcd55fe3575plougher			fifo_count ++;
971443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
972443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_SOCKET_TYPE:
97399ec5405b480bf852a0d9eed20693b750ed68943plougher		case SQUASHFS_LSOCKET_TYPE:
974443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: socket\n");
975443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("create_inode: socket %s ignored\n", pathname);
976443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
977443c15812032991c98b33b5424b17bcd55fe3575plougher		default:
978d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("Unknown inode type %d in create_inode_table!\n",
979d4204758f77acb5a371fa1487a755b76a05d5476plougher				i->type);
980443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
981443c15812032991c98b33b5424b17bcd55fe3575plougher	}
982fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
9836f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	created_inode[i->inode_number - 1] = strdup(pathname);
984443c15812032991c98b33b5424b17bcd55fe3575plougher
985443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
986443c15812032991c98b33b5424b17bcd55fe3575plougher}
987443c15812032991c98b33b5424b17bcd55fe3575plougher
988443c15812032991c98b33b5424b17bcd55fe3575plougher
98902bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_directory_table(long long start, long long end)
990443c15812032991c98b33b5424b17bcd55fe3575plougher{
991443c15812032991c98b33b5424b17bcd55fe3575plougher	int bytes = 0, size = 0, res;
992443c15812032991c98b33b5424b17bcd55fe3575plougher
99341da3230b2ac91a73f9190676f66b3d80b21c270plougher	TRACE("uncompress_directory_table: start %lld, end %lld\n", start, end);
99441da3230b2ac91a73f9190676f66b3d80b21c270plougher
995443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
99607d4d0dcafeb198a568f859b88034637e6e7a8e7plougher		if(size - bytes < SQUASHFS_METADATA_SIZE) {
99707d4d0dcafeb198a568f859b88034637e6e7a8e7plougher			directory_table = realloc(directory_table, size +=
99807d4d0dcafeb198a568f859b88034637e6e7a8e7plougher				SQUASHFS_METADATA_SIZE);
99907d4d0dcafeb198a568f859b88034637e6e7a8e7plougher			if(directory_table == NULL)
100007d4d0dcafeb198a568f859b88034637e6e7a8e7plougher				EXIT_UNSQUASH("Out of memory in "
100107d4d0dcafeb198a568f859b88034637e6e7a8e7plougher					"uncompress_directory_table\n");
100207d4d0dcafeb198a568f859b88034637e6e7a8e7plougher		}
1003c435240f52b78b0ef498118727ba8dad186db26bplougher		TRACE("uncompress_directory_table: reading block 0x%llx\n",
1004c435240f52b78b0ef498118727ba8dad186db26bplougher				start);
1005443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(directory_table_hash, start, bytes);
1006176b325add10f6b9846f771f75d8543364d4c121plougher		res = read_block(fd, start, &start, directory_table + bytes);
1007c435240f52b78b0ef498118727ba8dad186db26bplougher		if(res == 0)
1008c435240f52b78b0ef498118727ba8dad186db26bplougher			EXIT_UNSQUASH("uncompress_directory_table: failed to "
1009c435240f52b78b0ef498118727ba8dad186db26bplougher				"read block\n");
1010443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
1011443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1012443c15812032991c98b33b5424b17bcd55fe3575plougher}
1013443c15812032991c98b33b5424b17bcd55fe3575plougher
1014443c15812032991c98b33b5424b17bcd55fe3575plougher
10159dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block,
10169dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherunsigned int *offset, unsigned int *type)
1017443c15812032991c98b33b5424b17bcd55fe3575plougher{
1018443c15812032991c98b33b5424b17bcd55fe3575plougher	if(dir->cur_entry == dir->dir_count)
1019443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
1020443c15812032991c98b33b5424b17bcd55fe3575plougher
1021443c15812032991c98b33b5424b17bcd55fe3575plougher	*name = dir->dirs[dir->cur_entry].name;
1022443c15812032991c98b33b5424b17bcd55fe3575plougher	*start_block = dir->dirs[dir->cur_entry].start_block;
1023443c15812032991c98b33b5424b17bcd55fe3575plougher	*offset = dir->dirs[dir->cur_entry].offset;
1024443c15812032991c98b33b5424b17bcd55fe3575plougher	*type = dir->dirs[dir->cur_entry].type;
1025443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->cur_entry ++;
1026443c15812032991c98b33b5424b17bcd55fe3575plougher
1027443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1028443c15812032991c98b33b5424b17bcd55fe3575plougher}
1029443c15812032991c98b33b5424b17bcd55fe3575plougher
1030443c15812032991c98b33b5424b17bcd55fe3575plougher
1031443c15812032991c98b33b5424b17bcd55fe3575ploughervoid squashfs_closedir(struct dir *dir)
1032443c15812032991c98b33b5424b17bcd55fe3575plougher{
1033443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir->dirs);
1034443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir);
1035443c15812032991c98b33b5424b17bcd55fe3575plougher}
1036443c15812032991c98b33b5424b17bcd55fe3575plougher
1037443c15812032991c98b33b5424b17bcd55fe3575plougher
1038b54566f5c433764830c29c83151691d0034de094plougherchar *get_component(char *target, char *targname)
1039b54566f5c433764830c29c83151691d0034de094plougher{
1040b54566f5c433764830c29c83151691d0034de094plougher	while(*target == '/')
10413cef656655723444fb1e2de1a001e6c2a54cf81erlougher		target ++;
1042b54566f5c433764830c29c83151691d0034de094plougher
1043b54566f5c433764830c29c83151691d0034de094plougher	while(*target != '/' && *target!= '\0')
1044b54566f5c433764830c29c83151691d0034de094plougher		*targname ++ = *target ++;
1045b54566f5c433764830c29c83151691d0034de094plougher
1046b54566f5c433764830c29c83151691d0034de094plougher	*targname = '\0';
1047b54566f5c433764830c29c83151691d0034de094plougher
1048b54566f5c433764830c29c83151691d0034de094plougher	return target;
1049b54566f5c433764830c29c83151691d0034de094plougher}
1050b54566f5c433764830c29c83151691d0034de094plougher
1051b54566f5c433764830c29c83151691d0034de094plougher
10526ee88c6b5da9f7b3ea88ab7481db126efa01c8f4ploughervoid free_path(struct pathname *paths)
10536ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher{
10546ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	int i;
10556ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
10566ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	for(i = 0; i < paths->names; i++) {
10576ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths)
10586ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
10596ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		free(paths->name[i].name);
10606ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].preg) {
10616ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			regfree(paths->name[i].preg);
10626ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free(paths->name[i].preg);
10636ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		}
10646ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	}
10656ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
10666ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	free(paths);
10676ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher}
10686ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
10696ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
10704dba330d7b952f2f044d38e342e2ae3ea78910d6plougherstruct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
1071b54566f5c433764830c29c83151691d0034de094plougher{
107271add234b27054974d5e29f95b3fab3072792a62plougher	char targname[1024];
10734dba330d7b952f2f044d38e342e2ae3ea78910d6plougher	int i, error;
107471add234b27054974d5e29f95b3fab3072792a62plougher
1075b7bb000643cd21c615a0366a7365441aa9c433f2plougher	TRACE("add_path: adding \"%s\" extract file\n", target);
1076b7bb000643cd21c615a0366a7365441aa9c433f2plougher
107771add234b27054974d5e29f95b3fab3072792a62plougher	target = get_component(target, targname);
107871add234b27054974d5e29f95b3fab3072792a62plougher
107971add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
10809dd4507fac1c96098eda8abe699a813a59451633plougher		paths = malloc(sizeof(struct pathname));
10819dd4507fac1c96098eda8abe699a813a59451633plougher		if(paths == NULL)
10824dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			EXIT_UNSQUASH("failed to allocate paths\n");
10834dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
108471add234b27054974d5e29f95b3fab3072792a62plougher		paths->names = 0;
108571add234b27054974d5e29f95b3fab3072792a62plougher		paths->name = NULL;
108671add234b27054974d5e29f95b3fab3072792a62plougher	}
108771add234b27054974d5e29f95b3fab3072792a62plougher
108871add234b27054974d5e29f95b3fab3072792a62plougher	for(i = 0; i < paths->names; i++)
108971add234b27054974d5e29f95b3fab3072792a62plougher		if(strcmp(paths->name[i].name, targname) == 0)
109071add234b27054974d5e29f95b3fab3072792a62plougher			break;
109171add234b27054974d5e29f95b3fab3072792a62plougher
10926ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	if(i == paths->names) {
1093d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1094d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * allocate new name entry
1095d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
109671add234b27054974d5e29f95b3fab3072792a62plougher		paths->names ++;
1097d4204758f77acb5a371fa1487a755b76a05d5476plougher		paths->name = realloc(paths->name, (i + 1) *
1098d4204758f77acb5a371fa1487a755b76a05d5476plougher			sizeof(struct path_entry));
1099fd628227871aecb36bb2b4f9c7f664f731510cdeplougher		if(paths->name == NULL)
1100fd628227871aecb36bb2b4f9c7f664f731510cdeplougher			EXIT_UNSQUASH("Out of memory in add_path\n");
110171add234b27054974d5e29f95b3fab3072792a62plougher		paths->name[i].name = strdup(targname);
11026ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		paths->name[i].paths = NULL;
11034dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		if(use_regex) {
11044dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = malloc(sizeof(regex_t));
11051f3cc42a2f77966d321a38d1709eba26f71104bdplougher			if(paths->name[i].preg == NULL)
11061f3cc42a2f77966d321a38d1709eba26f71104bdplougher				EXIT_UNSQUASH("Out of memory in add_path\n");
1107d4204758f77acb5a371fa1487a755b76a05d5476plougher			error = regcomp(paths->name[i].preg, targname,
1108d4204758f77acb5a371fa1487a755b76a05d5476plougher				REG_EXTENDED|REG_NOSUB);
1109545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			if(error) {
11104dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				char str[1024];
11114dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
11124dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				regerror(error, paths->name[i].preg, str, 1024);
1113d4204758f77acb5a371fa1487a755b76a05d5476plougher				EXIT_UNSQUASH("invalid regex %s in export %s, "
1114c435240f52b78b0ef498118727ba8dad186db26bplougher					"because %s\n", targname, alltarget,
1115c435240f52b78b0ef498118727ba8dad186db26bplougher					str);
11164dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			}
11174dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		} else
11184dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = NULL;
11196ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
11206ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(target[0] == '\0')
1121d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1122d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * at leaf pathname component
1123d4204758f77acb5a371fa1487a755b76a05d5476plougher			*/
112471add234b27054974d5e29f95b3fab3072792a62plougher			paths->name[i].paths = NULL;
112571add234b27054974d5e29f95b3fab3072792a62plougher		else
1126d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1127d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * recurse adding child components
1128d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
11294dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].paths = add_path(NULL, target, alltarget);
11306ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	} else {
1131d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1132d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * existing matching entry
1133d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
11346ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths == NULL) {
1135d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1136c435240f52b78b0ef498118727ba8dad186db26bplougher			 * No sub-directory which means this is the leaf
1137c435240f52b78b0ef498118727ba8dad186db26bplougher			 * component of a pre-existing extract which subsumes
1138c435240f52b78b0ef498118727ba8dad186db26bplougher			 * the extract currently being added, in which case stop
1139c435240f52b78b0ef498118727ba8dad186db26bplougher			 * adding components
1140d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
11416ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else if(target[0] == '\0') {
1142d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1143d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * at leaf pathname component and child components exist
1144c435240f52b78b0ef498118727ba8dad186db26bplougher			 * from more specific extracts, delete as they're
1145c435240f52b78b0ef498118727ba8dad186db26bplougher			 * subsumed by this extract
1146d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
11476ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
11486ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			paths->name[i].paths = NULL;
11496ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else
1150d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1151d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * recurse adding child components
1152d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
11536ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			add_path(paths->name[i].paths, target, alltarget);
115471add234b27054974d5e29f95b3fab3072792a62plougher	}
115571add234b27054974d5e29f95b3fab3072792a62plougher
115671add234b27054974d5e29f95b3fab3072792a62plougher	return paths;
115771add234b27054974d5e29f95b3fab3072792a62plougher}
11586ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
11596ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
1160a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *init_subdir()
116171add234b27054974d5e29f95b3fab3072792a62plougher{
11628372232d2460411adaa2299c32a0a88665e44902plougher	struct pathnames *new = malloc(sizeof(struct pathnames));
1163c5671cbe8dffaff7062ceb7b75f8d96c657a67b7plougher	if(new == NULL)
1164c5671cbe8dffaff7062ceb7b75f8d96c657a67b7plougher		EXIT_UNSQUASH("Out of memory in init_subdir\n");
1165a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	new->count = 0;
1166a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return new;
1167a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1168a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1169a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1170a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
1171a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
11723488d3bb3b89c394534ad2be909b661771a9581bplougher	if(paths->count % PATHS_ALLOC_SIZE == 0) {
1173d4204758f77acb5a371fa1487a755b76a05d5476plougher		paths = realloc(paths, sizeof(struct pathnames *) +
11743488d3bb3b89c394534ad2be909b661771a9581bplougher			(paths->count + PATHS_ALLOC_SIZE) *
11753488d3bb3b89c394534ad2be909b661771a9581bplougher			sizeof(struct pathname *));
11763488d3bb3b89c394534ad2be909b661771a9581bplougher		if(paths == NULL)
11773488d3bb3b89c394534ad2be909b661771a9581bplougher			EXIT_UNSQUASH("Out of memory in add_subdir\n");
11783488d3bb3b89c394534ad2be909b661771a9581bplougher	}
1179a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1180a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	paths->path[paths->count++] = path;
1181a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return paths;
1182a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1183a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1184a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1185a706f1b6bb48f288ecaf74e218ce20504bda52c6ploughervoid free_subdir(struct pathnames *paths)
1186a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1187a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free(paths);
1188a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1189a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1190a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1191a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherint matches(struct pathnames *paths, char *name, struct pathnames **new)
1192a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1193a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	int i, n;
119471add234b27054974d5e29f95b3fab3072792a62plougher
119571add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
119671add234b27054974d5e29f95b3fab3072792a62plougher		*new = NULL;
1197b54566f5c433764830c29c83151691d0034de094plougher		return TRUE;
119871add234b27054974d5e29f95b3fab3072792a62plougher	}
119971add234b27054974d5e29f95b3fab3072792a62plougher
1200a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = init_subdir();
1201a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1202a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	for(n = 0; n < paths->count; n++) {
1203a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		struct pathname *path = paths->path[n];
1204a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		for(i = 0; i < path->names; i++) {
1205a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			int match = use_regex ?
1206c435240f52b78b0ef498118727ba8dad186db26bplougher				regexec(path->name[i].preg, name, (size_t) 0,
1207c435240f52b78b0ef498118727ba8dad186db26bplougher				NULL, 0) == 0 : fnmatch(path->name[i].name,
1208c435240f52b78b0ef498118727ba8dad186db26bplougher				name, FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) ==
1209c435240f52b78b0ef498118727ba8dad186db26bplougher				0;
1210a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match && path->name[i].paths == NULL)
1211d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
1212d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * match on a leaf component, any subdirectories
1213c435240f52b78b0ef498118727ba8dad186db26bplougher				 * will implicitly match, therefore return an
1214c435240f52b78b0ef498118727ba8dad186db26bplougher				 * empty new search set
1215d4204758f77acb5a371fa1487a755b76a05d5476plougher				 */
1216a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				goto empty_set;
1217a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1218a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match)
1219d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
1220d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * match on a non-leaf component, add any
1221c435240f52b78b0ef498118727ba8dad186db26bplougher				 * subdirectories to the new set of
1222c435240f52b78b0ef498118727ba8dad186db26bplougher				 * subdirectories to scan for this name
1223d4204758f77acb5a371fa1487a755b76a05d5476plougher				 */
1224a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				*new = add_subdir(*new, path->name[i].paths);
1225a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		}
1226a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1227b54566f5c433764830c29c83151691d0034de094plougher
1228a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if((*new)->count == 0) {
1229d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1230d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * no matching names found, delete empty search set, and return
1231d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * FALSE
1232d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
1233a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(*new);
1234a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		*new = NULL;
1235a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		return FALSE;
1236a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1237a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1238d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
12390a0d045642e8e413f90b770539193d3fd1522786plougher	 * one or more matches with sub-directories found (no leaf matches),
12400a0d045642e8e413f90b770539193d3fd1522786plougher	 * return new search set and return TRUE
12410a0d045642e8e413f90b770539193d3fd1522786plougher	 */
1242a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
1243a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1244a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherempty_set:
1245d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
1246d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * found matching leaf exclude, return empty search set and return TRUE
1247d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
1248a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free_subdir(*new);
1249a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = NULL;
1250a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
1251b54566f5c433764830c29c83151691d0034de094plougher}
1252b54566f5c433764830c29c83151691d0034de094plougher
1253b54566f5c433764830c29c83151691d0034de094plougher
1254b807ab3497c01a49fed6f9daafce3bfc599a9421ploughervoid pre_scan(char *parent_name, unsigned int start_block, unsigned int offset,
1255d4204758f77acb5a371fa1487a755b76a05d5476plougher	struct pathnames *paths)
1256eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1257eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	unsigned int type;
1258eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	char *name, pathname[1024];
1259eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct pathnames *new;
1260eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
1261eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1262eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1263cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher	if(dir == NULL)
1264cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher		return;
1265cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher
1266eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
1267eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		struct inode *i;
1268eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1269d4204758f77acb5a371fa1487a755b76a05d5476plougher		TRACE("pre_scan: name %s, start_block %d, offset %d, type %d\n",
1270d4204758f77acb5a371fa1487a755b76a05d5476plougher			name, start_block, offset, type);
1271eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1272eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(!matches(paths, name, &new))
1273eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			continue;
1274eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1275eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
1276eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1277eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(type == SQUASHFS_DIR_TYPE)
1278eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			pre_scan(parent_name, start_block, offset, new);
1279eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		else if(new == NULL) {
1280d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(type == SQUASHFS_FILE_TYPE ||
1281d4204758f77acb5a371fa1487a755b76a05d5476plougher					type == SQUASHFS_LREG_TYPE) {
1282312e50b7b8c9dd39577657bd3d79fcedf6e91a1bplougher				i = s_ops.read_inode(start_block, offset);
1283eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				if(created_inode[i->inode_number - 1] == NULL) {
1284d4204758f77acb5a371fa1487a755b76a05d5476plougher					created_inode[i->inode_number - 1] =
1285d4204758f77acb5a371fa1487a755b76a05d5476plougher						(char *) i;
1286d4204758f77acb5a371fa1487a755b76a05d5476plougher					total_blocks += (i->data +
1287d4204758f77acb5a371fa1487a755b76a05d5476plougher						(block_size - 1)) >> block_log;
1288eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
1289eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				total_files ++;
1290eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			}
1291eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			total_inodes ++;
1292eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		}
1293eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1294eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		free_subdir(new);
1295eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
1296eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1297eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	squashfs_closedir(dir);
1298eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1299eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1300eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1301a2cff53655359b044ea88baa76cb16d1c8f44d2aploughervoid dir_scan(char *parent_name, unsigned int start_block, unsigned int offset,
1302d4204758f77acb5a371fa1487a755b76a05d5476plougher	struct pathnames *paths)
1303443c15812032991c98b33b5424b17bcd55fe3575plougher{
1304443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int type;
1305443c15812032991c98b33b5424b17bcd55fe3575plougher	char *name, pathname[1024];
1306a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *new;
1307eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
1308eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1309443c15812032991c98b33b5424b17bcd55fe3575plougher
1310cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher	if(dir == NULL) {
1311cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher		ERROR("dir_scan: failed to read directory %s, skipping\n",
1312cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher			parent_name);
1313cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher		return;
1314cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher	}
1315cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher
1316eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(lsonly || info)
1317eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		print_filename(parent_name, i);
1318eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1319d4204758f77acb5a371fa1487a755b76a05d5476plougher	if(!lsonly && mkdir(parent_name, (mode_t) dir->mode) == -1 &&
132085917a285edbd4bb78f1b245f66c634d1e0d4029plougher			(!force || errno != EEXIST)) {
132185917a285edbd4bb78f1b245f66c634d1e0d4029plougher		ERROR("dir_scan: failed to make directory %s, because %s\n",
1322d4204758f77acb5a371fa1487a755b76a05d5476plougher			parent_name, strerror(errno));
132385917a285edbd4bb78f1b245f66c634d1e0d4029plougher		squashfs_closedir(dir);
132485917a285edbd4bb78f1b245f66c634d1e0d4029plougher		return;
132585917a285edbd4bb78f1b245f66c634d1e0d4029plougher	}
1326443c15812032991c98b33b5424b17bcd55fe3575plougher
1327443c15812032991c98b33b5424b17bcd55fe3575plougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
1328d4204758f77acb5a371fa1487a755b76a05d5476plougher		TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n",
1329d4204758f77acb5a371fa1487a755b76a05d5476plougher			name, start_block, offset, type);
1330b54566f5c433764830c29c83151691d0034de094plougher
133171add234b27054974d5e29f95b3fab3072792a62plougher
133271add234b27054974d5e29f95b3fab3072792a62plougher		if(!matches(paths, name, &new))
1333b54566f5c433764830c29c83151691d0034de094plougher			continue;
1334b54566f5c433764830c29c83151691d0034de094plougher
1335443c15812032991c98b33b5424b17bcd55fe3575plougher		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
1336fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
1337443c15812032991c98b33b5424b17bcd55fe3575plougher		if(type == SQUASHFS_DIR_TYPE)
133871add234b27054974d5e29f95b3fab3072792a62plougher			dir_scan(pathname, start_block, offset, new);
1339a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		else if(new == NULL) {
1340312e50b7b8c9dd39577657bd3d79fcedf6e91a1bplougher			i = s_ops.read_inode(start_block, offset);
13416f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
13426f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(lsonly || info)
13436f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				print_filename(pathname, i);
13446f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
1345eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			if(!lsonly) {
13466f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				create_inode(pathname, i);
1347eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				update_progress_bar();
1348eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
1349427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher
1350d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(i->type == SQUASHFS_SYMLINK_TYPE ||
1351d4204758f77acb5a371fa1487a755b76a05d5476plougher					i->type == SQUASHFS_LSYMLINK_TYPE)
1352427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher				free(i->symlink);
13536f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		}
1354a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1355a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(new);
1356443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1357443c15812032991c98b33b5424b17bcd55fe3575plougher
1358074d3f1129eae914655f6637773488052bf22327rlougher	if(!lsonly)
1359d4204758f77acb5a371fa1487a755b76a05d5476plougher		set_attributes(parent_name, dir->mode, dir->uid, dir->guid,
1360fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher			dir->mtime, dir->xattr, force);
1361443c15812032991c98b33b5424b17bcd55fe3575plougher
1362443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_closedir(dir);
1363443c15812032991c98b33b5424b17bcd55fe3575plougher	dir_count ++;
1364443c15812032991c98b33b5424b17bcd55fe3575plougher}
1365443c15812032991c98b33b5424b17bcd55fe3575plougher
1366443c15812032991c98b33b5424b17bcd55fe3575plougher
1367b624936abba03d38b7e9245c647339d8f6f34274ploughervoid squashfs_stat(char *source)
1368b624936abba03d38b7e9245c647339d8f6f34274plougher{
136927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	time_t mkfs_time = (time_t) sBlk.s.mkfs_time;
1370b624936abba03d38b7e9245c647339d8f6f34274plougher	char *mkfs_str = ctime(&mkfs_time);
1371b624936abba03d38b7e9245c647339d8f6f34274plougher
1372b624936abba03d38b7e9245c647339d8f6f34274plougher#if __BYTE_ORDER == __BIG_ENDIAN
1373d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n",
137427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.s_major == 4 ? "" : swap ? "little endian " :
137527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		"big endian ", sBlk.s.s_major, sBlk.s.s_minor, source);
1376b624936abba03d38b7e9245c647339d8f6f34274plougher#else
1377d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n",
137827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.s_major == 4 ? "" : swap ? "big endian " :
137927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		"little endian ", sBlk.s.s_major, sBlk.s.s_minor, source);
1380b624936abba03d38b7e9245c647339d8f6f34274plougher#endif
1381c766500607f1ea7494b8360409be3d8ea66f9761plougher
1382d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Creation or last append time %s", mkfs_str ? mkfs_str :
1383d4204758f77acb5a371fa1487a755b76a05d5476plougher		"failed to get time\n");
1384e5e5a7502f722fae4f057f49932fe4de2501f6e8plougher	printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n",
1385e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		sBlk.s.bytes_used / 1024.0, sBlk.s.bytes_used /
1386e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		(1024.0 * 1024.0));
1387c766500607f1ea7494b8360409be3d8ea66f9761plougher
138827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major == 4)
1389e5e5a7502f722fae4f057f49932fe4de2501f6e8plougher		printf("Compression %s\n", comp->name);
1390c766500607f1ea7494b8360409be3d8ea66f9761plougher
139127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	printf("Block size %d\n", sBlk.s.block_size);
1392d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Filesystem is %sexportable via NFS\n",
139327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_EXPORTABLE(sBlk.s.flags) ? "" : "not ");
1394d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Inodes are %scompressed\n",
139527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_UNCOMPRESSED_INODES(sBlk.s.flags) ? "un" : "");
1396d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Data is %scompressed\n",
139727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_UNCOMPRESSED_DATA(sBlk.s.flags) ? "un" : "");
1398c766500607f1ea7494b8360409be3d8ea66f9761plougher
13997ca09d1320cdc30a068f179b93ca5c141b55c395plougher	if(sBlk.s.s_major > 1) {
14007ca09d1320cdc30a068f179b93ca5c141b55c395plougher		if(SQUASHFS_NO_FRAGMENTS(sBlk.s.flags))
14017ca09d1320cdc30a068f179b93ca5c141b55c395plougher			printf("Fragments are not stored\n");
14027ca09d1320cdc30a068f179b93ca5c141b55c395plougher		else {
14037ca09d1320cdc30a068f179b93ca5c141b55c395plougher			printf("Fragments are %scompressed\n",
14047ca09d1320cdc30a068f179b93ca5c141b55c395plougher				SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.s.flags) ?
14057ca09d1320cdc30a068f179b93ca5c141b55c395plougher				"un" : "");
14067ca09d1320cdc30a068f179b93ca5c141b55c395plougher			printf("Always_use_fragments option is %sspecified\n",
14077ca09d1320cdc30a068f179b93ca5c141b55c395plougher				SQUASHFS_ALWAYS_FRAGMENTS(sBlk.s.flags) ? "" :
14087ca09d1320cdc30a068f179b93ca5c141b55c395plougher				"not ");
14097ca09d1320cdc30a068f179b93ca5c141b55c395plougher		}
14107ca09d1320cdc30a068f179b93ca5c141b55c395plougher	}
14117ca09d1320cdc30a068f179b93ca5c141b55c395plougher
1412de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher	if(sBlk.s.s_major == 4) {
1413de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher		if(SQUASHFS_NO_XATTRS(sBlk.s.flags))
1414de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher			printf("Xattrs are not stored\n");
1415de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher		else
1416de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher			printf("Xattrs are %scompressed\n",
1417de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher				SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.s.flags) ?
1418de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher				"un" : "");
1419de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher	}
1420de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher
1421ba95dd35ef0e9f618d926ddc1a595076adc23818plougher	if(sBlk.s.s_major < 4)
1422ba95dd35ef0e9f618d926ddc1a595076adc23818plougher			printf("Check data is %spresent in the filesystem\n",
1423ba95dd35ef0e9f618d926ddc1a595076adc23818plougher				SQUASHFS_CHECK_DATA(sBlk.s.flags) ? "" :
1424ba95dd35ef0e9f618d926ddc1a595076adc23818plougher				"not ");
1425c766500607f1ea7494b8360409be3d8ea66f9761plougher
142627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major > 1)
1427d4204758f77acb5a371fa1487a755b76a05d5476plougher		printf("Duplicates are %sremoved\n",
142827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			SQUASHFS_DUPLICATES(sBlk.s.flags) ? "" : "not ");
14290337de3977eec74e6a3d28e0d0863299246de8b7plougher	else
14300337de3977eec74e6a3d28e0d0863299246de8b7plougher		printf("Duplicates are removed\n");
1431c766500607f1ea7494b8360409be3d8ea66f9761plougher
143227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major > 1)
143327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		printf("Number of fragments %d\n", sBlk.s.fragments);
1434c766500607f1ea7494b8360409be3d8ea66f9761plougher
143527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	printf("Number of inodes %d\n", sBlk.s.inodes);
1436c766500607f1ea7494b8360409be3d8ea66f9761plougher
143727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major == 4)
143827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		printf("Number of ids %d\n", sBlk.s.no_ids);
14390f74340e3b68533339adc60f418ddf59fa188f61plougher	else {
14400f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of uids %d\n", sBlk.no_uids);
14410f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of gids %d\n", sBlk.no_guids);
14420f74340e3b68533339adc60f418ddf59fa188f61plougher	}
1443b624936abba03d38b7e9245c647339d8f6f34274plougher
144427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	TRACE("sBlk.s.inode_table_start 0x%llx\n", sBlk.s.inode_table_start);
144527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	TRACE("sBlk.s.directory_table_start 0x%llx\n",
144627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.directory_table_start);
1447c766500607f1ea7494b8360409be3d8ea66f9761plougher
14480ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher	if(sBlk.s.s_major > 1)
14490ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher		TRACE("sBlk.s.fragment_table_start 0x%llx\n\n",
14500ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher			sBlk.s.fragment_table_start);
14510ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher
14520ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher	if(sBlk.s.s_major > 2)
14530ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher		TRACE("sBlk.s.lookup_table_start 0x%llx\n\n",
14540ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher			sBlk.s.lookup_table_start);
14550ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher
1456053da34003852e494400c1ade35b526e1821b576plougher	if(sBlk.s.s_major == 4) {
145727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		TRACE("sBlk.s.id_table_start 0x%llx\n", sBlk.s.id_table_start);
1458053da34003852e494400c1ade35b526e1821b576plougher		TRACE("sBlk.s.xattr_id_table_start 0x%llx\n",
1459053da34003852e494400c1ade35b526e1821b576plougher			sBlk.s.xattr_id_table_start);
1460053da34003852e494400c1ade35b526e1821b576plougher	} else {
14610f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.uid_start 0x%llx\n", sBlk.uid_start);
14620f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.guid_start 0x%llx\n", sBlk.guid_start);
14630f74340e3b68533339adc60f418ddf59fa188f61plougher	}
1464b624936abba03d38b7e9245c647339d8f6f34274plougher}
1465b624936abba03d38b7e9245c647339d8f6f34274plougher
1466b624936abba03d38b7e9245c647339d8f6f34274plougher
146702bc3bcabf2b219f63961f07293b83629948f026plougherint read_super(char *source)
1468443c15812032991c98b33b5424b17bcd55fe3575plougher{
14696490378e5b5e8dc058daf28423a7465699a6ba7bplougher	squashfs_super_block_3 sBlk_3;
147064e83fda63a1b8408ffbfa466e6c67b0de7a8c99plougher	struct squashfs_super_block sBlk_4;
14716490378e5b5e8dc058daf28423a7465699a6ba7bplougher
14726490378e5b5e8dc058daf28423a7465699a6ba7bplougher	/*
14736490378e5b5e8dc058daf28423a7465699a6ba7bplougher	 * Try to read a Squashfs 4 superblock
14746490378e5b5e8dc058daf28423a7465699a6ba7bplougher	 */
147564e83fda63a1b8408ffbfa466e6c67b0de7a8c99plougher	read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
14763306cb2b54a60a32664617118336ac141e1471b6plougher		&sBlk_4);
147754660e177ba40ab08ee2f3304b9f030eb5675677plougher	swap = sBlk_4.s_magic != SQUASHFS_MAGIC;
14786490378e5b5e8dc058daf28423a7465699a6ba7bplougher	SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4);
14796490378e5b5e8dc058daf28423a7465699a6ba7bplougher
1480d4204758f77acb5a371fa1487a755b76a05d5476plougher	if(sBlk_4.s_magic == SQUASHFS_MAGIC && sBlk_4.s_major == 4 &&
1481d4204758f77acb5a371fa1487a755b76a05d5476plougher			sBlk_4.s_minor == 0) {
14826490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.squashfs_opendir = squashfs_opendir_4;
14836490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_fragment = read_fragment_4;
14846490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_fragment_table = read_fragment_table_4;
14856490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_block_list = read_block_list_2;
14866490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_inode = read_inode_4;
14876490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_uids_guids = read_uids_guids_4;
14886490378e5b5e8dc058daf28423a7465699a6ba7bplougher		memcpy(&sBlk, &sBlk_4, sizeof(sBlk_4));
1489efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
1490efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		/*
1491efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		 * Check the compression type
1492efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		 */
149327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		comp = lookup_compressor_id(sBlk.s.compression);
14946490378e5b5e8dc058daf28423a7465699a6ba7bplougher		return TRUE;
14956490378e5b5e8dc058daf28423a7465699a6ba7bplougher	}
14966490378e5b5e8dc058daf28423a7465699a6ba7bplougher
14976490378e5b5e8dc058daf28423a7465699a6ba7bplougher	/*
14986490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 * Not a Squashfs 4 superblock, try to read a squashfs 3 superblock
14996490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 * (compatible with 1 and 2 filesystems)
15006490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 */
150186561909d9ca51a4e4ce4efcfea30b41d1d08275plougher	read_fs_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block_3),
15023306cb2b54a60a32664617118336ac141e1471b6plougher		&sBlk_3);
1503443c15812032991c98b33b5424b17bcd55fe3575plougher
1504d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
1505d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * Check it is a SQUASHFS superblock
1506d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
1507443c15812032991c98b33b5424b17bcd55fe3575plougher	swap = 0;
150821ee4773956342a8a7d0f14e430ae77ffbd10601plougher	if(sBlk_3.s_magic != SQUASHFS_MAGIC) {
150921ee4773956342a8a7d0f14e430ae77ffbd10601plougher		if(sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP) {
15107a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher			squashfs_super_block_3 sblk;
1511c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("Reading a different endian SQUASHFS filesystem "
1512c435240f52b78b0ef498118727ba8dad186db26bplougher				"on %s\n", source);
15136490378e5b5e8dc058daf28423a7465699a6ba7bplougher			SQUASHFS_SWAP_SUPER_BLOCK_3(&sblk, &sBlk_3);
15146490378e5b5e8dc058daf28423a7465699a6ba7bplougher			memcpy(&sBlk_3, &sblk, sizeof(squashfs_super_block_3));
1515443c15812032991c98b33b5424b17bcd55fe3575plougher			swap = 1;
1516443c15812032991c98b33b5424b17bcd55fe3575plougher		} else  {
1517c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("Can't find a SQUASHFS superblock on %s\n",
1518c435240f52b78b0ef498118727ba8dad186db26bplougher				source);
1519443c15812032991c98b33b5424b17bcd55fe3575plougher			goto failed_mount;
1520443c15812032991c98b33b5424b17bcd55fe3575plougher		}
1521443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1522443c15812032991c98b33b5424b17bcd55fe3575plougher
152327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.s_magic = sBlk_3.s_magic;
152427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.inodes = sBlk_3.inodes;
152527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.mkfs_time = sBlk_3.mkfs_time;
152627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.block_size = sBlk_3.block_size;
152727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.fragments = sBlk_3.fragments;
152827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.block_log = sBlk_3.block_log;
152927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.flags = sBlk_3.flags;
153027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.s_major = sBlk_3.s_major;
153127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.s_minor = sBlk_3.s_minor;
153227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.root_inode = sBlk_3.root_inode;
153327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.bytes_used = sBlk_3.bytes_used;
153427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.inode_table_start = sBlk_3.inode_table_start;
153527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.directory_table_start = sBlk_3.directory_table_start;
153627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.fragment_table_start = sBlk_3.fragment_table_start;
153727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.lookup_table_start = sBlk_3.lookup_table_start;
15386490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.no_uids = sBlk_3.no_uids;
15396490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.no_guids = sBlk_3.no_guids;
15406490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.uid_start = sBlk_3.uid_start;
15416490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.guid_start = sBlk_3.guid_start;
154227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK;
15436490378e5b5e8dc058daf28423a7465699a6ba7bplougher
1544443c15812032991c98b33b5424b17bcd55fe3575plougher	/* Check the MAJOR & MINOR versions */
154527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major == 1 || sBlk.s.s_major == 2) {
154627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.bytes_used = sBlk_3.bytes_used_2;
15476490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.uid_start = sBlk_3.uid_start_2;
15486490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.guid_start = sBlk_3.guid_start_2;
154927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.inode_table_start = sBlk_3.inode_table_start_2;
155027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.directory_table_start = sBlk_3.directory_table_start_2;
155102bc3bcabf2b219f63961f07293b83629948f026plougher
155227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		if(sBlk.s.s_major == 1) {
155327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.block_size = sBlk_3.block_size_1;
155427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.fragment_table_start = sBlk.uid_start;
1555ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.squashfs_opendir = squashfs_opendir_1;
1556ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_1;
1557ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_block_list = read_block_list_1;
15586f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_1;
155979e700efc62527661ce140bd1013a2b60577917eplougher			s_ops.read_uids_guids = read_uids_guids_1;
1560ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		} else {
156127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.fragment_table_start =
1562c435240f52b78b0ef498118727ba8dad186db26bplougher				sBlk_3.fragment_table_start_2;
1563ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.squashfs_opendir = squashfs_opendir_1;
1564ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment = read_fragment_2;
1565ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_2;
1566ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.read_block_list = read_block_list_2;
15676f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_2;
156879e700efc62527661ce140bd1013a2b60577917eplougher			s_ops.read_uids_guids = read_uids_guids_1;
1569ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		}
157027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	} else if(sBlk.s.s_major == 3) {
1571ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.squashfs_opendir = squashfs_opendir_3;
1572ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_fragment = read_fragment_3;
1573ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_fragment_table = read_fragment_table_3;
1574ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_block_list = read_block_list_2;
1575ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_inode = read_inode_3;
157679e700efc62527661ce140bd1013a2b60577917eplougher		s_ops.read_uids_guids = read_uids_guids_1;
157702bc3bcabf2b219f63961f07293b83629948f026plougher	} else {
157827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		ERROR("Filesystem on %s is (%d:%d), ", source, sBlk.s.s_major,
157927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.s_minor);
15804c99cb7f458d8e1c598f1c80793daf3696c9b528plougher		ERROR("which is a later filesystem version than I support!\n");
1581443c15812032991c98b33b5424b17bcd55fe3575plougher		goto failed_mount;
1582443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1583443c15812032991c98b33b5424b17bcd55fe3575plougher
1584efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	/*
158599c8abf4de4297b3159355a0cefe9ad6f5182827plougher	 * 1.x, 2.x and 3.x filesystems use gzip compression.
1586efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	 */
1587efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	comp = lookup_compressor("gzip");
1588443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1589443c15812032991c98b33b5424b17bcd55fe3575plougher
1590443c15812032991c98b33b5424b17bcd55fe3575plougherfailed_mount:
1591443c15812032991c98b33b5424b17bcd55fe3575plougher	return FALSE;
1592443c15812032991c98b33b5424b17bcd55fe3575plougher}
1593443c15812032991c98b33b5424b17bcd55fe3575plougher
1594443c15812032991c98b33b5424b17bcd55fe3575plougher
1595a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathname *process_extract_files(struct pathname *path, char *filename)
159671add234b27054974d5e29f95b3fab3072792a62plougher{
159771add234b27054974d5e29f95b3fab3072792a62plougher	FILE *fd;
159871add234b27054974d5e29f95b3fab3072792a62plougher	char name[16384];
159971add234b27054974d5e29f95b3fab3072792a62plougher
160063e21ee4b795bb900f82c18e7b5c6f7369907360plougher	fd = fopen(filename, "r");
160163e21ee4b795bb900f82c18e7b5c6f7369907360plougher	if(fd == NULL)
1602d4204758f77acb5a371fa1487a755b76a05d5476plougher		EXIT_UNSQUASH("Could not open %s, because %s\n", filename,
1603d4204758f77acb5a371fa1487a755b76a05d5476plougher			strerror(errno));
160471add234b27054974d5e29f95b3fab3072792a62plougher
160571add234b27054974d5e29f95b3fab3072792a62plougher	while(fscanf(fd, "%16384[^\n]\n", name) != EOF)
1606a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, name, name);
160771add234b27054974d5e29f95b3fab3072792a62plougher
160871add234b27054974d5e29f95b3fab3072792a62plougher	fclose(fd);
1609a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return path;
161071add234b27054974d5e29f95b3fab3072792a62plougher}
161171add234b27054974d5e29f95b3fab3072792a62plougher
161271add234b27054974d5e29f95b3fab3072792a62plougher
1613d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
1614d4204758f77acb5a371fa1487a755b76a05d5476plougher * reader thread.  This thread processes read requests queued by the
1615d4204758f77acb5a371fa1487a755b76a05d5476plougher * cache_get() routine.
1616d4204758f77acb5a371fa1487a755b76a05d5476plougher */
16178888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *reader(void *arg)
16188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
16198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
16208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct cache_entry *entry = queue_get(to_reader);
162186561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		int res = read_fs_bytes(fd, entry->block,
16228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size),
16238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data);
16248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(res && SQUASHFS_COMPRESSED_BLOCK(entry->size))
1626d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1627c435240f52b78b0ef498118727ba8dad186db26bplougher			 * queue successfully read block to the deflate
1628c435240f52b78b0ef498118727ba8dad186db26bplougher			 * thread(s) for further processing
1629d4204758f77acb5a371fa1487a755b76a05d5476plougher 			 */
16308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			queue_put(to_deflate, entry);
16318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else
1632d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1633d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * block has either been successfully read and is
1634d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * uncompressed, or an error has occurred, clear pending
1635c435240f52b78b0ef498118727ba8dad186db26bplougher			 * flag, set error appropriately, and wake up any
1636c435240f52b78b0ef498118727ba8dad186db26bplougher			 * threads waiting on this buffer
1637d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
16388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_ready(entry, !res);
16398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
16408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
16418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1643d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
1644d4204758f77acb5a371fa1487a755b76a05d5476plougher * writer thread.  This processes file write requests queued by the
1645d4204758f77acb5a371fa1487a755b76a05d5476plougher * write_file() routine.
1646d4204758f77acb5a371fa1487a755b76a05d5476plougher */
16478888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *writer(void *arg)
16488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
16498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int i;
16508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
16528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct squashfs_file *file = queue_get(to_writer);
16538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int file_fd;
165487f5e0e29e5f56516daaa51b1d36cde3d86a0f1fplougher		long long hole = 0;
165527636cb2cec37a68313f9eb825c0548245eecad0plougher		int failed = FALSE;
1656c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		int error;
16578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(file == NULL) {
16598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			queue_put(from_writer, NULL);
16608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			continue;
16618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
16628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		TRACE("writer: regular file, blocks %d\n", file->blocks);
16648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		file_fd = file->fd;
16668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1667eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		for(i = 0; i < file->blocks; i++, cur_blocks ++) {
16688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			struct file_entry *block = queue_get(to_writer);
16698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(block->buffer == 0) { /* sparse file */
16718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole += block->size;
16728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				free(block);
16738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				continue;
16748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
16758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_wait(block->buffer);
167727636cb2cec37a68313f9eb825c0548245eecad0plougher
167827636cb2cec37a68313f9eb825c0548245eecad0plougher			if(block->buffer->error)
167927636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
168027636cb2cec37a68313f9eb825c0548245eecad0plougher
1681c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			if(failed)
1682c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				continue;
1683c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
1684c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			error = write_block(file_fd, block->buffer->data +
1685c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				block->offset, block->size, hole, file->sparse);
1686c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
1687c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			if(error == FALSE) {
1688d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("writer: failed to write data block %d\n",
1689d4204758f77acb5a371fa1487a755b76a05d5476plougher					i);
169027636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
16918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
1692c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
16938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			hole = 0;
16948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_put(block->buffer);
16958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			free(block);
16968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
16978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
169827636cb2cec37a68313f9eb825c0548245eecad0plougher		if(hole && failed == FALSE) {
1699d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1700d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * corner case for hole extending to end of file
1701d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
1702d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(file->sparse == FALSE ||
1703d4204758f77acb5a371fa1487a755b76a05d5476plougher					lseek(file_fd, hole, SEEK_CUR) == -1) {
1704d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
1705d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * for files which we don't want to write
1706c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * sparsely, or for broken lseeks which cannot
1707c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * seek beyond end of file, write_block will do
1708c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * the right thing
1709c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 */
17108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole --;
1711d4204758f77acb5a371fa1487a755b76a05d5476plougher				if(write_block(file_fd, "\0", 1, hole,
1712d4204758f77acb5a371fa1487a755b76a05d5476plougher						file->sparse) == FALSE) {
1713d4204758f77acb5a371fa1487a755b76a05d5476plougher					ERROR("writer: failed to write sparse "
1714d4204758f77acb5a371fa1487a755b76a05d5476plougher						"data block\n");
171527636cb2cec37a68313f9eb825c0548245eecad0plougher					failed = TRUE;
17168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				}
17178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			} else if(ftruncate(file_fd, file->file_size) == -1) {
1718d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("writer: failed to write sparse data "
1719d4204758f77acb5a371fa1487a755b76a05d5476plougher					"block\n");
172027636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
17218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
17228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
17238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
17248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		close(file_fd);
172527636cb2cec37a68313f9eb825c0548245eecad0plougher		if(failed == FALSE)
1726d4204758f77acb5a371fa1487a755b76a05d5476plougher			set_attributes(file->pathname, file->mode, file->uid,
1727fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher				file->gid, file->time, file->xattr, force);
172827636cb2cec37a68313f9eb825c0548245eecad0plougher		else {
172927636cb2cec37a68313f9eb825c0548245eecad0plougher			ERROR("Failed to write %s, skipping\n", file->pathname);
173027636cb2cec37a68313f9eb825c0548245eecad0plougher			unlink(file->pathname);
173127636cb2cec37a68313f9eb825c0548245eecad0plougher		}
173279df93becb68081effabebba3006c794be308598plougher		free(file->pathname);
17338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		free(file);
173427636cb2cec37a68313f9eb825c0548245eecad0plougher
17358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
17368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
17378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
17388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1739d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
1740d4204758f77acb5a371fa1487a755b76a05d5476plougher * decompress thread.  This decompresses buffers queued by the read thread
1741d4204758f77acb5a371fa1487a755b76a05d5476plougher */
17428888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *deflator(void *arg)
17438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
17448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	char tmp[block_size];
17458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
17468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
17478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct cache_entry *entry = queue_get(to_deflate);
1748efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		int error, res;
1749efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
1750b48442b2e37b3cb7efbffb032968f115eec7963cplougher		res = compressor_uncompress(comp, tmp, entry->data,
1751efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size), block_size,
1752efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			&error);
1753efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
1754efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		if(res == -1)
1755efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			ERROR("%s uncompress failed with error code %d\n",
1756efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher				comp->name, error);
1757efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		else
1758efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			memcpy(entry->data, tmp, res);
17598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1760d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1761d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * block has been either successfully decompressed, or an error
17628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * occurred, clear pending flag, set error appropriately and
1763d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 * wake up any threads waiting on this block
1764d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 */
1765efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		cache_block_ready(entry, res == -1);
17668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
17678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
17688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
17698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1770eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid *progress_thread(void *arg)
1771eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1772eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct timeval timeval;
1773eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct timespec timespec;
17741b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct itimerval itimerval;
17751b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct winsize winsize;
17761b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
17771b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
177801b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher		if(isatty(STDOUT_FILENO))
177901b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher			ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
178001b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher				"columns\n");
17811b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = 80;
17821b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	} else
17831b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = winsize.ws_col;
17841b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGWINCH, sigwinch_handler);
17851b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGALRM, sigalrm_handler);
17861b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
17871b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_sec = 0;
17881b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_usec = 250000;
17891b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_sec = 0;
17901b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_usec = 250000;
17911b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	setitimer(ITIMER_REAL, &itimerval, NULL);
1792eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1793eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_cond_init(&progress_wait, NULL);
1794eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
17951b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
1796eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(1) {
1797eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		gettimeofday(&timeval, NULL);
1798eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		timespec.tv_sec = timeval.tv_sec;
1799eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(timeval.tv_usec + 250000 > 999999)
1800eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			timespec.tv_sec++;
1801c435240f52b78b0ef498118727ba8dad186db26bplougher		timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) *
1802c435240f52b78b0ef498118727ba8dad186db26bplougher			1000;
1803c435240f52b78b0ef498118727ba8dad186db26bplougher		pthread_cond_timedwait(&progress_wait, &screen_mutex,
1804c435240f52b78b0ef498118727ba8dad186db26bplougher			&timespec);
18051b42101056befe25b5f19d5b099e806a2ecee9cdplougher		if(progress_enabled)
18061b42101056befe25b5f19d5b099e806a2ecee9cdplougher			progress_bar(sym_count + dev_count +
1807d4204758f77acb5a371fa1487a755b76a05d5476plougher				fifo_count + cur_blocks, total_inodes -
1808d4204758f77acb5a371fa1487a755b76a05d5476plougher				total_files + total_blocks, columns);
1809eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
1810eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1811eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1812eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
18138888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid initialise_threads(int fragment_buffer_size, int data_buffer_size)
18148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
18158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int i;
18168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigset_t sigmask, old_mask;
18178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int all_buffers_size = fragment_buffer_size + data_buffer_size;
18188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigemptyset(&sigmask);
18208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigaddset(&sigmask, SIGINT);
18218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigaddset(&sigmask, SIGQUIT);
18228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
1823c435240f52b78b0ef498118727ba8dad186db26bplougher		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
1824c435240f52b78b0ef498118727ba8dad186db26bplougher			"\n");
18258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(processors == -1) {
18278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifndef linux
18288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int mib[2];
18298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		size_t len = sizeof(processors);
18308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[0] = CTL_HW;
18328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifdef HW_AVAILCPU
18338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_AVAILCPU;
18348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
18358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_NCPU;
18368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
18378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
1839d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("Failed to get number of available processors.  "
1840d4204758f77acb5a371fa1487a755b76a05d5476plougher				"Defaulting to 1\n");
18418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors = 1;
18428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
18438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
18449cc26b77a61fefdeb45f5c487c2bfdefd394b66fplougher		processors = sysconf(_SC_NPROCESSORS_ONLN);
18458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
18468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
18478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18486697cff2155192a3e0c182a3cef046ebf215ac32plougher	thread = malloc((3 + processors) * sizeof(pthread_t));
18496697cff2155192a3e0c182a3cef046ebf215ac32plougher	if(thread == NULL)
18508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
1851eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	deflator_thread = &thread[3];
18528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	to_reader = queue_init(all_buffers_size);
18548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	to_deflate = queue_init(all_buffers_size);
1855eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	to_writer = queue_init(1000);
18568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	from_writer = queue_init(1);
18578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	fragment_cache = cache_init(block_size, fragment_buffer_size);
18588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data_cache = cache_init(block_size, data_buffer_size);
18598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[0], NULL, reader, NULL);
18608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[1], NULL, writer, NULL);
1861eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_create(&thread[2], NULL, progress_thread, NULL);
18628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&fragment_mutex, NULL);
18638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(i = 0; i < processors; i++) {
1865c435240f52b78b0ef498118727ba8dad186db26bplougher		if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
1866c435240f52b78b0ef498118727ba8dad186db26bplougher				 0)
18678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("Failed to create thread\n");
18688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
18698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	printf("Parallel unsquashfs: Using %d processor%s\n", processors,
18718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors == 1 ? "" : "s");
18728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
1874c435240f52b78b0ef498118727ba8dad186db26bplougher		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
1875c435240f52b78b0ef498118727ba8dad186db26bplougher			"\n");
18768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
18778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18791b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid enable_progress_bar()
18801b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
18811b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
18821b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_enabled = TRUE;
18831b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
18841b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
18851b42101056befe25b5f19d5b099e806a2ecee9cdplougher
18861b42101056befe25b5f19d5b099e806a2ecee9cdplougher
18871b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid disable_progress_bar()
18881b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
18891b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
18901b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_enabled = FALSE;
18911b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
18921b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
18931b42101056befe25b5f19d5b099e806a2ecee9cdplougher
18941b42101056befe25b5f19d5b099e806a2ecee9cdplougher
1895eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar()
1896eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
18971b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
1898eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_cond_signal(&progress_wait);
18991b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
1900eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1901eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1902eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1903eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns)
1904eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1905eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	char rotate_list[] = { '|', '/', '-', '\\' };
1906b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	int max_digits, used, hashes, spaces;
1907dce832998340bea4236fddb5ba1525121044ce18plougher	static int tty = -1;
1908eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1909b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	if(max == 0)
1910b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher		return;
1911b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher
1912b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	max_digits = floor(log10(max)) + 1;
1913b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	used = max_digits * 2 + 11;
1914b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	hashes = (current * (columns - used)) / max;
1915b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	spaces = columns - used - hashes;
1916b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher
1917eaf639366792995c36ae7295bddf534f6f416643plougher	if((current > max) || (columns - used < 0))
1918eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		return;
1919eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1920dce832998340bea4236fddb5ba1525121044ce18plougher	if(tty == -1)
1921dce832998340bea4236fddb5ba1525121044ce18plougher		tty = isatty(STDOUT_FILENO);
1922dce832998340bea4236fddb5ba1525121044ce18plougher	if(!tty) {
1923dce832998340bea4236fddb5ba1525121044ce18plougher		static long long previous = -1;
1924dce832998340bea4236fddb5ba1525121044ce18plougher
19250a0d045642e8e413f90b770539193d3fd1522786plougher		/*
19260a0d045642e8e413f90b770539193d3fd1522786plougher		 * Updating much more frequently than this results in huge
19270a0d045642e8e413f90b770539193d3fd1522786plougher		 * log files.
19280a0d045642e8e413f90b770539193d3fd1522786plougher		 */
1929dce832998340bea4236fddb5ba1525121044ce18plougher		if((current % 100) != 0 && current != max)
1930dce832998340bea4236fddb5ba1525121044ce18plougher			return;
1931dce832998340bea4236fddb5ba1525121044ce18plougher		/* Don't update just to rotate the spinner. */
1932dce832998340bea4236fddb5ba1525121044ce18plougher		if(current == previous)
1933dce832998340bea4236fddb5ba1525121044ce18plougher			return;
1934dce832998340bea4236fddb5ba1525121044ce18plougher		previous = current;
1935dce832998340bea4236fddb5ba1525121044ce18plougher	}
1936dce832998340bea4236fddb5ba1525121044ce18plougher
1937eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("\r[");
1938eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1939eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while (hashes --)
1940eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar('=');
1941eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1942eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	putchar(rotate_list[rotate]);
1943eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1944eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(spaces --)
1945eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar(' ');
1946eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1947eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("] %*lld/%*lld", max_digits, current, max_digits, max);
1948eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf(" %3lld%%", current * 100 / max);
1949eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	fflush(stdout);
1950eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1951eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1952eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1953443c15812032991c98b33b5424b17bcd55fe3575plougher#define VERSION() \
19540ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher	printf("unsquashfs version 4.2-CVS (2012/01/12)\n");\
19550ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher	printf("copyright (C) 2012 Phillip Lougher "\
1956e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		"<phillip@lougher.demon.co.uk>\n\n");\
1957e3206fad5b70e7e0527db2a627ad26616a8a2429plougher    	printf("This program is free software; you can redistribute it and/or"\
1958d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
1959e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("modify it under the terms of the GNU General Public License"\
1960d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
1961e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("as published by the Free Software Foundation; either version "\
1962e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		"2,\n");\
1963e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("or (at your option) any later version.\n\n");\
1964e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("This program is distributed in the hope that it will be "\
1965e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		"useful,\n");\
1966d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of"\
1967d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
1968d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the"\
1969d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
1970443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("GNU General Public License for more details.\n");
1971443c15812032991c98b33b5424b17bcd55fe3575plougherint main(int argc, char *argv[])
1972443c15812032991c98b33b5424b17bcd55fe3575plougher{
1973443c15812032991c98b33b5424b17bcd55fe3575plougher	char *dest = "squashfs-root";
1974b624936abba03d38b7e9245c647339d8f6f34274plougher	int i, stat_sys = FALSE, version = FALSE;
1975545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	int n;
1976a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *paths = NULL;
1977a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathname *path = NULL;
1978ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int fragment_buffer_size = FRAGMENT_BUFFER_DEFAULT;
1979ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int data_buffer_size = DATA_BUFFER_DEFAULT;
19800cf5c297bec42c7c220d2825f12f9499f2293279plougher	char *b;
1981443c15812032991c98b33b5424b17bcd55fe3575plougher
19821b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_init(&screen_mutex, NULL);
1983545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	root_process = geteuid() == 0;
1984545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	if(root_process)
19859dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		umask(0);
19869dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
1987443c15812032991c98b33b5424b17bcd55fe3575plougher	for(i = 1; i < argc; i++) {
1988443c15812032991c98b33b5424b17bcd55fe3575plougher		if(*argv[i] != '-')
1989443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1990d4204758f77acb5a371fa1487a755b76a05d5476plougher		if(strcmp(argv[i], "-version") == 0 ||
1991d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-v") == 0) {
1992443c15812032991c98b33b5424b17bcd55fe3575plougher			VERSION();
1993443c15812032991c98b33b5424b17bcd55fe3575plougher			version = TRUE;
1994d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-info") == 0 ||
1995d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-i") == 0)
1996443c15812032991c98b33b5424b17bcd55fe3575plougher			info = TRUE;
1997c435240f52b78b0ef498118727ba8dad186db26bplougher		else if(strcmp(argv[i], "-ls") == 0 ||
1998c435240f52b78b0ef498118727ba8dad186db26bplougher				strcmp(argv[i], "-l") == 0)
1999443c15812032991c98b33b5424b17bcd55fe3575plougher			lsonly = TRUE;
2000d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-no-progress") == 0 ||
2001d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-n") == 0)
2002296d7d8a68e33341d68f4354b5e1fe2f3aa275a6plougher			progress = FALSE;
200331638061a6de0cb89093672aa71ddeb42f2eb28aplougher		else if(strcmp(argv[i], "-no-xattrs") == 0 ||
200431638061a6de0cb89093672aa71ddeb42f2eb28aplougher				strcmp(argv[i], "-no") == 0)
200531638061a6de0cb89093672aa71ddeb42f2eb28aplougher			no_xattrs = TRUE;
2006df9d38a515489c2c573754ad81abd230dfd8b1f0plougher		else if(strcmp(argv[i], "-xattrs") == 0 ||
2007df9d38a515489c2c573754ad81abd230dfd8b1f0plougher				strcmp(argv[i], "-x") == 0)
2008df9d38a515489c2c573754ad81abd230dfd8b1f0plougher			no_xattrs = FALSE;
2009d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-dest") == 0 ||
2010d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-d") == 0) {
201171add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
2012d4204758f77acb5a371fa1487a755b76a05d5476plougher				fprintf(stderr, "%s: -dest missing filename\n",
2013d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
201471add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
201571add234b27054974d5e29f95b3fab3072792a62plougher			}
2016443c15812032991c98b33b5424b17bcd55fe3575plougher			dest = argv[i];
2017d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-processors") == 0 ||
2018d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-p") == 0) {
2019c435240f52b78b0ef498118727ba8dad186db26bplougher			if((++i == argc) ||
2020c435240f52b78b0ef498118727ba8dad186db26bplougher					(processors = strtol(argv[i], &b, 10),
2021d4204758f77acb5a371fa1487a755b76a05d5476plougher					*b != '\0')) {
2022d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -processors missing or invalid "
2023d4204758f77acb5a371fa1487a755b76a05d5476plougher					"processor number\n", argv[0]);
20240cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
20250cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
20260cf5c297bec42c7c220d2825f12f9499f2293279plougher			if(processors < 1) {
2027d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -processors should be 1 or larger\n",
2028d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
20290cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
20300cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
2031d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-data-queue") == 0 ||
2032d4204758f77acb5a371fa1487a755b76a05d5476plougher					 strcmp(argv[i], "-da") == 0) {
2033c435240f52b78b0ef498118727ba8dad186db26bplougher			if((++i == argc) ||
2034c435240f52b78b0ef498118727ba8dad186db26bplougher					(data_buffer_size = strtol(argv[i], &b,
2035d4204758f77acb5a371fa1487a755b76a05d5476plougher					 10), *b != '\0')) {
2036c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("%s: -data-queue missing or invalid "
2037c435240f52b78b0ef498118727ba8dad186db26bplougher					"queue size\n", argv[0]);
2038ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2039ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2040ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(data_buffer_size < 1) {
2041d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -data-queue should be 1 Mbyte or "
2042d4204758f77acb5a371fa1487a755b76a05d5476plougher					"larger\n", argv[0]);
2043ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2044ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2045d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-frag-queue") == 0 ||
2046d4204758f77acb5a371fa1487a755b76a05d5476plougher					strcmp(argv[i], "-fr") == 0) {
2047c435240f52b78b0ef498118727ba8dad186db26bplougher			if((++i == argc) ||
2048c435240f52b78b0ef498118727ba8dad186db26bplougher					(fragment_buffer_size = strtol(argv[i],
2049d4204758f77acb5a371fa1487a755b76a05d5476plougher					 &b, 10), *b != '\0')) {
2050c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("%s: -frag-queue missing or invalid "
2051c435240f52b78b0ef498118727ba8dad186db26bplougher					"queue size\n", argv[0]);
2052ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2053ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2054ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(fragment_buffer_size < 1) {
2055d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -frag-queue should be 1 Mbyte or "
2056d4204758f77acb5a371fa1487a755b76a05d5476plougher					"larger\n", argv[0]);
2057ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2058ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2059d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-force") == 0 ||
2060d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-f") == 0)
2061a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			force = TRUE;
2062d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-stat") == 0 ||
2063d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-s") == 0)
2064b624936abba03d38b7e9245c647339d8f6f34274plougher			stat_sys = TRUE;
2065d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-lls") == 0 ||
2066d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-ll") == 0) {
20679baf35a00f38816d2054deb70184943d0686d03eplougher			lsonly = TRUE;
20689baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
2069d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-linfo") == 0 ||
2070d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-li") == 0) {
20719baf35a00f38816d2054deb70184943d0686d03eplougher			info = TRUE;
20729baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
2073d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-ef") == 0 ||
2074d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-e") == 0) {
207571add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
2076d4204758f77acb5a371fa1487a755b76a05d5476plougher				fprintf(stderr, "%s: -ef missing filename\n",
2077d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
207871add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
207971add234b27054974d5e29f95b3fab3072792a62plougher			}
2080a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			path = process_extract_files(path, argv[i]);
2081d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-regex") == 0 ||
2082d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-r") == 0)
20834dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			use_regex = TRUE;
20844dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		else
2085b624936abba03d38b7e9245c647339d8f6f34274plougher			goto options;
2086443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2087443c15812032991c98b33b5424b17bcd55fe3575plougher
2088feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher	if(lsonly || info)
2089feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher		progress = FALSE;
2090feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher
2091bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher#ifdef SQUASHFS_TRACE
2092bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher	progress = FALSE;
2093bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher#endif
2094bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher
2095443c15812032991c98b33b5424b17bcd55fe3575plougher	if(i == argc) {
2096443c15812032991c98b33b5424b17bcd55fe3575plougher		if(!version) {
2097443c15812032991c98b33b5424b17bcd55fe3575plougheroptions:
2098d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("SYNTAX: %s [options] filesystem [directories or "
2099d4204758f77acb5a371fa1487a755b76a05d5476plougher				"files to extract]\n", argv[0]);
2100d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-v[ersion]\t\tprint version, licence and "
2101d4204758f77acb5a371fa1487a755b76a05d5476plougher				"copyright information\n");
2102d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-d[est] <pathname>\tunsquash to <pathname>, "
2103d4204758f77acb5a371fa1487a755b76a05d5476plougher				"default \"squashfs-root\"\n");
2104c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-n[o-progress]\t\tdon't display the progress "
2105c435240f52b78b0ef498118727ba8dad186db26bplougher				"bar\n");
2106df9d38a515489c2c573754ad81abd230dfd8b1f0plougher			ERROR("\t-no[-xattrs]\t\tdon't extract xattrs in file system"
2107df9d38a515489c2c573754ad81abd230dfd8b1f0plougher				NOXOPT_STR"\n");
2108df9d38a515489c2c573754ad81abd230dfd8b1f0plougher			ERROR("\t-x[attrs]\t\textract xattrs in file system"
2109df9d38a515489c2c573754ad81abd230dfd8b1f0plougher				XOPT_STR "\n");
2110c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-p[rocessors] <number>\tuse <number> "
2111c435240f52b78b0ef498118727ba8dad186db26bplougher				"processors.  By default will use\n");
2112c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\tnumber of processors available\n");
2113c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-i[nfo]\t\t\tprint files as they are "
2114c435240f52b78b0ef498118727ba8dad186db26bplougher				"unsquashed\n");
2115c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-li[nfo]\t\tprint files as they are "
2116c435240f52b78b0ef498118727ba8dad186db26bplougher				"unsquashed with file\n");
2117c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\tattributes (like ls -l output)\n");
2118d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-l[s]\t\t\tlist filesystem, but don't unsquash"
2119d4204758f77acb5a371fa1487a755b76a05d5476plougher				"\n");
2120c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-ll[s]\t\t\tlist filesystem with file "
2121c435240f52b78b0ef498118727ba8dad186db26bplougher				"attributes (like\n");
2122c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\tls -l output), but don't unsquash\n");
2123c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-f[orce]\t\tif file already exists then "
2124c435240f52b78b0ef498118727ba8dad186db26bplougher				"overwrite\n");
2125d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-s[tat]\t\t\tdisplay filesystem superblock "
2126d4204758f77acb5a371fa1487a755b76a05d5476plougher				"information\n");
2127d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-e[f] <extract file>\tlist of directories or "
2128d4204758f77acb5a371fa1487a755b76a05d5476plougher				"files to extract.\n\t\t\t\tOne per line\n");
2129c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-da[ta-queue] <size>\tSet data queue to "
2130c435240f52b78b0ef498118727ba8dad186db26bplougher				"<size> Mbytes.  Default %d\n\t\t\t\tMbytes\n",
2131d4204758f77acb5a371fa1487a755b76a05d5476plougher				DATA_BUFFER_DEFAULT);
21328bc376ba1f7110fb88989e5134b74aa8412fb00eplougher			ERROR("\t-fr[ag-queue] <size>\tSet fragment queue to "
2133d56f6723626a391b473c2c023b628abcd8ed31e3Phillip Lougher				"<size> Mbytes.  Default\n\t\t\t\t%d Mbytes\n",
2134d4204758f77acb5a371fa1487a755b76a05d5476plougher				FRAGMENT_BUFFER_DEFAULT);
2135c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-r[egex]\t\ttreat extract names as POSIX "
2136c435240f52b78b0ef498118727ba8dad186db26bplougher				"regular expressions\n");
2137c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\trather than use the default shell "
2138c435240f52b78b0ef498118727ba8dad186db26bplougher				"wildcard\n\t\t\t\texpansion (globbing)\n");
2139076b053e2cce5c9172b4f385e866c2e606712a32plougher			ERROR("\nDecompressors available:\n");
2140076b053e2cce5c9172b4f385e866c2e606712a32plougher			display_compressors("", "");
2141443c15812032991c98b33b5424b17bcd55fe3575plougher		}
2142443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2143443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2144443c15812032991c98b33b5424b17bcd55fe3575plougher
214571add234b27054974d5e29f95b3fab3072792a62plougher	for(n = i + 1; n < argc; n++)
2146a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, argv[n], argv[n]);
2147b54566f5c433764830c29c83151691d0034de094plougher
2148443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fd = open(argv[i], O_RDONLY)) == -1) {
2149d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("Could not open %s, because %s\n", argv[i],
2150d4204758f77acb5a371fa1487a755b76a05d5476plougher			strerror(errno));
2151443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2152443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2153443c15812032991c98b33b5424b17bcd55fe3575plougher
215402bc3bcabf2b219f63961f07293b83629948f026plougher	if(read_super(argv[i]) == FALSE)
2155443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2156443c15812032991c98b33b5424b17bcd55fe3575plougher
2157b624936abba03d38b7e9245c647339d8f6f34274plougher	if(stat_sys) {
2158b624936abba03d38b7e9245c647339d8f6f34274plougher		squashfs_stat(argv[i]);
2159b624936abba03d38b7e9245c647339d8f6f34274plougher		exit(0);
2160b624936abba03d38b7e9245c647339d8f6f34274plougher	}
2161b624936abba03d38b7e9245c647339d8f6f34274plougher
2162f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher	if(!comp->supported) {
2163f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher		ERROR("Filesystem uses %s compression, this is "
2164f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher			"unsupported by this version\n", comp->name);
2165f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher		ERROR("Decompressors available:\n");
2166f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher		display_compressors("", "");
2167f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher		exit(1);
2168f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher	}
2169f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher
217027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	block_size = sBlk.s.block_size;
217127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	block_log = sBlk.s.block_log;
2172ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2173ae271cc93e3684d5314bcdc45b631e497ae43166plougher	fragment_buffer_size <<= 20 - block_log;
2174ae271cc93e3684d5314bcdc45b631e497ae43166plougher	data_buffer_size <<= 20 - block_log;
21758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	initialise_threads(fragment_buffer_size, data_buffer_size);
21768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
217744a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	fragment_data = malloc(block_size);
217844a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(fragment_data == NULL)
2179443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate fragment_data\n");
2180443c15812032991c98b33b5424b17bcd55fe3575plougher
218144a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	file_data = malloc(block_size);
218244a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(file_data == NULL)
2183443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate file_data");
2184443c15812032991c98b33b5424b17bcd55fe3575plougher
218544a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	data = malloc(block_size);
218644a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(data == NULL)
2187eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		EXIT_UNSQUASH("failed to allocate data\n");
2188443c15812032991c98b33b5424b17bcd55fe3575plougher
218944a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	created_inode = malloc(sBlk.s.inodes * sizeof(char *));
219044a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(created_inode == NULL)
2191443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate created_inode\n");
2192443c15812032991c98b33b5424b17bcd55fe3575plougher
219327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	memset(created_inode, 0, sBlk.s.inodes * sizeof(char *));
2194443c15812032991c98b33b5424b17bcd55fe3575plougher
21951a7e7e871169a6cb6e3470a50b33db83830886e2plougher	if(s_ops.read_uids_guids() == FALSE)
21961a7e7e871169a6cb6e3470a50b33db83830886e2plougher		EXIT_UNSQUASH("failed to uid/gid table\n");
2197ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2198cce13b2f8f73a4224f9dcfe203c992a09f22c6bcplougher	if(s_ops.read_fragment_table() == FALSE)
2199cce13b2f8f73a4224f9dcfe203c992a09f22c6bcplougher		EXIT_UNSQUASH("failed to read fragment table\n");
2200ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
220127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	uncompress_inode_table(sBlk.s.inode_table_start,
220227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.directory_table_start);
2203ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
220427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	uncompress_directory_table(sBlk.s.directory_table_start,
220527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.fragment_table_start);
2206443c15812032991c98b33b5424b17bcd55fe3575plougher
220731638061a6de0cb89093672aa71ddeb42f2eb28aplougher	if(no_xattrs)
220831638061a6de0cb89093672aa71ddeb42f2eb28aplougher		sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK;
220931638061a6de0cb89093672aa71ddeb42f2eb28aplougher
22108935dc25479321709c74c2f8214cf5365669100eplougher	if(read_xattrs_from_disk(fd, &sBlk.s) == 0)
22118935dc25479321709c74c2f8214cf5365669100eplougher		EXIT_UNSQUASH("failed to read the xattr table\n");
22128935dc25479321709c74c2f8214cf5365669100eplougher
2213a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if(path) {
2214a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = init_subdir();
2215a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = add_subdir(paths, path);
2216a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
2217a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
221827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	pre_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode),
221927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths);
2220eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
222127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	memset(created_inode, 0, sBlk.s.inodes * sizeof(char *));
22229b58176e667b67770569c9076a410b27aaa3bcf5plougher	inode_number = 1;
2223eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2224c435240f52b78b0ef498118727ba8dad186db26bplougher	printf("%d inodes (%d blocks) to write\n\n", total_inodes,
2225c435240f52b78b0ef498118727ba8dad186db26bplougher		total_inodes - total_files + total_blocks);
2226eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
22271b42101056befe25b5f19d5b099e806a2ecee9cdplougher	if(progress)
22281b42101056befe25b5f19d5b099e806a2ecee9cdplougher		enable_progress_bar();
22291b42101056befe25b5f19d5b099e806a2ecee9cdplougher
223027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode),
223127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths);
2232443c15812032991c98b33b5424b17bcd55fe3575plougher
22338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_put(to_writer, NULL);
22348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_get(from_writer);
22358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
22365c7885bc293ab675812fd77a05f59c2917e3e8b4plougher	if(progress) {
22371b42101056befe25b5f19d5b099e806a2ecee9cdplougher		disable_progress_bar();
22385c7885bc293ab675812fd77a05f59c2917e3e8b4plougher		progress_bar(sym_count + dev_count + fifo_count + cur_blocks,
22391b42101056befe25b5f19d5b099e806a2ecee9cdplougher			total_inodes - total_files + total_blocks, columns);
22405c7885bc293ab675812fd77a05f59c2917e3e8b4plougher	}
2241eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2242443c15812032991c98b33b5424b17bcd55fe3575plougher	if(!lsonly) {
2243443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("\n");
2244443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d files\n", file_count);
2245443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d directories\n", dir_count);
2246443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d symlinks\n", sym_count);
2247443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d devices\n", dev_count);
2248443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d fifos\n", fifo_count);
2249443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2250eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
22519dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	return 0;
2252443c15812032991c98b33b5424b17bcd55fe3575plougher}
2253