unsquashfs.c revision 01b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6
12f60990fb0352f7a30e0281a066458dbf033618bplougher/*
2443c15812032991c98b33b5424b17bcd55fe3575plougher * Unsquash a squashfs filesystem.  This is a highly compressed read only filesystem.
3443c15812032991c98b33b5424b17bcd55fe3575plougher *
4d9b631e9e82c9e0d0e14b7f3d0f2965c523b113dplougher * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
579df93becb68081effabebba3006c794be308598plougher * Phillip Lougher <phillip@lougher.demon.co.uk>
6443c15812032991c98b33b5424b17bcd55fe3575plougher *
7443c15812032991c98b33b5424b17bcd55fe3575plougher * This program is free software; you can redistribute it and/or
8443c15812032991c98b33b5424b17bcd55fe3575plougher * modify it under the terms of the GNU General Public License
9443c15812032991c98b33b5424b17bcd55fe3575plougher * as published by the Free Software Foundation; either version 2,
10443c15812032991c98b33b5424b17bcd55fe3575plougher * or (at your option) any later version.
11443c15812032991c98b33b5424b17bcd55fe3575plougher *
12443c15812032991c98b33b5424b17bcd55fe3575plougher * This program is distributed in the hope that it will be useful,
13443c15812032991c98b33b5424b17bcd55fe3575plougher * but WITHOUT ANY WARRANTY; without even the implied warranty of
14443c15812032991c98b33b5424b17bcd55fe3575plougher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15443c15812032991c98b33b5424b17bcd55fe3575plougher * GNU General Public License for more details.
16443c15812032991c98b33b5424b17bcd55fe3575plougher *
17443c15812032991c98b33b5424b17bcd55fe3575plougher * You should have received a copy of the GNU General Public License
18443c15812032991c98b33b5424b17bcd55fe3575plougher * along with this program; if not, write to the Free Software
19443c15812032991c98b33b5424b17bcd55fe3575plougher * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20443c15812032991c98b33b5424b17bcd55fe3575plougher *
21ed5124f016834932db2c63d60d259d846171c216plougher * unsquashfs.c
22443c15812032991c98b33b5424b17bcd55fe3575plougher */
23443c15812032991c98b33b5424b17bcd55fe3575plougher
24ed5124f016834932db2c63d60d259d846171c216plougher#include "unsquashfs.h"
256490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "squashfs_swap.h"
266490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "squashfs_compat.h"
276490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "read_fs.h"
288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *fragment_cache, *data_cache;
308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *to_reader, *to_deflate, *to_writer, *from_writer;
318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherpthread_t *thread, *deflator_thread;
328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherpthread_mutex_t	fragment_mutex;
338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* user options that control parallelisation */
358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherint processors = -1;
368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
376490378e5b5e8dc058daf28423a7465699a6ba7bplougherstruct super_block sBlk;
3802bc3bcabf2b219f63961f07293b83629948f026ploughersquashfs_operations s_ops;
3902bc3bcabf2b219f63961f07293b83629948f026plougher
409dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0,
419dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	dev_count = 0, fifo_count = 0;
42443c15812032991c98b33b5424b17bcd55fe3575plougherchar *inode_table = NULL, *directory_table = NULL;
43443c15812032991c98b33b5424b17bcd55fe3575plougherstruct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536];
44443c15812032991c98b33b5424b17bcd55fe3575plougherint fd;
45443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int *uid_table, *guid_table;
46443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int cached_frag = SQUASHFS_INVALID_FRAG;
47443c15812032991c98b33b5424b17bcd55fe3575plougherchar *fragment_data;
48443c15812032991c98b33b5424b17bcd55fe3575plougherchar *file_data;
49443c15812032991c98b33b5424b17bcd55fe3575plougherchar *data;
50443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int block_size;
51ae271cc93e3684d5314bcdc45b631e497ae43166plougherunsigned int block_log;
52d4204758f77acb5a371fa1487a755b76a05d5476plougherint lsonly = FALSE, info = FALSE, force = FALSE, short_ls = TRUE;
53d4204758f77acb5a371fa1487a755b76a05d5476plougherint use_regex = FALSE;
54443c15812032991c98b33b5424b17bcd55fe3575plougherchar **created_inode;
559dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint root_process;
56eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint columns;
57eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint rotate = 0;
581b42101056befe25b5f19d5b099e806a2ecee9cdplougherpthread_mutex_t	screen_mutex;
59eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherpthread_cond_t progress_wait;
601b42101056befe25b5f19d5b099e806a2ecee9cdplougherint progress = TRUE, progress_enabled = FALSE;
61eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int total_blocks = 0, total_files = 0, total_inodes = 0;
62eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int cur_blocks = 0;
63ed5124f016834932db2c63d60d259d846171c216plougherint inode_number = 1;
64443c15812032991c98b33b5424b17bcd55fe3575plougher
65476dcb48b24efff22caa970f000e151f1b28918dplougherint lookup_type[] = {
66476dcb48b24efff22caa970f000e151f1b28918dplougher	0,
67476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
68476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFREG,
69476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFLNK,
70476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFBLK,
71476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFCHR,
72476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFIFO,
73476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFSOCK,
74476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
75eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFREG,
76eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFLNK,
77eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFBLK,
78eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFCHR,
79eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFIFO,
80eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFSOCK
81476dcb48b24efff22caa970f000e151f1b28918dplougher};
82476dcb48b24efff22caa970f000e151f1b28918dplougher
83476dcb48b24efff22caa970f000e151f1b28918dplougherstruct test table[] = {
84476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFSOCK, 0, 's' },
85476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFLNK, 0, 'l' },
86476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFBLK, 0, 'b' },
87476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFDIR, 0, 'd' },
88476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFCHR, 0, 'c' },
89476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFIFO, 0, 'p' },
90476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRUSR, S_IRUSR, 1, 'r' },
91476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWUSR, S_IWUSR, 2, 'w' },
92476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRGRP, S_IRGRP, 4, 'r' },
93476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWGRP, S_IWGRP, 5, 'w' },
94476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IROTH, S_IROTH, 7, 'r' },
95476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWOTH, S_IWOTH, 8, 'w' },
96476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR | S_ISUID, 3, 's' },
97476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_ISUID, 3, 'S' },
98476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR, 3, 'x' },
99476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP | S_ISGID, 6, 's' },
100476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_ISGID, 6, 'S' },
101476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP, 6, 'x' },
102476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH | S_ISVTX, 9, 't' },
103476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_ISVTX, 9, 'T' },
104476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH, 9, 'x' },
1058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	{ 0, 0, 0, 0}
1068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher};
1078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
108eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns);
109eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar();
110eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
111eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid sigwinch_handler()
112eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
113eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct winsize winsize;
114eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
115eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
116c27a3d72b339d80d38623a4ee5a42601338fb4c9plougher		if(isatty(STDOUT_FILENO))
117d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
118d4204758f77acb5a371fa1487a755b76a05d5476plougher				"columns\n");
119eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = 80;
120eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	} else
121eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = winsize.ws_col;
122eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
123eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1251b5f6c5145f284683a2628b73ab5f8a0e37dd7b4ploughervoid sigalrm_handler()
1261b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher{
1271b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	rotate = (rotate + 1) % 4;
1281b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher}
1291b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
1301b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
1318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *queue_init(int size)
1328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct queue *queue = malloc(sizeof(struct queue));
1348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(queue == NULL)
1368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return NULL;
1378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if((queue->data = malloc(sizeof(void *) * (size + 1))) == NULL) {
1398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		free(queue);
1408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return NULL;
1418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
1428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->size = size + 1;
1448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = queue->writep = 0;
1458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&queue->mutex, NULL);
1468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->empty, NULL);
1478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->full, NULL);
1488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return queue;
1508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1538888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid queue_put(struct queue *queue, void *data)
1548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int nextp;
1568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
1588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
1608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->full, &queue->mutex);
1618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->data[queue->writep] = data;
1638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->writep = nextp;
1648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->empty);
1658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
1668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1698888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *queue_get(struct queue *queue)
1708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	void *data;
1728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
1738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(queue->readp == queue->writep)
1758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->empty, &queue->mutex);
1768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data = queue->data[queue->readp];
1788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = (queue->readp + 1) % queue->size;
1798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->full);
1808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
1818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return data;
1838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
1878888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_hash_table(struct cache *cache, struct cache_entry *entry)
1888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(entry->block);
1908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_next = cache->hash_table[hash];
1928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->hash_table[hash] = entry;
1938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = NULL;
1948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
1958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry;
1968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2008888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_hash_table(struct cache *cache, struct cache_entry *entry)
2018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_prev)
2038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_prev->hash_next = entry->hash_next;
2048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	else
2058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->hash_table[CALCULATE_HASH(entry->block)] = entry->hash_next;
2068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
2078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry->hash_prev;
2088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = entry->hash_next = NULL;
2108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2148888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_free_list(struct cache *cache, struct cache_entry *entry)
2158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache->free_list) {
2178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next = cache->free_list;
2188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = cache->free_list->free_prev;
2198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev->free_next = entry;
2208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev = entry;
2218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
2228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = entry;
2238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = entry->free_next = entry;
2248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
2258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2298888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_free_list(struct cache *cache, struct cache_entry *entry)
2308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->free_prev == NULL && entry->free_next == NULL)
2328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* not in free list */
2338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return;
234222e49e257bccb10c0e608f071778f26fce28f01plougher	else if(entry->free_prev == entry && entry->free_next == entry) {
2358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* only this entry in the free list */
2368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = NULL;
2378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
2388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* more than one entry in the free list */
2398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next->free_prev = entry->free_prev;
2408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev->free_next = entry->free_next;
2418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->free_list == entry)
2428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->free_list = entry->free_next;
2438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
2448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->free_prev = entry->free_next = NULL;
2468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *cache_init(int buffer_size, int max_buffers)
2508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache *cache = malloc(sizeof(struct cache));
2528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache == NULL)
2548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return NULL;
2558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->max_buffers = max_buffers;
2578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->buffer_size = buffer_size;
2588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->count = 0;
2598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->free_list = NULL;
2608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536);
2618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_free = FALSE;
2628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_pending = FALSE;
2638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&cache->mutex, NULL);
2648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_free, NULL);
2658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_pending, NULL);
2668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return cache;
2688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache_entry *cache_get(struct cache *cache, long long block, int size)
2728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
273d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
274d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * Get a block out of the cache.  If the block isn't in the cache
275d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * it is added and queued to the reader() and deflate() threads for
276d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * reading * off disk and decompression.  The cache grows until max_blocks
277d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * is reached, once this occurs existing discarded blocks on the free list
278d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * are reused
279d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
2808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(block);
2818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *entry;
2828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&cache->mutex);
2848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
2868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->block == block)
2878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			break;
2888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry) {
290d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
291d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 *found the block in the cache, increment used count and
2928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * if necessary remove from free list so it won't disappear
2938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
2948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used ++;
2958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		remove_free_list(cache, entry);
2968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
2978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
298d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
299d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 * not in the cache
300d4204758f77acb5a371fa1487a755b76a05d5476plougher		 *
301d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * first try to allocate new block
302d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
3038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->count < cache->max_buffers) {
3048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = malloc(sizeof(struct cache_entry));
3058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(entry == NULL)
3068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				goto failed;
3078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data = malloc(cache->buffer_size);
3088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(entry->data == NULL) {
3098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				free(entry);
3108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				goto failed;
3118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
3128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache = cache;
3138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->free_prev = entry->free_next = NULL;
3148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->count ++;
3158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		} else {
316d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
317d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * try to get from free list
318d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
3198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			while(cache->free_list == NULL) {
3208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				cache->wait_free = TRUE;
321d4204758f77acb5a371fa1487a755b76a05d5476plougher				pthread_cond_wait(&cache->wait_for_free,
322d4204758f77acb5a371fa1487a755b76a05d5476plougher					&cache->mutex);
3238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
3248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = cache->free_list;
3258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_free_list(cache, entry);
3268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_hash_table(cache, entry);
3278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
3288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
329d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
330d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * initialise block and insert into the hash table
331d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
3328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->block = block;
3338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->size = size;
3348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used = 1;
3358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->error = FALSE;
3368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->pending = TRUE;
3378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_hash_table(cache, entry);
3388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
339d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
340d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * queue to read thread to read and ultimately (via the decompress
3418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * threads) decompress the buffer
3428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
3438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
3448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_reader, entry);
3458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return entry;
3488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherfailed:
3508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&cache->mutex);
3518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return NULL;
3528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3558888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_ready(struct cache_entry *entry, int error)
3568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
357d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
358d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * mark cache entry as being complete, reading and (if necessary)
3598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * decompression has taken place, and the buffer is valid for use.
3608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * If an error occurs reading or decompressing, the buffer also
361d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * becomes ready but with an error...
362d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
3638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
3648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->pending = FALSE;
3658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->error = error;
3668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
367d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
368d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * if the wait_pending flag is set, one or more threads may be waiting on
369d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * this buffer
370d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
3718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->cache->wait_pending) {
3728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = FALSE;
3738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_broadcast(&entry->cache->wait_for_pending);
3748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
3778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3808888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_wait(struct cache_entry *entry)
3818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
382d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
383d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * wait for this cache entry to become ready, when reading and (if
384d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * necessary) decompression has taken place
385d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
3868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
3878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(entry->pending) {
3898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = TRUE;
390d4204758f77acb5a371fa1487a755b76a05d5476plougher		pthread_cond_wait(&entry->cache->wait_for_pending,
391d4204758f77acb5a371fa1487a755b76a05d5476plougher			&entry->cache->mutex);
3928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
3958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3988888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_put(struct cache_entry *entry)
3998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
400d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
401d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * finished with this cache entry, once the usage count reaches zero it
4028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * can be reused and is put onto the free list.  As it remains accessible
4038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * via the hash table it can be found getting a new lease of life before it
404d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * is reused.
405d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
4068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
4078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->used --;
4098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->used == 0) {
4108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_free_list(entry->cache, entry);
4118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
412d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
413d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * if the wait_free flag is set, one or more threads may be waiting
414d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * on this buffer
415d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
4168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->cache->wait_free) {
4178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache->wait_free = FALSE;
4188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			pthread_cond_broadcast(&entry->cache->wait_for_free);
4198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
4208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
4218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
4238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
424476dcb48b24efff22caa970f000e151f1b28918dplougher
425476dcb48b24efff22caa970f000e151f1b28918dplougher
426476dcb48b24efff22caa970f000e151f1b28918dplougherchar *modestr(char *str, int mode)
427476dcb48b24efff22caa970f000e151f1b28918dplougher{
428476dcb48b24efff22caa970f000e151f1b28918dplougher	int i;
429476dcb48b24efff22caa970f000e151f1b28918dplougher
430476dcb48b24efff22caa970f000e151f1b28918dplougher	strcpy(str, "----------");
431476dcb48b24efff22caa970f000e151f1b28918dplougher
432476dcb48b24efff22caa970f000e151f1b28918dplougher	for(i = 0; table[i].mask != 0; i++) {
433476dcb48b24efff22caa970f000e151f1b28918dplougher		if((mode & table[i].mask) == table[i].value)
434476dcb48b24efff22caa970f000e151f1b28918dplougher			str[table[i].position] = table[i].mode;
435476dcb48b24efff22caa970f000e151f1b28918dplougher	}
436476dcb48b24efff22caa970f000e151f1b28918dplougher
437476dcb48b24efff22caa970f000e151f1b28918dplougher	return str;
438476dcb48b24efff22caa970f000e151f1b28918dplougher}
439476dcb48b24efff22caa970f000e151f1b28918dplougher
440476dcb48b24efff22caa970f000e151f1b28918dplougher
4413edfa57b6a463f7d441d995559143f4861d62e98plougher#define TOTALCHARS  25
4426f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint print_filename(char *pathname, struct inode *inode)
443476dcb48b24efff22caa970f000e151f1b28918dplougher{
4446f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	char str[11], dummy[100], dummy2[100], *userstr, *groupstr;
4456f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int padchars;
446476dcb48b24efff22caa970f000e151f1b28918dplougher	struct passwd *user;
447476dcb48b24efff22caa970f000e151f1b28918dplougher	struct group *group;
44888facddfd83e48a907b82210ddccbb4f84d80aecplougher	struct tm *t;
449476dcb48b24efff22caa970f000e151f1b28918dplougher
450476dcb48b24efff22caa970f000e151f1b28918dplougher	if(short_ls) {
451476dcb48b24efff22caa970f000e151f1b28918dplougher		printf("%s\n", pathname);
452476dcb48b24efff22caa970f000e151f1b28918dplougher		return 1;
453476dcb48b24efff22caa970f000e151f1b28918dplougher	}
454476dcb48b24efff22caa970f000e151f1b28918dplougher
4556f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((user = getpwuid(inode->uid)) == NULL) {
4566f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		sprintf(dummy, "%d", inode->uid);
4573edfa57b6a463f7d441d995559143f4861d62e98plougher		userstr = dummy;
4583edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
4593edfa57b6a463f7d441d995559143f4861d62e98plougher		userstr = user->pw_name;
4603edfa57b6a463f7d441d995559143f4861d62e98plougher
4616f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((group = getgrgid(inode->gid)) == NULL) {
4626f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		sprintf(dummy2, "%d", inode->gid);
4633edfa57b6a463f7d441d995559143f4861d62e98plougher		groupstr = dummy2;
4643edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
4653edfa57b6a463f7d441d995559143f4861d62e98plougher		groupstr = group->gr_name;
4663edfa57b6a463f7d441d995559143f4861d62e98plougher
4676f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	printf("%s %s/%s ", modestr(str, inode->mode), userstr, groupstr);
4683edfa57b6a463f7d441d995559143f4861d62e98plougher
4696f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(inode->mode & S_IFMT) {
4703edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFREG:
4713edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFDIR:
4723edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFSOCK:
4733edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFIFO:
4743edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFLNK:
4753edfa57b6a463f7d441d995559143f4861d62e98plougher			padchars = TOTALCHARS - strlen(userstr) - strlen(groupstr);
4763edfa57b6a463f7d441d995559143f4861d62e98plougher
477caf2f0f593c7f14a4e7e151eeeed773c72578f69plougher			printf("%*lld ", padchars > 0 ? padchars : 0, inode->data);
4783edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
4793edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFCHR:
4803edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFBLK:
4813edfa57b6a463f7d441d995559143f4861d62e98plougher			padchars = TOTALCHARS - strlen(userstr) - strlen(groupstr) - 7;
4823edfa57b6a463f7d441d995559143f4861d62e98plougher
483d4204758f77acb5a371fa1487a755b76a05d5476plougher			printf("%*s%3d,%3d ", padchars > 0 ? padchars : 0, " ",
484d4204758f77acb5a371fa1487a755b76a05d5476plougher				(int) inode->data >> 8, (int) inode->data & 0xff);
4853edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
4863edfa57b6a463f7d441d995559143f4861d62e98plougher	}
487476dcb48b24efff22caa970f000e151f1b28918dplougher
4886f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	t = localtime(&inode->time);
48988facddfd83e48a907b82210ddccbb4f84d80aecplougher
490d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("%d-%02d-%02d %02d:%02d %s", t->tm_year + 1900, t->tm_mon + 1,
491d4204758f77acb5a371fa1487a755b76a05d5476plougher		t->tm_mday, t->tm_hour, t->tm_min, pathname);
4926f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((inode->mode & S_IFMT) == S_IFLNK)
4936f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		printf(" -> %s", inode->symlink);
4943edfa57b6a463f7d441d995559143f4861d62e98plougher	printf("\n");
4953edfa57b6a463f7d441d995559143f4861d62e98plougher
496476dcb48b24efff22caa970f000e151f1b28918dplougher	return 1;
497476dcb48b24efff22caa970f000e151f1b28918dplougher}
498476dcb48b24efff22caa970f000e151f1b28918dplougher
499443c15812032991c98b33b5424b17bcd55fe3575plougher
500f404f4914fdb272a70e18664e8963d793cc90f44plougherint add_entry(struct hash_table_entry *hash_table[], long long start, int bytes)
501443c15812032991c98b33b5424b17bcd55fe3575plougher{
502443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
503443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
504443c15812032991c98b33b5424b17bcd55fe3575plougher
505443c15812032991c98b33b5424b17bcd55fe3575plougher	if((hash_table_entry = malloc(sizeof(struct hash_table_entry))) == NULL) {
506443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("add_hash: out of memory in malloc\n");
507443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
508443c15812032991c98b33b5424b17bcd55fe3575plougher	}
509443c15812032991c98b33b5424b17bcd55fe3575plougher
510443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->start = start;
511443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->bytes = bytes;
512443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->next = hash_table[hash];
513443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table[hash] = hash_table_entry;
514443c15812032991c98b33b5424b17bcd55fe3575plougher
515443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
516443c15812032991c98b33b5424b17bcd55fe3575plougher}
517443c15812032991c98b33b5424b17bcd55fe3575plougher
518443c15812032991c98b33b5424b17bcd55fe3575plougher
519f404f4914fdb272a70e18664e8963d793cc90f44plougherint lookup_entry(struct hash_table_entry *hash_table[], long long start)
520443c15812032991c98b33b5424b17bcd55fe3575plougher{
521443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
522443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
523443c15812032991c98b33b5424b17bcd55fe3575plougher
5249dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	for(hash_table_entry = hash_table[hash]; hash_table_entry;
5259dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				hash_table_entry = hash_table_entry->next)
5267a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher
527443c15812032991c98b33b5424b17bcd55fe3575plougher		if(hash_table_entry->start == start)
528443c15812032991c98b33b5424b17bcd55fe3575plougher			return hash_table_entry->bytes;
529443c15812032991c98b33b5424b17bcd55fe3575plougher
530443c15812032991c98b33b5424b17bcd55fe3575plougher	return -1;
531443c15812032991c98b33b5424b17bcd55fe3575plougher}
532443c15812032991c98b33b5424b17bcd55fe3575plougher
533443c15812032991c98b33b5424b17bcd55fe3575plougher
534443c15812032991c98b33b5424b17bcd55fe3575plougherint read_bytes(long long byte, int bytes, char *buff)
535443c15812032991c98b33b5424b17bcd55fe3575plougher{
536443c15812032991c98b33b5424b17bcd55fe3575plougher	off_t off = byte;
537d7f3de3408089ce187d8bc26f6072730c77628daplougher	int res, count;
538443c15812032991c98b33b5424b17bcd55fe3575plougher
539fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes);
540fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
541443c15812032991c98b33b5424b17bcd55fe3575plougher	if(lseek(fd, off, SEEK_SET) == -1) {
5425d415c6659faaa7a69c9baa7175610d889747142plougher		ERROR("Lseek failed because %s\n", strerror(errno));
543443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
544443c15812032991c98b33b5424b17bcd55fe3575plougher	}
545443c15812032991c98b33b5424b17bcd55fe3575plougher
546d7f3de3408089ce187d8bc26f6072730c77628daplougher	for(count = 0; count < bytes; count += res) {
547d7f3de3408089ce187d8bc26f6072730c77628daplougher		res = read(fd, buff + count, bytes - count);
548d7f3de3408089ce187d8bc26f6072730c77628daplougher		if(res < 1) {
549d7f3de3408089ce187d8bc26f6072730c77628daplougher			if(res == 0) {
550d7f3de3408089ce187d8bc26f6072730c77628daplougher				ERROR("Read on filesystem failed because EOF\n");
551d7f3de3408089ce187d8bc26f6072730c77628daplougher				return FALSE;
552d7f3de3408089ce187d8bc26f6072730c77628daplougher			} else if(errno != EINTR) {
553d7f3de3408089ce187d8bc26f6072730c77628daplougher				ERROR("Read on filesystem failed because %s\n",
554d7f3de3408089ce187d8bc26f6072730c77628daplougher						strerror(errno));
555d7f3de3408089ce187d8bc26f6072730c77628daplougher				return FALSE;
556d7f3de3408089ce187d8bc26f6072730c77628daplougher			} else
557d7f3de3408089ce187d8bc26f6072730c77628daplougher				res = 0;
558d7f3de3408089ce187d8bc26f6072730c77628daplougher		}
559443c15812032991c98b33b5424b17bcd55fe3575plougher	}
560443c15812032991c98b33b5424b17bcd55fe3575plougher
561443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
562443c15812032991c98b33b5424b17bcd55fe3575plougher}
563443c15812032991c98b33b5424b17bcd55fe3575plougher
564443c15812032991c98b33b5424b17bcd55fe3575plougher
56502bc3bcabf2b219f63961f07293b83629948f026plougherint read_block(long long start, long long *next, char *block)
566443c15812032991c98b33b5424b17bcd55fe3575plougher{
567443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned short c_byte;
568443c15812032991c98b33b5424b17bcd55fe3575plougher	int offset = 2;
569443c15812032991c98b33b5424b17bcd55fe3575plougher
570443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
571443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, 2, block) == FALSE)
572fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
573443c15812032991c98b33b5424b17bcd55fe3575plougher		((unsigned char *) &c_byte)[1] = block[0];
574443c15812032991c98b33b5424b17bcd55fe3575plougher		((unsigned char *) &c_byte)[0] = block[1];
575443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
576443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, 2, (char *)&c_byte) == FALSE)
577fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
578fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
579d4204758f77acb5a371fa1487a755b76a05d5476plougher	TRACE("read_block: block @0x%llx, %d %s bytes\n", start,
580d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ?
581d4204758f77acb5a371fa1487a755b76a05d5476plougher		"compressed" : "uncompressed");
582443c15812032991c98b33b5424b17bcd55fe3575plougher
58302bc3bcabf2b219f63961f07293b83629948f026plougher	if(SQUASHFS_CHECK_DATA(sBlk.flags))
584443c15812032991c98b33b5424b17bcd55fe3575plougher		offset = 3;
585443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED(c_byte)) {
586443c15812032991c98b33b5424b17bcd55fe3575plougher		char buffer[SQUASHFS_METADATA_SIZE];
587443c15812032991c98b33b5424b17bcd55fe3575plougher		int res;
588443c15812032991c98b33b5424b17bcd55fe3575plougher		unsigned long bytes = SQUASHFS_METADATA_SIZE;
589443c15812032991c98b33b5424b17bcd55fe3575plougher
590443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
591443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start + offset, c_byte, buffer) == FALSE)
592fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
593443c15812032991c98b33b5424b17bcd55fe3575plougher
594d4204758f77acb5a371fa1487a755b76a05d5476plougher		res = uncompress((unsigned char *) block, &bytes,
595d4204758f77acb5a371fa1487a755b76a05d5476plougher			(const unsigned char *) buffer, c_byte);
596545404219cdd79c1e06ac7d0698d02a15240c4c3plougher
597545404219cdd79c1e06ac7d0698d02a15240c4c3plougher		if(res != Z_OK) {
598443c15812032991c98b33b5424b17bcd55fe3575plougher			if(res == Z_MEM_ERROR)
599d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("zlib::uncompress failed, not enough memory"
600d4204758f77acb5a371fa1487a755b76a05d5476plougher					"\n");
601443c15812032991c98b33b5424b17bcd55fe3575plougher			else if(res == Z_BUF_ERROR)
602d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("zlib::uncompress failed, not enough room "
603d4204758f77acb5a371fa1487a755b76a05d5476plougher					"in output buffer\n");
604443c15812032991c98b33b5424b17bcd55fe3575plougher			else
605d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("zlib::uncompress failed, unknown error "
606d4204758f77acb5a371fa1487a755b76a05d5476plougher					"%d\n", res);
607fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
608443c15812032991c98b33b5424b17bcd55fe3575plougher		}
609443c15812032991c98b33b5424b17bcd55fe3575plougher		if(next)
610443c15812032991c98b33b5424b17bcd55fe3575plougher			*next = start + offset + c_byte;
611443c15812032991c98b33b5424b17bcd55fe3575plougher		return bytes;
612443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
613443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
614443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(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{
629443c15812032991c98b33b5424b17bcd55fe3575plougher	int res;
630443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned long bytes = block_size;
631443c15812032991c98b33b5424b17bcd55fe3575plougher	int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
632443c15812032991c98b33b5424b17bcd55fe3575plougher
633d4204758f77acb5a371fa1487a755b76a05d5476plougher	TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start,
634d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte),
635d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_COMPRESSED_BLOCK(c_byte) ? "compressed" : "uncompressed");
636fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
637443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED_BLOCK(size)) {
638443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, c_byte, data) == FALSE)
63968ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
640443c15812032991c98b33b5424b17bcd55fe3575plougher
641d4204758f77acb5a371fa1487a755b76a05d5476plougher		res = uncompress((unsigned char *) block, &bytes,
642d4204758f77acb5a371fa1487a755b76a05d5476plougher			(const unsigned char *) data, c_byte);
643545404219cdd79c1e06ac7d0698d02a15240c4c3plougher
644545404219cdd79c1e06ac7d0698d02a15240c4c3plougher		if(res != Z_OK) {
645443c15812032991c98b33b5424b17bcd55fe3575plougher			if(res == Z_MEM_ERROR)
646d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("zlib::uncompress failed, not enough memory"
647d4204758f77acb5a371fa1487a755b76a05d5476plougher					"\n");
648443c15812032991c98b33b5424b17bcd55fe3575plougher			else if(res == Z_BUF_ERROR)
649d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("zlib::uncompress failed, not enough room "
650d4204758f77acb5a371fa1487a755b76a05d5476plougher					"in output buffer\n");
651443c15812032991c98b33b5424b17bcd55fe3575plougher			else
652d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("zlib::uncompress failed, unknown error "
653d4204758f77acb5a371fa1487a755b76a05d5476plougher					"%d\n", res);
65468ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
655443c15812032991c98b33b5424b17bcd55fe3575plougher		}
656443c15812032991c98b33b5424b17bcd55fe3575plougher
657443c15812032991c98b33b5424b17bcd55fe3575plougher		return bytes;
658443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
659443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, c_byte, block) == FALSE)
66068ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
661443c15812032991c98b33b5424b17bcd55fe3575plougher
662443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
663443c15812032991c98b33b5424b17bcd55fe3575plougher	}
66468ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher
66568ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougherfailed:
666d4204758f77acb5a371fa1487a755b76a05d5476plougher	ERROR("read_data_block: failed to read block @0x%llx, size %d\n", start,
667d4204758f77acb5a371fa1487a755b76a05d5476plougher		size);
66868ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher	return FALSE;
669443c15812032991c98b33b5424b17bcd55fe3575plougher}
670443c15812032991c98b33b5424b17bcd55fe3575plougher
671443c15812032991c98b33b5424b17bcd55fe3575plougher
67202bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_inode_table(long long start, long long end)
673443c15812032991c98b33b5424b17bcd55fe3575plougher{
674443c15812032991c98b33b5424b17bcd55fe3575plougher	int size = 0, bytes = 0, res;
675443c15812032991c98b33b5424b17bcd55fe3575plougher
67641da3230b2ac91a73f9190676f66b3d80b21c270plougher	TRACE("uncompress_inode_table: start %lld, end %lld\n", start, end);
677443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
678443c15812032991c98b33b5424b17bcd55fe3575plougher		if((size - bytes < SQUASHFS_METADATA_SIZE) &&
6799dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				((inode_table = realloc(inode_table, size +=
6809dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				SQUASHFS_METADATA_SIZE)) == NULL))
681d4204758f77acb5a371fa1487a755b76a05d5476plougher			EXIT_UNSQUASH("uncompress_inode_table: out of memory in "
682d4204758f77acb5a371fa1487a755b76a05d5476plougher				"realloc\n");
683443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("uncompress_inode_table: reading block 0x%llx\n", start);
684443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(inode_table_hash, start, bytes);
68502bc3bcabf2b219f63961f07293b83629948f026plougher		if((res = read_block(start, &start, inode_table + bytes)) == 0) {
686443c15812032991c98b33b5424b17bcd55fe3575plougher			free(inode_table);
687d4204758f77acb5a371fa1487a755b76a05d5476plougher			EXIT_UNSQUASH("uncompress_inode_table: failed to read "
688d4204758f77acb5a371fa1487a755b76a05d5476plougher				"block \n");
689443c15812032991c98b33b5424b17bcd55fe3575plougher		}
690443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
691443c15812032991c98b33b5424b17bcd55fe3575plougher	}
692443c15812032991c98b33b5424b17bcd55fe3575plougher}
693443c15812032991c98b33b5424b17bcd55fe3575plougher
694443c15812032991c98b33b5424b17bcd55fe3575plougher
695d4204758f77acb5a371fa1487a755b76a05d5476plougherint set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time,
696d4204758f77acb5a371fa1487a755b76a05d5476plougher	unsigned int set_mode)
697443c15812032991c98b33b5424b17bcd55fe3575plougher{
6986f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	struct utimbuf times = { time, time };
699443c15812032991c98b33b5424b17bcd55fe3575plougher
700443c15812032991c98b33b5424b17bcd55fe3575plougher	if(utime(pathname, &times) == -1) {
701d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("set_attributes: failed to set time on %s, because %s\n",
702d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
703443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
704443c15812032991c98b33b5424b17bcd55fe3575plougher	}
705443c15812032991c98b33b5424b17bcd55fe3575plougher
7069dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if(root_process) {
7076f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(chown(pathname, uid, guid) == -1) {
708d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("set_attributes: failed to change uid and gids on "
709d4204758f77acb5a371fa1487a755b76a05d5476plougher				"%s, because %s\n", pathname, strerror(errno));
710443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
711443c15812032991c98b33b5424b17bcd55fe3575plougher		}
7129dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	} else
7139dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		mode &= ~07000;
7149dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
7159dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) {
716d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("set_attributes: failed to change mode %s, because %s\n",
717d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
7189dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		return FALSE;
719443c15812032991c98b33b5424b17bcd55fe3575plougher	}
720443c15812032991c98b33b5424b17bcd55fe3575plougher
721443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
722443c15812032991c98b33b5424b17bcd55fe3575plougher}
723443c15812032991c98b33b5424b17bcd55fe3575plougher
724443c15812032991c98b33b5424b17bcd55fe3575plougher
7251c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougherint write_bytes(int fd, char *buff, int bytes)
7261c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher{
7271c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	int res, count;
7281c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
7291c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	for(count = 0; count < bytes; count += res) {
7301c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		res = write(fd, buff + count, bytes - count);
7311c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		if(res == -1) {
7321c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			if(errno != EINTR) {
7331c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher				ERROR("Write on output file failed because %s\n",
7341c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher						strerror(errno));
7351c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher				return -1;
7361c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			}
7371c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			res = 0;
7381c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		}
7391c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	}
7401c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
7411c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	return 0;
7421c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher}
7431c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
7441c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
745b9cee889506e674726856035dba52d5e1cceeb99plougherint lseek_broken = FALSE;
746c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougherchar *zero_data = NULL;
747b9cee889506e674726856035dba52d5e1cceeb99plougher
748c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougherint write_block(int file_fd, char *buffer, int size, int hole, int sparse)
749b9cee889506e674726856035dba52d5e1cceeb99plougher{
750b9cee889506e674726856035dba52d5e1cceeb99plougher	off_t off = hole;
751b9cee889506e674726856035dba52d5e1cceeb99plougher
752b9cee889506e674726856035dba52d5e1cceeb99plougher	if(hole) {
753c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if(sparse && lseek_broken == FALSE) {
754c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			 int error = lseek(file_fd, off, SEEK_CUR);
755c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			 if(error == -1)
756c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				/* failed to seek beyond end of file */
757c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				lseek_broken = TRUE;
758c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		}
759c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
760c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if((sparse == FALSE || lseek_broken) && zero_data == NULL) {
761b9cee889506e674726856035dba52d5e1cceeb99plougher			if((zero_data = malloc(block_size)) == NULL)
762d4204758f77acb5a371fa1487a755b76a05d5476plougher				EXIT_UNSQUASH("write_block: failed to alloc zero "
763d4204758f77acb5a371fa1487a755b76a05d5476plougher					"data block\n");
764b9cee889506e674726856035dba52d5e1cceeb99plougher			memset(zero_data, 0, block_size);
765b9cee889506e674726856035dba52d5e1cceeb99plougher		}
766c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
767c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if(sparse == FALSE || lseek_broken) {
768b9cee889506e674726856035dba52d5e1cceeb99plougher			int blocks = (hole + block_size -1) / block_size;
769b9cee889506e674726856035dba52d5e1cceeb99plougher			int avail_bytes, i;
770b9cee889506e674726856035dba52d5e1cceeb99plougher			for(i = 0; i < blocks; i++, hole -= avail_bytes) {
771d4204758f77acb5a371fa1487a755b76a05d5476plougher				avail_bytes = hole > block_size ? block_size :
772d4204758f77acb5a371fa1487a755b76a05d5476plougher					hole;
773d4204758f77acb5a371fa1487a755b76a05d5476plougher				if(write_bytes(file_fd, zero_data, avail_bytes)
774d4204758f77acb5a371fa1487a755b76a05d5476plougher						== -1)
775b9cee889506e674726856035dba52d5e1cceeb99plougher					goto failure;
776b9cee889506e674726856035dba52d5e1cceeb99plougher			}
777b9cee889506e674726856035dba52d5e1cceeb99plougher		}
778b9cee889506e674726856035dba52d5e1cceeb99plougher	}
779b9cee889506e674726856035dba52d5e1cceeb99plougher
7801c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	if(write_bytes(file_fd, buffer, size) == -1)
781b9cee889506e674726856035dba52d5e1cceeb99plougher		goto failure;
782b9cee889506e674726856035dba52d5e1cceeb99plougher
783b9cee889506e674726856035dba52d5e1cceeb99plougher	return TRUE;
784b9cee889506e674726856035dba52d5e1cceeb99plougher
785b9cee889506e674726856035dba52d5e1cceeb99plougherfailure:
786b9cee889506e674726856035dba52d5e1cceeb99plougher	return FALSE;
787b9cee889506e674726856035dba52d5e1cceeb99plougher}
788b9cee889506e674726856035dba52d5e1cceeb99plougher
7898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
79079df93becb68081effabebba3006c794be308598plougherint write_file(struct inode *inode, char *pathname)
791443c15812032991c98b33b5424b17bcd55fe3575plougher{
7928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	unsigned int file_fd, i;
793f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher	unsigned int *block_list;
79479df93becb68081effabebba3006c794be308598plougher	int file_end = inode->data / block_size;
79579df93becb68081effabebba3006c794be308598plougher	long long start = inode->start;
7968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct squashfs_file *file;
797443c15812032991c98b33b5424b17bcd55fe3575plougher
79879df93becb68081effabebba3006c794be308598plougher	TRACE("write_file: regular file, blocks %d\n", inode->blocks);
799443c15812032991c98b33b5424b17bcd55fe3575plougher
800d4204758f77acb5a371fa1487a755b76a05d5476plougher	file_fd = open(pathname, O_CREAT | O_WRONLY | (force ? O_TRUNC : 0),
801d4204758f77acb5a371fa1487a755b76a05d5476plougher		(mode_t) inode->mode & 0777);
802d4204758f77acb5a371fa1487a755b76a05d5476plougher	if(file_fd == -1) {
803d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("write_file: failed to create file %s, because %s\n",
804d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
805443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
806443c15812032991c98b33b5424b17bcd55fe3575plougher	}
807443c15812032991c98b33b5424b17bcd55fe3575plougher
80879df93becb68081effabebba3006c794be308598plougher	if((block_list = malloc(inode->blocks * sizeof(unsigned int))) == NULL)
8098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("write_file: unable to malloc block list\n");
810443c15812032991c98b33b5424b17bcd55fe3575plougher
81179df93becb68081effabebba3006c794be308598plougher	s_ops.read_block_list(block_list, inode->block_ptr, inode->blocks);
812443c15812032991c98b33b5424b17bcd55fe3575plougher
8138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if((file = malloc(sizeof(struct squashfs_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
8188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * file.  If the file has one or more blocks or a fragments they are queued
819d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * 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;
8308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_put(to_writer, file);
831443c15812032991c98b33b5424b17bcd55fe3575plougher
83279df93becb68081effabebba3006c794be308598plougher	for(i = 0; i < inode->blocks; i++) {
8338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
8348372232d2460411adaa2299c32a0a88665e44902plougher		struct file_entry *block = malloc(sizeof(struct file_entry));
8358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
8368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
8378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
8388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->offset = 0;
839d4204758f77acb5a371fa1487a755b76a05d5476plougher		block->size = i == file_end ? inode->data & (block_size - 1) :
840d4204758f77acb5a371fa1487a755b76a05d5476plougher			block_size;
8418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block_list[i] == 0) /* sparse file */
8428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			block->buffer = NULL;
8438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else {
844d4204758f77acb5a371fa1487a755b76a05d5476plougher			block->buffer = cache_get(data_cache, start,
845d4204758f77acb5a371fa1487a755b76a05d5476plougher				block_list[i]);
8468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(block->buffer == NULL)
8478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				EXIT_UNSQUASH("write_file: cache_get failed\n");
8488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			start += c_byte;
849443c15812032991c98b33b5424b17bcd55fe3575plougher		}
8508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
851443c15812032991c98b33b5424b17bcd55fe3575plougher	}
852443c15812032991c98b33b5424b17bcd55fe3575plougher
85379df93becb68081effabebba3006c794be308598plougher	if(inode->frag_bytes) {
8548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int size;
8558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		long long start;
8568372232d2460411adaa2299c32a0a88665e44902plougher		struct file_entry *block = malloc(sizeof(struct file_entry));
8578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
8588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
8598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
86079df93becb68081effabebba3006c794be308598plougher		s_ops.read_fragment(inode->fragment, &start, &size);
8618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->buffer = cache_get(fragment_cache, start, size);
8628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block->buffer == NULL)
8638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: cache_get failed\n");
86479df93becb68081effabebba3006c794be308598plougher		block->offset = inode->offset;
86579df93becb68081effabebba3006c794be308598plougher		block->size = inode->frag_bytes;
8668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
867b9cee889506e674726856035dba52d5e1cceeb99plougher	}
868b9cee889506e674726856035dba52d5e1cceeb99plougher
869b9cee889506e674726856035dba52d5e1cceeb99plougher	free(block_list);
870443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
871443c15812032991c98b33b5424b17bcd55fe3575plougher}
872476dcb48b24efff22caa970f000e151f1b28918dplougher
873476dcb48b24efff22caa970f000e151f1b28918dplougher
8746f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint create_inode(char *pathname, struct inode *i)
875443c15812032991c98b33b5424b17bcd55fe3575plougher{
8766f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	TRACE("create_inode: pathname %s\n", pathname);
877443c15812032991c98b33b5424b17bcd55fe3575plougher
8786f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if(created_inode[i->inode_number - 1]) {
879443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("create_inode: hard link\n");
8806013a30bd39550decc2546a47e5168e57bfcfde8plougher		if(force)
8816013a30bd39550decc2546a47e5168e57bfcfde8plougher			unlink(pathname);
8826013a30bd39550decc2546a47e5168e57bfcfde8plougher
8836f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(link(created_inode[i->inode_number - 1], pathname) == -1) {
884d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("create_inode: failed to create hardlink, because "
885d4204758f77acb5a371fa1487a755b76a05d5476plougher				"%s\n", strerror(errno));
886443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
887443c15812032991c98b33b5424b17bcd55fe3575plougher		}
888443c15812032991c98b33b5424b17bcd55fe3575plougher
889443c15812032991c98b33b5424b17bcd55fe3575plougher		return TRUE;
890443c15812032991c98b33b5424b17bcd55fe3575plougher	}
891443c15812032991c98b33b5424b17bcd55fe3575plougher
8926f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(i->type) {
8936f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_FILE_TYPE:
8946f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_LREG_TYPE:
895d4204758f77acb5a371fa1487a755b76a05d5476plougher			TRACE("create_inode: regular file, file_size %lld, blocks "
896d4204758f77acb5a371fa1487a755b76a05d5476plougher				"%d\n", i->data, i->blocks);
897443c15812032991c98b33b5424b17bcd55fe3575plougher
89879df93becb68081effabebba3006c794be308598plougher			if(write_file(i, pathname))
899443c15812032991c98b33b5424b17bcd55fe3575plougher				file_count ++;
900443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
9016f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_SYMLINK_TYPE:
902d4204758f77acb5a371fa1487a755b76a05d5476plougher			TRACE("create_inode: symlink, symlink_size %lld\n",
903d4204758f77acb5a371fa1487a755b76a05d5476plougher				i->data);
904443c15812032991c98b33b5424b17bcd55fe3575plougher
905a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
906a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
907a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
9086f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(symlink(i->symlink, pathname) == -1) {
909d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("create_inode: failed to create symlink %s, "
910d4204758f77acb5a371fa1487a755b76a05d5476plougher					"because %s\n", pathname, strerror(errno));
911443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
912443c15812032991c98b33b5424b17bcd55fe3575plougher			}
913443c15812032991c98b33b5424b17bcd55fe3575plougher
9149dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
9156f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(lchown(pathname, i->uid, i->gid) == -1)
916d4204758f77acb5a371fa1487a755b76a05d5476plougher					ERROR("create_inode: failed to change uid "
917d4204758f77acb5a371fa1487a755b76a05d5476plougher						"and gids on %s, because %s\n",
918d4204758f77acb5a371fa1487a755b76a05d5476plougher						pathname, strerror(errno));
919443c15812032991c98b33b5424b17bcd55fe3575plougher			}
920443c15812032991c98b33b5424b17bcd55fe3575plougher
921443c15812032991c98b33b5424b17bcd55fe3575plougher			sym_count ++;
922443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
923443c15812032991c98b33b5424b17bcd55fe3575plougher 		case SQUASHFS_BLKDEV_TYPE:
924443c15812032991c98b33b5424b17bcd55fe3575plougher	 	case SQUASHFS_CHRDEV_TYPE: {
9256f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			int chrdev = i->type == SQUASHFS_CHRDEV_TYPE;
926545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			TRACE("create_inode: dev, rdev 0x%llx\n", i->data);
927443c15812032991c98b33b5424b17bcd55fe3575plougher
9289dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
929a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				if(force)
930a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher					unlink(pathname);
931a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
9326f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(mknod(pathname, chrdev ? S_IFCHR : S_IFBLK,
933d4204758f77acb5a371fa1487a755b76a05d5476plougher						makedev((i->data >> 8) & 0xff,
934d4204758f77acb5a371fa1487a755b76a05d5476plougher						i->data & 0xff)) == -1) {
935d4204758f77acb5a371fa1487a755b76a05d5476plougher					ERROR("create_inode: failed to create %s "
936d4204758f77acb5a371fa1487a755b76a05d5476plougher						"device %s, because %s\n",
937d4204758f77acb5a371fa1487a755b76a05d5476plougher						chrdev ? "character" : "block",
938d4204758f77acb5a371fa1487a755b76a05d5476plougher						pathname, strerror(errno));
939443c15812032991c98b33b5424b17bcd55fe3575plougher					break;
940443c15812032991c98b33b5424b17bcd55fe3575plougher				}
941d4204758f77acb5a371fa1487a755b76a05d5476plougher				set_attributes(pathname, i->mode, i->uid, i->gid,
942d4204758f77acb5a371fa1487a755b76a05d5476plougher					i->time, TRUE);
943443c15812032991c98b33b5424b17bcd55fe3575plougher				dev_count ++;
944443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
945d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("create_inode: could not create %s device "
946d4204758f77acb5a371fa1487a755b76a05d5476plougher					"%s, because you're not superuser!\n",
947545404219cdd79c1e06ac7d0698d02a15240c4c3plougher					chrdev ? "character" : "block", pathname);
948443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
9496f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		}
950443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_FIFO_TYPE:
951443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: fifo\n");
952443c15812032991c98b33b5424b17bcd55fe3575plougher
953a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
954a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
955a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
956443c15812032991c98b33b5424b17bcd55fe3575plougher			if(mknod(pathname, S_IFIFO, 0) == -1) {
957d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("create_inode: failed to create fifo %s, "
958d4204758f77acb5a371fa1487a755b76a05d5476plougher					"because %s\n", pathname,
959d4204758f77acb5a371fa1487a755b76a05d5476plougher					strerror(errno));
960443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
961443c15812032991c98b33b5424b17bcd55fe3575plougher			}
9626f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			set_attributes(pathname, i->mode, i->uid, i->gid, i->time, TRUE);
963443c15812032991c98b33b5424b17bcd55fe3575plougher			fifo_count ++;
964443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
965443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_SOCKET_TYPE:
966443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: socket\n");
967443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("create_inode: socket %s ignored\n", pathname);
968443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
969443c15812032991c98b33b5424b17bcd55fe3575plougher		default:
970d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("Unknown inode type %d in create_inode_table!\n",
971d4204758f77acb5a371fa1487a755b76a05d5476plougher				i->type);
972443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
973443c15812032991c98b33b5424b17bcd55fe3575plougher	}
974fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
9756f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	created_inode[i->inode_number - 1] = strdup(pathname);
976443c15812032991c98b33b5424b17bcd55fe3575plougher
977443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
978443c15812032991c98b33b5424b17bcd55fe3575plougher}
979443c15812032991c98b33b5424b17bcd55fe3575plougher
980443c15812032991c98b33b5424b17bcd55fe3575plougher
98102bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_directory_table(long long start, long long end)
982443c15812032991c98b33b5424b17bcd55fe3575plougher{
983443c15812032991c98b33b5424b17bcd55fe3575plougher	int bytes = 0, size = 0, res;
984443c15812032991c98b33b5424b17bcd55fe3575plougher
98541da3230b2ac91a73f9190676f66b3d80b21c270plougher	TRACE("uncompress_directory_table: start %lld, end %lld\n", start, end);
98641da3230b2ac91a73f9190676f66b3d80b21c270plougher
987443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
9889dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		if(size - bytes < SQUASHFS_METADATA_SIZE && (directory_table =
9899dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				realloc(directory_table, size +=
9909dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				SQUASHFS_METADATA_SIZE)) == NULL)
991d4204758f77acb5a371fa1487a755b76a05d5476plougher			EXIT_UNSQUASH("uncompress_directory_table: out of memory "
992d4204758f77acb5a371fa1487a755b76a05d5476plougher				"in realloc\n");
993443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("uncompress_directory_table: reading block 0x%llx\n", start);
994443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(directory_table_hash, start, bytes);
99502bc3bcabf2b219f63961f07293b83629948f026plougher		if((res = read_block(start, &start, directory_table + bytes)) == 0)
996d4204758f77acb5a371fa1487a755b76a05d5476plougher			EXIT_UNSQUASH("uncompress_directory_table: failed to read "
997d4204758f77acb5a371fa1487a755b76a05d5476plougher				"block\n");
998443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
999443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1000443c15812032991c98b33b5424b17bcd55fe3575plougher}
1001443c15812032991c98b33b5424b17bcd55fe3575plougher
1002443c15812032991c98b33b5424b17bcd55fe3575plougher
10039dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block,
10049dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherunsigned int *offset, unsigned int *type)
1005443c15812032991c98b33b5424b17bcd55fe3575plougher{
1006443c15812032991c98b33b5424b17bcd55fe3575plougher	if(dir->cur_entry == dir->dir_count)
1007443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
1008443c15812032991c98b33b5424b17bcd55fe3575plougher
1009443c15812032991c98b33b5424b17bcd55fe3575plougher	*name = dir->dirs[dir->cur_entry].name;
1010443c15812032991c98b33b5424b17bcd55fe3575plougher	*start_block = dir->dirs[dir->cur_entry].start_block;
1011443c15812032991c98b33b5424b17bcd55fe3575plougher	*offset = dir->dirs[dir->cur_entry].offset;
1012443c15812032991c98b33b5424b17bcd55fe3575plougher	*type = dir->dirs[dir->cur_entry].type;
1013443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->cur_entry ++;
1014443c15812032991c98b33b5424b17bcd55fe3575plougher
1015443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1016443c15812032991c98b33b5424b17bcd55fe3575plougher}
1017443c15812032991c98b33b5424b17bcd55fe3575plougher
1018443c15812032991c98b33b5424b17bcd55fe3575plougher
1019443c15812032991c98b33b5424b17bcd55fe3575ploughervoid squashfs_closedir(struct dir *dir)
1020443c15812032991c98b33b5424b17bcd55fe3575plougher{
1021443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir->dirs);
1022443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir);
1023443c15812032991c98b33b5424b17bcd55fe3575plougher}
1024443c15812032991c98b33b5424b17bcd55fe3575plougher
1025443c15812032991c98b33b5424b17bcd55fe3575plougher
1026b54566f5c433764830c29c83151691d0034de094plougherchar *get_component(char *target, char *targname)
1027b54566f5c433764830c29c83151691d0034de094plougher{
1028b54566f5c433764830c29c83151691d0034de094plougher	while(*target == '/')
10293cef656655723444fb1e2de1a001e6c2a54cf81erlougher		target ++;
1030b54566f5c433764830c29c83151691d0034de094plougher
1031b54566f5c433764830c29c83151691d0034de094plougher	while(*target != '/' && *target!= '\0')
1032b54566f5c433764830c29c83151691d0034de094plougher		*targname ++ = *target ++;
1033b54566f5c433764830c29c83151691d0034de094plougher
1034b54566f5c433764830c29c83151691d0034de094plougher	*targname = '\0';
1035b54566f5c433764830c29c83151691d0034de094plougher
1036b54566f5c433764830c29c83151691d0034de094plougher	return target;
1037b54566f5c433764830c29c83151691d0034de094plougher}
1038b54566f5c433764830c29c83151691d0034de094plougher
1039b54566f5c433764830c29c83151691d0034de094plougher
10406ee88c6b5da9f7b3ea88ab7481db126efa01c8f4ploughervoid free_path(struct pathname *paths)
10416ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher{
10426ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	int i;
10436ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
10446ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	for(i = 0; i < paths->names; i++) {
10456ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths)
10466ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
10476ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		free(paths->name[i].name);
10486ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].preg) {
10496ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			regfree(paths->name[i].preg);
10506ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free(paths->name[i].preg);
10516ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		}
10526ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	}
10536ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
10546ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	free(paths);
10556ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher}
10566ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
10576ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
10584dba330d7b952f2f044d38e342e2ae3ea78910d6plougherstruct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
1059b54566f5c433764830c29c83151691d0034de094plougher{
106071add234b27054974d5e29f95b3fab3072792a62plougher	char targname[1024];
10614dba330d7b952f2f044d38e342e2ae3ea78910d6plougher	int i, error;
106271add234b27054974d5e29f95b3fab3072792a62plougher
106371add234b27054974d5e29f95b3fab3072792a62plougher	target = get_component(target, targname);
106471add234b27054974d5e29f95b3fab3072792a62plougher
106571add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
10664dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		if((paths = malloc(sizeof(struct pathname))) == NULL)
10674dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			EXIT_UNSQUASH("failed to allocate paths\n");
10684dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
106971add234b27054974d5e29f95b3fab3072792a62plougher		paths->names = 0;
107071add234b27054974d5e29f95b3fab3072792a62plougher		paths->name = NULL;
107171add234b27054974d5e29f95b3fab3072792a62plougher	}
107271add234b27054974d5e29f95b3fab3072792a62plougher
107371add234b27054974d5e29f95b3fab3072792a62plougher	for(i = 0; i < paths->names; i++)
107471add234b27054974d5e29f95b3fab3072792a62plougher		if(strcmp(paths->name[i].name, targname) == 0)
107571add234b27054974d5e29f95b3fab3072792a62plougher			break;
107671add234b27054974d5e29f95b3fab3072792a62plougher
10776ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	if(i == paths->names) {
1078d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1079d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * allocate new name entry
1080d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
108171add234b27054974d5e29f95b3fab3072792a62plougher		paths->names ++;
1082d4204758f77acb5a371fa1487a755b76a05d5476plougher		paths->name = realloc(paths->name, (i + 1) *
1083d4204758f77acb5a371fa1487a755b76a05d5476plougher			sizeof(struct path_entry));
108471add234b27054974d5e29f95b3fab3072792a62plougher		paths->name[i].name = strdup(targname);
10856ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		paths->name[i].paths = NULL;
10864dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		if(use_regex) {
10874dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = malloc(sizeof(regex_t));
1088d4204758f77acb5a371fa1487a755b76a05d5476plougher			error = regcomp(paths->name[i].preg, targname,
1089d4204758f77acb5a371fa1487a755b76a05d5476plougher				REG_EXTENDED|REG_NOSUB);
1090545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			if(error) {
10914dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				char str[1024];
10924dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
10934dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				regerror(error, paths->name[i].preg, str, 1024);
1094d4204758f77acb5a371fa1487a755b76a05d5476plougher				EXIT_UNSQUASH("invalid regex %s in export %s, "
1095d4204758f77acb5a371fa1487a755b76a05d5476plougher					"because %s\n", targname, alltarget, str);
10964dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			}
10974dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		} else
10984dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = NULL;
10996ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
11006ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(target[0] == '\0')
1101d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1102d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * at leaf pathname component
1103d4204758f77acb5a371fa1487a755b76a05d5476plougher			*/
110471add234b27054974d5e29f95b3fab3072792a62plougher			paths->name[i].paths = NULL;
110571add234b27054974d5e29f95b3fab3072792a62plougher		else
1106d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1107d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * recurse adding child components
1108d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
11094dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].paths = add_path(NULL, target, alltarget);
11106ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	} else {
1111d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1112d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * existing matching entry
1113d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
11146ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths == NULL) {
1115d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1116d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * No sub-directory which means this is the leaf component
1117d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * of a pre-existing extract which subsumes the extract
1118d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * currently being added, in which case stop adding
1119d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * components
1120d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
11216ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else if(target[0] == '\0') {
1122d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1123d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * at leaf pathname component and child components exist
1124d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * from more specific extracts, delete as they're subsumed
1125d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * by this extract
1126d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
11276ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
11286ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			paths->name[i].paths = NULL;
11296ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else
1130d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1131d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * recurse adding child components
1132d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
11336ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			add_path(paths->name[i].paths, target, alltarget);
113471add234b27054974d5e29f95b3fab3072792a62plougher	}
113571add234b27054974d5e29f95b3fab3072792a62plougher
113671add234b27054974d5e29f95b3fab3072792a62plougher	return paths;
113771add234b27054974d5e29f95b3fab3072792a62plougher}
11386ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
11396ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
1140a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *init_subdir()
114171add234b27054974d5e29f95b3fab3072792a62plougher{
11428372232d2460411adaa2299c32a0a88665e44902plougher	struct pathnames *new = malloc(sizeof(struct pathnames));
1143a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	new->count = 0;
1144a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return new;
1145a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1146a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1147a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1148a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
1149a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1150a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if(paths->count % PATHS_ALLOC_SIZE == 0)
1151d4204758f77acb5a371fa1487a755b76a05d5476plougher		paths = realloc(paths, sizeof(struct pathnames *) +
1152d4204758f77acb5a371fa1487a755b76a05d5476plougher		(paths->count + PATHS_ALLOC_SIZE) * sizeof(struct pathname *));
1153a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1154a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	paths->path[paths->count++] = path;
1155a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return paths;
1156a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1157a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1158a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1159a706f1b6bb48f288ecaf74e218ce20504bda52c6ploughervoid free_subdir(struct pathnames *paths)
1160a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1161a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free(paths);
1162a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1163a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1164a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1165a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherint matches(struct pathnames *paths, char *name, struct pathnames **new)
1166a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1167a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	int i, n;
116871add234b27054974d5e29f95b3fab3072792a62plougher
116971add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
117071add234b27054974d5e29f95b3fab3072792a62plougher		*new = NULL;
1171b54566f5c433764830c29c83151691d0034de094plougher		return TRUE;
117271add234b27054974d5e29f95b3fab3072792a62plougher	}
117371add234b27054974d5e29f95b3fab3072792a62plougher
1174a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = init_subdir();
1175a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1176a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	for(n = 0; n < paths->count; n++) {
1177a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		struct pathname *path = paths->path[n];
1178a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		for(i = 0; i < path->names; i++) {
1179a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			int match = use_regex ?
1180d4204758f77acb5a371fa1487a755b76a05d5476plougher				regexec(path->name[i].preg, name, (size_t) 0, NULL,
1181d4204758f77acb5a371fa1487a755b76a05d5476plougher				0) == 0 : fnmatch(path->name[i].name, name,
1182d4204758f77acb5a371fa1487a755b76a05d5476plougher				FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;
1183a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match && path->name[i].paths == NULL)
1184d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
1185d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * match on a leaf component, any subdirectories
1186d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * will implicitly match, therefore return an empty
1187d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * new search set
1188d4204758f77acb5a371fa1487a755b76a05d5476plougher				 */
1189a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				goto empty_set;
1190a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1191a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match)
1192d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
1193d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * match on a non-leaf component, add any
1194d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * subdirectories to the new set of subdirectories
1195d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * to scan for this name
1196d4204758f77acb5a371fa1487a755b76a05d5476plougher				 */
1197a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				*new = add_subdir(*new, path->name[i].paths);
1198a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		}
1199a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1200b54566f5c433764830c29c83151691d0034de094plougher
1201a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if((*new)->count == 0) {
1202d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1203d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * no matching names found, delete empty search set, and return
1204d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * FALSE
1205d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
1206a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(*new);
1207a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		*new = NULL;
1208a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		return FALSE;
1209a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1210a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1211d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
1212d4204758f77acb5a371fa1487a755b76a05d5476plougher	* one or more matches with sub-directories found (no leaf matches),
1213d4204758f77acb5a371fa1487a755b76a05d5476plougher	* return new search set and return TRUE
1214d4204758f77acb5a371fa1487a755b76a05d5476plougher	*/
1215a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
1216a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1217a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherempty_set:
1218d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
1219d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * found matching leaf exclude, return empty search set and return TRUE
1220d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
1221a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free_subdir(*new);
1222a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = NULL;
1223a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
1224b54566f5c433764830c29c83151691d0034de094plougher}
1225b54566f5c433764830c29c83151691d0034de094plougher
1226b54566f5c433764830c29c83151691d0034de094plougher
1227d4204758f77acb5a371fa1487a755b76a05d5476plougherint pre_scan(char *parent_name, unsigned int start_block, unsigned int offset,
1228d4204758f77acb5a371fa1487a755b76a05d5476plougher	struct pathnames *paths)
1229eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1230eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	unsigned int type;
1231eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	char *name, pathname[1024];
1232eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct pathnames *new;
1233eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
1234eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1235eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1236eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(dir == NULL) {
1237d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("pre_scan: Failed to read directory %s (%x:%x)\n",
1238d4204758f77acb5a371fa1487a755b76a05d5476plougher			parent_name, start_block, offset);
1239eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		return FALSE;
1240eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
1241eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1242eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
1243eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		struct inode *i;
1244eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1245d4204758f77acb5a371fa1487a755b76a05d5476plougher		TRACE("pre_scan: name %s, start_block %d, offset %d, type %d\n",
1246d4204758f77acb5a371fa1487a755b76a05d5476plougher			name, start_block, offset, type);
1247eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1248eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(!matches(paths, name, &new))
1249eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			continue;
1250eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1251eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
1252eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1253eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(type == SQUASHFS_DIR_TYPE)
1254eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			pre_scan(parent_name, start_block, offset, new);
1255eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		else if(new == NULL) {
1256d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(type == SQUASHFS_FILE_TYPE ||
1257d4204758f77acb5a371fa1487a755b76a05d5476plougher					type == SQUASHFS_LREG_TYPE) {
1258d4204758f77acb5a371fa1487a755b76a05d5476plougher				if((i = s_ops.read_inode(start_block, offset)) ==
1259d4204758f77acb5a371fa1487a755b76a05d5476plougher						NULL) {
1260eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher					ERROR("failed to read header\n");
1261eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher					continue;
1262eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
1263eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				if(created_inode[i->inode_number - 1] == NULL) {
1264d4204758f77acb5a371fa1487a755b76a05d5476plougher					created_inode[i->inode_number - 1] =
1265d4204758f77acb5a371fa1487a755b76a05d5476plougher						(char *) i;
1266d4204758f77acb5a371fa1487a755b76a05d5476plougher					total_blocks += (i->data +
1267d4204758f77acb5a371fa1487a755b76a05d5476plougher						(block_size - 1)) >> block_log;
1268eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
1269eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				total_files ++;
1270eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			}
1271eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			total_inodes ++;
1272eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		}
1273eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1274eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		free_subdir(new);
1275eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
1276eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1277eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	squashfs_closedir(dir);
1278eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1279eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	return TRUE;
1280eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1281eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1282eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1283d4204758f77acb5a371fa1487a755b76a05d5476plougherint dir_scan(char *parent_name, unsigned int start_block, unsigned int offset,
1284d4204758f77acb5a371fa1487a755b76a05d5476plougher	struct pathnames *paths)
1285443c15812032991c98b33b5424b17bcd55fe3575plougher{
1286443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int type;
1287443c15812032991c98b33b5424b17bcd55fe3575plougher	char *name, pathname[1024];
1288a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *new;
1289eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
1290eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1291443c15812032991c98b33b5424b17bcd55fe3575plougher
1292443c15812032991c98b33b5424b17bcd55fe3575plougher	if(dir == NULL) {
1293d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("dir_scan: Failed to read directory %s (%x:%x)\n",
1294d4204758f77acb5a371fa1487a755b76a05d5476plougher			parent_name, start_block, offset);
1295443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
1296443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1297443c15812032991c98b33b5424b17bcd55fe3575plougher
1298eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(lsonly || info)
1299eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		print_filename(parent_name, i);
1300eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1301d4204758f77acb5a371fa1487a755b76a05d5476plougher	if(!lsonly && mkdir(parent_name, (mode_t) dir->mode) == -1 &&
1302d4204758f77acb5a371fa1487a755b76a05d5476plougher			(!force || errno != EEXIST)) {
1303d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("dir_scan: failed to open directory %s, because %s\n",
1304d4204758f77acb5a371fa1487a755b76a05d5476plougher			parent_name, strerror(errno));
1305443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
1306443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1307443c15812032991c98b33b5424b17bcd55fe3575plougher
1308443c15812032991c98b33b5424b17bcd55fe3575plougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
1309d4204758f77acb5a371fa1487a755b76a05d5476plougher		TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n",
1310d4204758f77acb5a371fa1487a755b76a05d5476plougher			name, start_block, offset, type);
1311b54566f5c433764830c29c83151691d0034de094plougher
131271add234b27054974d5e29f95b3fab3072792a62plougher
131371add234b27054974d5e29f95b3fab3072792a62plougher		if(!matches(paths, name, &new))
1314b54566f5c433764830c29c83151691d0034de094plougher			continue;
1315b54566f5c433764830c29c83151691d0034de094plougher
1316443c15812032991c98b33b5424b17bcd55fe3575plougher		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
1317fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
1318443c15812032991c98b33b5424b17bcd55fe3575plougher		if(type == SQUASHFS_DIR_TYPE)
131971add234b27054974d5e29f95b3fab3072792a62plougher			dir_scan(pathname, start_block, offset, new);
1320a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		else if(new == NULL) {
13216f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if((i = s_ops.read_inode(start_block, offset)) == NULL) {
13226f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				ERROR("failed to read header\n");
13236f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				continue;
13246f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			}
13256f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
13266f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(lsonly || info)
13276f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				print_filename(pathname, i);
13286f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
1329eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			if(!lsonly) {
13306f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				create_inode(pathname, i);
1331eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				update_progress_bar();
1332eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
1333427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher
1334d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(i->type == SQUASHFS_SYMLINK_TYPE ||
1335d4204758f77acb5a371fa1487a755b76a05d5476plougher					i->type == SQUASHFS_LSYMLINK_TYPE)
1336427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher				free(i->symlink);
13376f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		}
1338a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1339a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(new);
1340443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1341443c15812032991c98b33b5424b17bcd55fe3575plougher
1342074d3f1129eae914655f6637773488052bf22327rlougher	if(!lsonly)
1343d4204758f77acb5a371fa1487a755b76a05d5476plougher		set_attributes(parent_name, dir->mode, dir->uid, dir->guid,
1344d4204758f77acb5a371fa1487a755b76a05d5476plougher			dir->mtime, force);
1345443c15812032991c98b33b5424b17bcd55fe3575plougher
1346443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_closedir(dir);
1347443c15812032991c98b33b5424b17bcd55fe3575plougher	dir_count ++;
1348443c15812032991c98b33b5424b17bcd55fe3575plougher
1349443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1350443c15812032991c98b33b5424b17bcd55fe3575plougher}
1351443c15812032991c98b33b5424b17bcd55fe3575plougher
1352443c15812032991c98b33b5424b17bcd55fe3575plougher
1353b624936abba03d38b7e9245c647339d8f6f34274ploughervoid squashfs_stat(char *source)
1354b624936abba03d38b7e9245c647339d8f6f34274plougher{
1355b624936abba03d38b7e9245c647339d8f6f34274plougher	time_t mkfs_time = (time_t) sBlk.mkfs_time;
1356b624936abba03d38b7e9245c647339d8f6f34274plougher	char *mkfs_str = ctime(&mkfs_time);
1357b624936abba03d38b7e9245c647339d8f6f34274plougher
1358b624936abba03d38b7e9245c647339d8f6f34274plougher#if __BYTE_ORDER == __BIG_ENDIAN
1359d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n",
1360d4204758f77acb5a371fa1487a755b76a05d5476plougher		sBlk.s_major == 4 ? "" : swap ? "little endian " : "big endian ",
1361d4204758f77acb5a371fa1487a755b76a05d5476plougher		sBlk.s_major, sBlk.s_minor, source);
1362b624936abba03d38b7e9245c647339d8f6f34274plougher#else
1363d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n",
1364d4204758f77acb5a371fa1487a755b76a05d5476plougher		sBlk.s_major == 4 ? "" : swap ? "big endian " : "little endian ",
1365d4204758f77acb5a371fa1487a755b76a05d5476plougher		sBlk.s_major, sBlk.s_minor, source);
1366b624936abba03d38b7e9245c647339d8f6f34274plougher#endif
1367d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Creation or last append time %s", mkfs_str ? mkfs_str :
1368d4204758f77acb5a371fa1487a755b76a05d5476plougher		"failed to get time\n");
1369d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Filesystem is %sexportable via NFS\n",
1370d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_EXPORTABLE(sBlk.flags) ? "" : "not ");
1371d4204758f77acb5a371fa1487a755b76a05d5476plougher
1372d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Inodes are %scompressed\n",
1373d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags) ? "un" : "");
1374d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Data is %scompressed\n",
1375d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags) ? "un" : "");
1376b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1 && !SQUASHFS_NO_FRAGMENTS(sBlk.flags))
1377d4204758f77acb5a371fa1487a755b76a05d5476plougher		printf("Fragments are %scompressed\n",
1378d4204758f77acb5a371fa1487a755b76a05d5476plougher			SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags) ? "un" : "");
1379d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Check data is %spresent in the filesystem\n",
1380d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_CHECK_DATA(sBlk.flags) ? "" : "not ");
1381b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1) {
1382d4204758f77acb5a371fa1487a755b76a05d5476plougher		printf("Fragments are %spresent in the filesystem\n",
1383d4204758f77acb5a371fa1487a755b76a05d5476plougher			SQUASHFS_NO_FRAGMENTS(sBlk.flags) ? "not " : "");
1384d4204758f77acb5a371fa1487a755b76a05d5476plougher		printf("Always_use_fragments option is %sspecified\n",
1385d4204758f77acb5a371fa1487a755b76a05d5476plougher			SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags) ? "" : "not ");
1386b624936abba03d38b7e9245c647339d8f6f34274plougher	} else
1387b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Fragments are not supported by the filesystem\n");
1388b624936abba03d38b7e9245c647339d8f6f34274plougher
13890337de3977eec74e6a3d28e0d0863299246de8b7plougher	if(sBlk.s_major > 1)
1390d4204758f77acb5a371fa1487a755b76a05d5476plougher		printf("Duplicates are %sremoved\n",
1391d4204758f77acb5a371fa1487a755b76a05d5476plougher			SQUASHFS_DUPLICATES(sBlk.flags) ? "" : "not ");
13920337de3977eec74e6a3d28e0d0863299246de8b7plougher	else
13930337de3977eec74e6a3d28e0d0863299246de8b7plougher		printf("Duplicates are removed\n");
1394d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n",
1395d4204758f77acb5a371fa1487a755b76a05d5476plougher		sBlk.bytes_used / 1024.0, sBlk.bytes_used / (1024.0 * 1024.0));
1396b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Block size %d\n", sBlk.block_size);
1397b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1)
1398b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Number of fragments %d\n", sBlk.fragments);
1399b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Number of inodes %d\n", sBlk.inodes);
14000f74340e3b68533339adc60f418ddf59fa188f61plougher	if(sBlk.s_major == 4)
14010f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of ids %d\n", sBlk.no_ids);
14020f74340e3b68533339adc60f418ddf59fa188f61plougher	else {
14030f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of uids %d\n", sBlk.no_uids);
14040f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of gids %d\n", sBlk.no_guids);
14050f74340e3b68533339adc60f418ddf59fa188f61plougher	}
1406b624936abba03d38b7e9245c647339d8f6f34274plougher
1407b624936abba03d38b7e9245c647339d8f6f34274plougher	TRACE("sBlk.inode_table_start 0x%llx\n", sBlk.inode_table_start);
1408b624936abba03d38b7e9245c647339d8f6f34274plougher	TRACE("sBlk.directory_table_start 0x%llx\n", sBlk.directory_table_start);
14090f74340e3b68533339adc60f418ddf59fa188f61plougher	if(sBlk.s_major == 4)
14100f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.id_table_start 0x%llx\n", sBlk.id_table_start);
14110f74340e3b68533339adc60f418ddf59fa188f61plougher	else {
14120f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.uid_start 0x%llx\n", sBlk.uid_start);
14130f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.guid_start 0x%llx\n", sBlk.guid_start);
14140f74340e3b68533339adc60f418ddf59fa188f61plougher	}
1415b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1)
1416d4204758f77acb5a371fa1487a755b76a05d5476plougher		TRACE("sBlk.fragment_table_start 0x%llx\n\n",
1417d4204758f77acb5a371fa1487a755b76a05d5476plougher			sBlk.fragment_table_start);
1418b624936abba03d38b7e9245c647339d8f6f34274plougher}
1419b624936abba03d38b7e9245c647339d8f6f34274plougher
1420b624936abba03d38b7e9245c647339d8f6f34274plougher
142102bc3bcabf2b219f63961f07293b83629948f026plougherint read_super(char *source)
1422443c15812032991c98b33b5424b17bcd55fe3575plougher{
14236490378e5b5e8dc058daf28423a7465699a6ba7bplougher	squashfs_super_block_3 sBlk_3;
14246490378e5b5e8dc058daf28423a7465699a6ba7bplougher	squashfs_super_block sBlk_4;
14256490378e5b5e8dc058daf28423a7465699a6ba7bplougher
14266490378e5b5e8dc058daf28423a7465699a6ba7bplougher	/*
14276490378e5b5e8dc058daf28423a7465699a6ba7bplougher	 * Try to read a Squashfs 4 superblock
14286490378e5b5e8dc058daf28423a7465699a6ba7bplougher	 */
1429d4204758f77acb5a371fa1487a755b76a05d5476plougher	read_bytes(SQUASHFS_START, sizeof(squashfs_super_block),
1430d4204758f77acb5a371fa1487a755b76a05d5476plougher		(char *) &sBlk_4);
143154660e177ba40ab08ee2f3304b9f030eb5675677plougher	swap = sBlk_4.s_magic != SQUASHFS_MAGIC;
14326490378e5b5e8dc058daf28423a7465699a6ba7bplougher	SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4);
14336490378e5b5e8dc058daf28423a7465699a6ba7bplougher
1434d4204758f77acb5a371fa1487a755b76a05d5476plougher	if(sBlk_4.s_magic == SQUASHFS_MAGIC && sBlk_4.s_major == 4 &&
1435d4204758f77acb5a371fa1487a755b76a05d5476plougher			sBlk_4.s_minor == 0) {
14366490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.squashfs_opendir = squashfs_opendir_4;
14376490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_fragment = read_fragment_4;
14386490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_fragment_table = read_fragment_table_4;
14396490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_block_list = read_block_list_2;
14406490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_inode = read_inode_4;
14416490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_uids_guids = read_uids_guids_4;
14426490378e5b5e8dc058daf28423a7465699a6ba7bplougher		memcpy(&sBlk, &sBlk_4, sizeof(sBlk_4));
14436490378e5b5e8dc058daf28423a7465699a6ba7bplougher		return TRUE;
14446490378e5b5e8dc058daf28423a7465699a6ba7bplougher	}
14456490378e5b5e8dc058daf28423a7465699a6ba7bplougher
14466490378e5b5e8dc058daf28423a7465699a6ba7bplougher	/*
14476490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 * Not a Squashfs 4 superblock, try to read a squashfs 3 superblock
14486490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 * (compatible with 1 and 2 filesystems)
14496490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 */
1450d4204758f77acb5a371fa1487a755b76a05d5476plougher	read_bytes(SQUASHFS_START, sizeof(squashfs_super_block_3),
1451d4204758f77acb5a371fa1487a755b76a05d5476plougher		(char *) &sBlk_3);
1452443c15812032991c98b33b5424b17bcd55fe3575plougher
1453d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
1454d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * Check it is a SQUASHFS superblock
1455d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
1456443c15812032991c98b33b5424b17bcd55fe3575plougher	swap = 0;
145721ee4773956342a8a7d0f14e430ae77ffbd10601plougher	if(sBlk_3.s_magic != SQUASHFS_MAGIC) {
145821ee4773956342a8a7d0f14e430ae77ffbd10601plougher		if(sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP) {
14597a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher			squashfs_super_block_3 sblk;
1460d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("Reading a different endian SQUASHFS filesystem on "
1461d4204758f77acb5a371fa1487a755b76a05d5476plougher				"%s\n", source);
14626490378e5b5e8dc058daf28423a7465699a6ba7bplougher			SQUASHFS_SWAP_SUPER_BLOCK_3(&sblk, &sBlk_3);
14636490378e5b5e8dc058daf28423a7465699a6ba7bplougher			memcpy(&sBlk_3, &sblk, sizeof(squashfs_super_block_3));
1464443c15812032991c98b33b5424b17bcd55fe3575plougher			swap = 1;
1465443c15812032991c98b33b5424b17bcd55fe3575plougher		} else  {
1466443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("Can't find a SQUASHFS superblock on %s\n", source);
1467443c15812032991c98b33b5424b17bcd55fe3575plougher			goto failed_mount;
1468443c15812032991c98b33b5424b17bcd55fe3575plougher		}
1469443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1470443c15812032991c98b33b5424b17bcd55fe3575plougher
14716490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.s_magic = sBlk_3.s_magic;
14726490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.inodes = sBlk_3.inodes;
14736490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.mkfs_time = sBlk_3.mkfs_time;
14746490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.block_size = sBlk_3.block_size;
14756490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.fragments = sBlk_3.fragments;
14766490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.block_log = sBlk_3.block_log;
14776490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.flags = sBlk_3.flags;
14786490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.s_major = sBlk_3.s_major;
14796490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.s_minor = sBlk_3.s_minor;
14806490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.root_inode = sBlk_3.root_inode;
14816490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.bytes_used = sBlk_3.bytes_used;
14826490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.inode_table_start = sBlk_3.inode_table_start;
14836490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.directory_table_start = sBlk_3.directory_table_start;
14846490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.fragment_table_start = sBlk_3.fragment_table_start;
14856490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.lookup_table_start = sBlk_3.lookup_table_start;
14866490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.no_uids = sBlk_3.no_uids;
14876490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.no_guids = sBlk_3.no_guids;
14886490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.uid_start = sBlk_3.uid_start;
14896490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.guid_start = sBlk_3.guid_start;
14906490378e5b5e8dc058daf28423a7465699a6ba7bplougher
1491443c15812032991c98b33b5424b17bcd55fe3575plougher	/* Check the MAJOR & MINOR versions */
1492ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	if(sBlk.s_major == 1 || sBlk.s_major == 2) {
14936490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.bytes_used = sBlk_3.bytes_used_2;
14946490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.uid_start = sBlk_3.uid_start_2;
14956490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.guid_start = sBlk_3.guid_start_2;
14966490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.inode_table_start = sBlk_3.inode_table_start_2;
14976490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.directory_table_start = sBlk_3.directory_table_start_2;
149802bc3bcabf2b219f63961f07293b83629948f026plougher
1499ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		if(sBlk.s_major == 1) {
15006490378e5b5e8dc058daf28423a7465699a6ba7bplougher			sBlk.block_size = sBlk_3.block_size_1;
15015ff400bfbae6bb397cf3110190e83a29725fcd07plougher			sBlk.fragment_table_start = sBlk.uid_start;
1502ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.squashfs_opendir = squashfs_opendir_1;
1503ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_1;
1504ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_block_list = read_block_list_1;
15056f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_1;
150679e700efc62527661ce140bd1013a2b60577917eplougher			s_ops.read_uids_guids = read_uids_guids_1;
1507ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		} else {
15086490378e5b5e8dc058daf28423a7465699a6ba7bplougher			sBlk.fragment_table_start = sBlk_3.fragment_table_start_2;
1509ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.squashfs_opendir = squashfs_opendir_1;
1510ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment = read_fragment_2;
1511ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_2;
1512ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.read_block_list = read_block_list_2;
15136f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_2;
151479e700efc62527661ce140bd1013a2b60577917eplougher			s_ops.read_uids_guids = read_uids_guids_1;
1515ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		}
15164ce87501a1b07102cef9750060d9a53cd5b00a61plougher	} else if(sBlk.s_major == 3) {
1517ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.squashfs_opendir = squashfs_opendir_3;
1518ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_fragment = read_fragment_3;
1519ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_fragment_table = read_fragment_table_3;
1520ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_block_list = read_block_list_2;
1521ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_inode = read_inode_3;
152279e700efc62527661ce140bd1013a2b60577917eplougher		s_ops.read_uids_guids = read_uids_guids_1;
152302bc3bcabf2b219f63961f07293b83629948f026plougher	} else {
1524d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("Filesystem on %s is (%d:%d), ", source, sBlk.s_major,
1525d4204758f77acb5a371fa1487a755b76a05d5476plougher			sBlk.s_minor);
15264c99cb7f458d8e1c598f1c80793daf3696c9b528plougher		ERROR("which is a later filesystem version than I support!\n");
1527443c15812032991c98b33b5424b17bcd55fe3575plougher		goto failed_mount;
1528443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1529443c15812032991c98b33b5424b17bcd55fe3575plougher
1530443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1531443c15812032991c98b33b5424b17bcd55fe3575plougher
1532443c15812032991c98b33b5424b17bcd55fe3575plougherfailed_mount:
1533443c15812032991c98b33b5424b17bcd55fe3575plougher	return FALSE;
1534443c15812032991c98b33b5424b17bcd55fe3575plougher}
1535443c15812032991c98b33b5424b17bcd55fe3575plougher
1536443c15812032991c98b33b5424b17bcd55fe3575plougher
1537a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathname *process_extract_files(struct pathname *path, char *filename)
153871add234b27054974d5e29f95b3fab3072792a62plougher{
153971add234b27054974d5e29f95b3fab3072792a62plougher	FILE *fd;
154071add234b27054974d5e29f95b3fab3072792a62plougher	char name[16384];
154171add234b27054974d5e29f95b3fab3072792a62plougher
15424dba330d7b952f2f044d38e342e2ae3ea78910d6plougher	if((fd = fopen(filename, "r")) == NULL)
1543d4204758f77acb5a371fa1487a755b76a05d5476plougher		EXIT_UNSQUASH("Could not open %s, because %s\n", filename,
1544d4204758f77acb5a371fa1487a755b76a05d5476plougher			strerror(errno));
154571add234b27054974d5e29f95b3fab3072792a62plougher
154671add234b27054974d5e29f95b3fab3072792a62plougher	while(fscanf(fd, "%16384[^\n]\n", name) != EOF)
1547a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, name, name);
154871add234b27054974d5e29f95b3fab3072792a62plougher
154971add234b27054974d5e29f95b3fab3072792a62plougher	fclose(fd);
1550a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return path;
155171add234b27054974d5e29f95b3fab3072792a62plougher}
155271add234b27054974d5e29f95b3fab3072792a62plougher
155371add234b27054974d5e29f95b3fab3072792a62plougher
1554d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
1555d4204758f77acb5a371fa1487a755b76a05d5476plougher * reader thread.  This thread processes read requests queued by the
1556d4204758f77acb5a371fa1487a755b76a05d5476plougher * cache_get() routine.
1557d4204758f77acb5a371fa1487a755b76a05d5476plougher */
15588888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *reader(void *arg)
15598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
15608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
15618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct cache_entry *entry = queue_get(to_reader);
15628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int res = read_bytes(entry->block,
15638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size),
15648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data);
15658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(res && SQUASHFS_COMPRESSED_BLOCK(entry->size))
1567d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1568d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * queue successfully read block to the deflate thread(s)
1569d4204758f77acb5a371fa1487a755b76a05d5476plougher 			 * for further processing
1570d4204758f77acb5a371fa1487a755b76a05d5476plougher 			 */
15718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			queue_put(to_deflate, entry);
15728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else
1573d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1574d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * block has either been successfully read and is
1575d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * uncompressed, or an error has occurred, clear pending
1576d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * flag, set error appropriately, and wake up any threads
1577d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * waiting on this buffer
1578d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
15798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_ready(entry, !res);
15808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
15818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
15828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1584d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
1585d4204758f77acb5a371fa1487a755b76a05d5476plougher * writer thread.  This processes file write requests queued by the
1586d4204758f77acb5a371fa1487a755b76a05d5476plougher * write_file() routine.
1587d4204758f77acb5a371fa1487a755b76a05d5476plougher */
15888888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *writer(void *arg)
15898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
15908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int i;
15918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
15938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct squashfs_file *file = queue_get(to_writer);
15948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int file_fd;
15958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int hole = 0;
159627636cb2cec37a68313f9eb825c0548245eecad0plougher		int failed = FALSE;
1597c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		int error;
15988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(file == NULL) {
16008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			queue_put(from_writer, NULL);
16018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			continue;
16028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
16038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		TRACE("writer: regular file, blocks %d\n", file->blocks);
16058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		file_fd = file->fd;
16078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1608eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		for(i = 0; i < file->blocks; i++, cur_blocks ++) {
16098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			struct file_entry *block = queue_get(to_writer);
16108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(block->buffer == 0) { /* sparse file */
16128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole += block->size;
16138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				free(block);
16148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				continue;
16158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
16168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_wait(block->buffer);
161827636cb2cec37a68313f9eb825c0548245eecad0plougher
161927636cb2cec37a68313f9eb825c0548245eecad0plougher			if(block->buffer->error)
162027636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
162127636cb2cec37a68313f9eb825c0548245eecad0plougher
1622c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			if(failed)
1623c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				continue;
1624c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
1625c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			error = write_block(file_fd, block->buffer->data +
1626c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				block->offset, block->size, hole, file->sparse);
1627c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
1628c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			if(error == FALSE) {
1629d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("writer: failed to write data block %d\n",
1630d4204758f77acb5a371fa1487a755b76a05d5476plougher					i);
163127636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
16328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
1633c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
16348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			hole = 0;
16358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_put(block->buffer);
16368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			free(block);
16378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
16388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
163927636cb2cec37a68313f9eb825c0548245eecad0plougher		if(hole && failed == FALSE) {
1640d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1641d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * corner case for hole extending to end of file
1642d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
1643d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(file->sparse == FALSE ||
1644d4204758f77acb5a371fa1487a755b76a05d5476plougher					lseek(file_fd, hole, SEEK_CUR) == -1) {
1645d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
1646d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * for files which we don't want to write
1647c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * sparsely, or for broken lseeks which cannot
1648c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * seek beyond end of file, write_block will do
1649c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * the right thing
1650c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 */
16518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole --;
1652d4204758f77acb5a371fa1487a755b76a05d5476plougher				if(write_block(file_fd, "\0", 1, hole,
1653d4204758f77acb5a371fa1487a755b76a05d5476plougher						file->sparse) == FALSE) {
1654d4204758f77acb5a371fa1487a755b76a05d5476plougher					ERROR("writer: failed to write sparse "
1655d4204758f77acb5a371fa1487a755b76a05d5476plougher						"data block\n");
165627636cb2cec37a68313f9eb825c0548245eecad0plougher					failed = TRUE;
16578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				}
16588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			} else if(ftruncate(file_fd, file->file_size) == -1) {
1659d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("writer: failed to write sparse data "
1660d4204758f77acb5a371fa1487a755b76a05d5476plougher					"block\n");
166127636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
16628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
16638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
16648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		close(file_fd);
166627636cb2cec37a68313f9eb825c0548245eecad0plougher		if(failed == FALSE)
1667d4204758f77acb5a371fa1487a755b76a05d5476plougher			set_attributes(file->pathname, file->mode, file->uid,
1668d4204758f77acb5a371fa1487a755b76a05d5476plougher				file->gid, file->time, force);
166927636cb2cec37a68313f9eb825c0548245eecad0plougher		else {
167027636cb2cec37a68313f9eb825c0548245eecad0plougher			ERROR("Failed to write %s, skipping\n", file->pathname);
167127636cb2cec37a68313f9eb825c0548245eecad0plougher			unlink(file->pathname);
167227636cb2cec37a68313f9eb825c0548245eecad0plougher		}
167379df93becb68081effabebba3006c794be308598plougher		free(file->pathname);
16748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		free(file);
167527636cb2cec37a68313f9eb825c0548245eecad0plougher
16768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
16778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
16788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1680d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
1681d4204758f77acb5a371fa1487a755b76a05d5476plougher * decompress thread.  This decompresses buffers queued by the read thread
1682d4204758f77acb5a371fa1487a755b76a05d5476plougher */
16838888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *deflator(void *arg)
16848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
16858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	char tmp[block_size];
16868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
16888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct cache_entry *entry = queue_get(to_deflate);
16898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int res;
16908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		unsigned long bytes = block_size;
16918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1692d4204758f77acb5a371fa1487a755b76a05d5476plougher		res = uncompress((unsigned char *) tmp, &bytes,
1693d4204758f77acb5a371fa1487a755b76a05d5476plougher			(const unsigned char *) entry->data,
1694d4204758f77acb5a371fa1487a755b76a05d5476plougher			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size));
16958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(res != Z_OK) {
16978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(res == Z_MEM_ERROR)
1698d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("zlib::uncompress failed, not enough memory"
1699d4204758f77acb5a371fa1487a755b76a05d5476plougher					"\n");
17008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			else if(res == Z_BUF_ERROR)
1701d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("zlib::uncompress failed, not enough room "
1702d4204758f77acb5a371fa1487a755b76a05d5476plougher					"in output buffer\n");
17038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			else
1704d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("zlib::uncompress failed, unknown error "
1705d4204758f77acb5a371fa1487a755b76a05d5476plougher					"%d\n", res);
17068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		} else
17078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			memcpy(entry->data, tmp, bytes);
17088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1709d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1710d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * block has been either successfully decompressed, or an error
17118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * occurred, clear pending flag, set error appropriately and
1712d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 * wake up any threads waiting on this block
1713d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 */
17148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache_block_ready(entry, res != Z_OK);
17158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
17168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
17178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
17188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1719eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid *progress_thread(void *arg)
1720eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1721eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct timeval timeval;
1722eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct timespec timespec;
17231b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct itimerval itimerval;
17241b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct winsize winsize;
17251b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
17261b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
172701b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher		if(isatty(STDOUT_FILENO))
172801b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher			ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
172901b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher				"columns\n");
17301b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = 80;
17311b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	} else
17321b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = winsize.ws_col;
17331b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGWINCH, sigwinch_handler);
17341b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGALRM, sigalrm_handler);
17351b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
17361b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_sec = 0;
17371b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_usec = 250000;
17381b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_sec = 0;
17391b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_usec = 250000;
17401b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	setitimer(ITIMER_REAL, &itimerval, NULL);
1741eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1742eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_cond_init(&progress_wait, NULL);
1743eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
17441b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
1745eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(1) {
1746eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		gettimeofday(&timeval, NULL);
1747eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		timespec.tv_sec = timeval.tv_sec;
1748eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(timeval.tv_usec + 250000 > 999999)
1749eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			timespec.tv_sec++;
1750eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) * 1000;
17511b42101056befe25b5f19d5b099e806a2ecee9cdplougher		pthread_cond_timedwait(&progress_wait, &screen_mutex, &timespec);
17521b42101056befe25b5f19d5b099e806a2ecee9cdplougher		if(progress_enabled)
17531b42101056befe25b5f19d5b099e806a2ecee9cdplougher			progress_bar(sym_count + dev_count +
1754d4204758f77acb5a371fa1487a755b76a05d5476plougher				fifo_count + cur_blocks, total_inodes -
1755d4204758f77acb5a371fa1487a755b76a05d5476plougher				total_files + total_blocks, columns);
1756eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
1757eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1758eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1759eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
17608888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid initialise_threads(int fragment_buffer_size, int data_buffer_size)
17618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
17628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int i;
17638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigset_t sigmask, old_mask;
17648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int all_buffers_size = fragment_buffer_size + data_buffer_size;
17658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
17668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigemptyset(&sigmask);
17678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigaddset(&sigmask, SIGINT);
17688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigaddset(&sigmask, SIGQUIT);
17698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
17708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads\n");
17718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
17728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(processors == -1) {
17738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifndef linux
17748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int mib[2];
17758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		size_t len = sizeof(processors);
17768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
17778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[0] = CTL_HW;
17788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifdef HW_AVAILCPU
17798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_AVAILCPU;
17808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
17818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_NCPU;
17828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
17838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
17848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
1785d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("Failed to get number of available processors.  "
1786d4204758f77acb5a371fa1487a755b76a05d5476plougher				"Defaulting to 1\n");
17878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors = 1;
17888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
17898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
17908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		processors = get_nprocs();
17918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
17928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
17938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1794eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if((thread = malloc((3 + processors) * sizeof(pthread_t))) == NULL)
17958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
1796eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	deflator_thread = &thread[3];
17978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
17988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	to_reader = queue_init(all_buffers_size);
17998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	to_deflate = queue_init(all_buffers_size);
1800eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	to_writer = queue_init(1000);
18018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	from_writer = queue_init(1);
18028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	fragment_cache = cache_init(block_size, fragment_buffer_size);
18038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data_cache = cache_init(block_size, data_buffer_size);
18048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[0], NULL, reader, NULL);
18058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[1], NULL, writer, NULL);
1806eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_create(&thread[2], NULL, progress_thread, NULL);
18078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&fragment_mutex, NULL);
18088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(i = 0; i < processors; i++) {
1810d4204758f77acb5a371fa1487a755b76a05d5476plougher		if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) != 0)
18118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("Failed to create thread\n");
18128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
18138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	printf("Parallel unsquashfs: Using %d processor%s\n", processors,
18158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors == 1 ? "" : "s");
18168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
18188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads\n");
18198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
18208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18221b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid enable_progress_bar()
18231b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
18241b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
18251b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_enabled = TRUE;
18261b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
18271b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
18281b42101056befe25b5f19d5b099e806a2ecee9cdplougher
18291b42101056befe25b5f19d5b099e806a2ecee9cdplougher
18301b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid disable_progress_bar()
18311b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
18321b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
18331b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_enabled = FALSE;
18341b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
18351b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
18361b42101056befe25b5f19d5b099e806a2ecee9cdplougher
18371b42101056befe25b5f19d5b099e806a2ecee9cdplougher
1838eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar()
1839eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
18401b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
1841eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_cond_signal(&progress_wait);
18421b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
1843eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1844eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1845eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1846eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns)
1847eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1848eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	char rotate_list[] = { '|', '/', '-', '\\' };
184984ece5dece9234d3ec58f988690c02aa41b41eb0plougher	int max_digits = floor(log10(max)) + 1;
1850eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	int used = max_digits * 2 + 11;
1851eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	int hashes = (current * (columns - used)) / max;
1852eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	int spaces = columns - used - hashes;
1853dce832998340bea4236fddb5ba1525121044ce18plougher	static int tty = -1;
1854eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1855eaf639366792995c36ae7295bddf534f6f416643plougher	if((current > max) || (columns - used < 0))
1856eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		return;
1857eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1858dce832998340bea4236fddb5ba1525121044ce18plougher	if(tty == -1)
1859dce832998340bea4236fddb5ba1525121044ce18plougher		tty = isatty(STDOUT_FILENO);
1860dce832998340bea4236fddb5ba1525121044ce18plougher	if(!tty) {
1861dce832998340bea4236fddb5ba1525121044ce18plougher		static long long previous = -1;
1862dce832998340bea4236fddb5ba1525121044ce18plougher
1863dce832998340bea4236fddb5ba1525121044ce18plougher		/* Updating much more frequently than this results in huge
1864dce832998340bea4236fddb5ba1525121044ce18plougher		 * log files. */
1865dce832998340bea4236fddb5ba1525121044ce18plougher		if((current % 100) != 0 && current != max)
1866dce832998340bea4236fddb5ba1525121044ce18plougher			return;
1867dce832998340bea4236fddb5ba1525121044ce18plougher		/* Don't update just to rotate the spinner. */
1868dce832998340bea4236fddb5ba1525121044ce18plougher		if(current == previous)
1869dce832998340bea4236fddb5ba1525121044ce18plougher			return;
1870dce832998340bea4236fddb5ba1525121044ce18plougher		previous = current;
1871dce832998340bea4236fddb5ba1525121044ce18plougher	}
1872dce832998340bea4236fddb5ba1525121044ce18plougher
1873eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("\r[");
1874eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1875eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while (hashes --)
1876eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar('=');
1877eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1878eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	putchar(rotate_list[rotate]);
1879eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1880eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(spaces --)
1881eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar(' ');
1882eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1883eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("] %*lld/%*lld", max_digits, current, max_digits, max);
1884eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf(" %3lld%%", current * 100 / max);
1885eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	fflush(stdout);
1886eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1887eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1888eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1889443c15812032991c98b33b5424b17bcd55fe3575plougher#define VERSION() \
1890513f37ed1a2bef56f1681c0e3eec8971e4f0bd65plougher	printf("unsquashfs version 4.0-CVS (2009/03/29)\n");\
1891d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("copyright (C) 2009 Phillip Lougher <phillip@lougher.demon.co.uk>"\
1892d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n\n");\
1893443c15812032991c98b33b5424b17bcd55fe3575plougher    	printf("This program is free software; you can redistribute it and/or\n");\
1894443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("modify it under the terms of the GNU General Public License\n");\
1895d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("as published by the Free Software Foundation; either version 2,"\
1896d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
1897443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("or (at your option) any later version.\n\n");\
1898d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("This program is distributed in the hope that it will be useful,"\
1899d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
1900d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of"\
1901d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
1902d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the"\
1903d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
1904443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("GNU General Public License for more details.\n");
1905443c15812032991c98b33b5424b17bcd55fe3575plougherint main(int argc, char *argv[])
1906443c15812032991c98b33b5424b17bcd55fe3575plougher{
1907443c15812032991c98b33b5424b17bcd55fe3575plougher	char *dest = "squashfs-root";
1908b624936abba03d38b7e9245c647339d8f6f34274plougher	int i, stat_sys = FALSE, version = FALSE;
1909545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	int n;
1910a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *paths = NULL;
1911a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathname *path = NULL;
1912ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int fragment_buffer_size = FRAGMENT_BUFFER_DEFAULT;
1913ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int data_buffer_size = DATA_BUFFER_DEFAULT;
19140cf5c297bec42c7c220d2825f12f9499f2293279plougher	char *b;
1915eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct winsize winsize;
1916443c15812032991c98b33b5424b17bcd55fe3575plougher
19171b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_init(&screen_mutex, NULL);
1918545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	root_process = geteuid() == 0;
1919545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	if(root_process)
19209dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		umask(0);
19219dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
1922443c15812032991c98b33b5424b17bcd55fe3575plougher	for(i = 1; i < argc; i++) {
1923443c15812032991c98b33b5424b17bcd55fe3575plougher		if(*argv[i] != '-')
1924443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1925d4204758f77acb5a371fa1487a755b76a05d5476plougher		if(strcmp(argv[i], "-version") == 0 ||
1926d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-v") == 0) {
1927443c15812032991c98b33b5424b17bcd55fe3575plougher			VERSION();
1928443c15812032991c98b33b5424b17bcd55fe3575plougher			version = TRUE;
1929d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-info") == 0 ||
1930d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-i") == 0)
1931443c15812032991c98b33b5424b17bcd55fe3575plougher			info = TRUE;
1932a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher		else if(strcmp(argv[i], "-ls") == 0 || strcmp(argv[i], "-l") == 0)
1933443c15812032991c98b33b5424b17bcd55fe3575plougher			lsonly = TRUE;
1934d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-no-progress") == 0 ||
1935d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-n") == 0)
1936296d7d8a68e33341d68f4354b5e1fe2f3aa275a6plougher			progress = FALSE;
1937d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-dest") == 0 ||
1938d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-d") == 0) {
193971add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
1940d4204758f77acb5a371fa1487a755b76a05d5476plougher				fprintf(stderr, "%s: -dest missing filename\n",
1941d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
194271add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
194371add234b27054974d5e29f95b3fab3072792a62plougher			}
1944443c15812032991c98b33b5424b17bcd55fe3575plougher			dest = argv[i];
1945d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-processors") == 0 ||
1946d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-p") == 0) {
1947d4204758f77acb5a371fa1487a755b76a05d5476plougher			if((++i == argc) || (processors = strtol(argv[i], &b, 10),
1948d4204758f77acb5a371fa1487a755b76a05d5476plougher					*b != '\0')) {
1949d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -processors missing or invalid "
1950d4204758f77acb5a371fa1487a755b76a05d5476plougher					"processor number\n", argv[0]);
19510cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
19520cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
19530cf5c297bec42c7c220d2825f12f9499f2293279plougher			if(processors < 1) {
1954d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -processors should be 1 or larger\n",
1955d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
19560cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
19570cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
1958d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-data-queue") == 0 ||
1959d4204758f77acb5a371fa1487a755b76a05d5476plougher					 strcmp(argv[i], "-da") == 0) {
1960d4204758f77acb5a371fa1487a755b76a05d5476plougher			if((++i == argc) || (data_buffer_size = strtol(argv[i], &b,
1961d4204758f77acb5a371fa1487a755b76a05d5476plougher					 10), *b != '\0')) {
1962d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -data-queue missing or invalid queue "
1963d4204758f77acb5a371fa1487a755b76a05d5476plougher					"size\n", argv[0]);
1964ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
1965ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
1966ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(data_buffer_size < 1) {
1967d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -data-queue should be 1 Mbyte or "
1968d4204758f77acb5a371fa1487a755b76a05d5476plougher					"larger\n", argv[0]);
1969ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
1970ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
1971d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-frag-queue") == 0 ||
1972d4204758f77acb5a371fa1487a755b76a05d5476plougher					strcmp(argv[i], "-fr") == 0) {
1973d4204758f77acb5a371fa1487a755b76a05d5476plougher			if((++i == argc) || (fragment_buffer_size = strtol(argv[i],
1974d4204758f77acb5a371fa1487a755b76a05d5476plougher					 &b, 10), *b != '\0')) {
1975d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -frag-queue missing or invalid queue "
1976d4204758f77acb5a371fa1487a755b76a05d5476plougher					"size\n", argv[0]);
1977ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
1978ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
1979ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(fragment_buffer_size < 1) {
1980d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -frag-queue should be 1 Mbyte or "
1981d4204758f77acb5a371fa1487a755b76a05d5476plougher					"larger\n", argv[0]);
1982ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
1983ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
1984d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-force") == 0 ||
1985d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-f") == 0)
1986a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			force = TRUE;
1987d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-stat") == 0 ||
1988d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-s") == 0)
1989b624936abba03d38b7e9245c647339d8f6f34274plougher			stat_sys = TRUE;
1990d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-lls") == 0 ||
1991d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-ll") == 0) {
19929baf35a00f38816d2054deb70184943d0686d03eplougher			lsonly = TRUE;
19939baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
1994d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-linfo") == 0 ||
1995d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-li") == 0) {
19969baf35a00f38816d2054deb70184943d0686d03eplougher			info = TRUE;
19979baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
1998d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-ef") == 0 ||
1999d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-e") == 0) {
200071add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
2001d4204758f77acb5a371fa1487a755b76a05d5476plougher				fprintf(stderr, "%s: -ef missing filename\n",
2002d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
200371add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
200471add234b27054974d5e29f95b3fab3072792a62plougher			}
2005a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			path = process_extract_files(path, argv[i]);
2006d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-regex") == 0 ||
2007d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-r") == 0)
20084dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			use_regex = TRUE;
20094dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		else
2010b624936abba03d38b7e9245c647339d8f6f34274plougher			goto options;
2011443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2012443c15812032991c98b33b5424b17bcd55fe3575plougher
2013feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher	if(lsonly || info)
2014feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher		progress = FALSE;
2015feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher
2016bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher#ifdef SQUASHFS_TRACE
2017bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher	progress = FALSE;
2018bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher#endif
2019bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher
2020443c15812032991c98b33b5424b17bcd55fe3575plougher	if(i == argc) {
2021443c15812032991c98b33b5424b17bcd55fe3575plougher		if(!version) {
2022443c15812032991c98b33b5424b17bcd55fe3575plougheroptions:
2023d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("SYNTAX: %s [options] filesystem [directories or "
2024d4204758f77acb5a371fa1487a755b76a05d5476plougher				"files to extract]\n", argv[0]);
2025d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-v[ersion]\t\tprint version, licence and "
2026d4204758f77acb5a371fa1487a755b76a05d5476plougher				"copyright information\n");
2027d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-d[est] <pathname>\tunsquash to <pathname>, "
2028d4204758f77acb5a371fa1487a755b76a05d5476plougher				"default \"squashfs-root\"\n");
2029d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-n[o-progress]\t\tdon't display the progress bar"
2030d4204758f77acb5a371fa1487a755b76a05d5476plougher				"\n");
2031d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-p[rocessors] <number>\tuse <number> processors."
2032d4204758f77acb5a371fa1487a755b76a05d5476plougher				"  By default will use\n\t\t\t\tnumber of "
2033d4204758f77acb5a371fa1487a755b76a05d5476plougher				"processors available\n");
2034d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-i[nfo]\t\t\tprint files as they are unsquashed"
2035d4204758f77acb5a371fa1487a755b76a05d5476plougher				"\n");
2036d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-li[nfo]\t\tprint files as they are unsquashed "
2037d4204758f77acb5a371fa1487a755b76a05d5476plougher				"with file\n\t\t\t\tattributes (like ls -l "
2038d4204758f77acb5a371fa1487a755b76a05d5476plougher				"output)\n");
2039d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-l[s]\t\t\tlist filesystem, but don't unsquash"
2040d4204758f77acb5a371fa1487a755b76a05d5476plougher				"\n");
2041d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-ll[s]\t\t\tlist filesystem with file attributes "
2042d4204758f77acb5a371fa1487a755b76a05d5476plougher				"(like\n\t\t\t\tls -l output), but don't unsquash"
2043d4204758f77acb5a371fa1487a755b76a05d5476plougher				"\n");
2044d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-f[orce]\t\tif file already exists then overwrite"
2045d4204758f77acb5a371fa1487a755b76a05d5476plougher				"\n");
2046d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-s[tat]\t\t\tdisplay filesystem superblock "
2047d4204758f77acb5a371fa1487a755b76a05d5476plougher				"information\n");
2048d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-e[f] <extract file>\tlist of directories or "
2049d4204758f77acb5a371fa1487a755b76a05d5476plougher				"files to extract.\n\t\t\t\tOne per line\n");
2050d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-da[ta-queue] <size>\tSet data queue to <size> "
2051d4204758f77acb5a371fa1487a755b76a05d5476plougher				"Mbytes.  Default %d\n\t\t\t\tMbytes\n",
2052d4204758f77acb5a371fa1487a755b76a05d5476plougher				DATA_BUFFER_DEFAULT);
2053d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-fr[ag-queue] <size>\tSet fagment queue to "
2054d4204758f77acb5a371fa1487a755b76a05d5476plougher				"<size> Mbytes.  Default %d\n\t\t\t\t Mbytes\n",
2055d4204758f77acb5a371fa1487a755b76a05d5476plougher				FRAGMENT_BUFFER_DEFAULT);
2056d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-r[egex]\t\ttreat extract names as POSIX regular "
2057d4204758f77acb5a371fa1487a755b76a05d5476plougher				"expressions\n\t\t\t\trather than use the default "
2058d4204758f77acb5a371fa1487a755b76a05d5476plougher				"shell wildcard\n\t\t\t\texpansion (globbing)\n");
2059443c15812032991c98b33b5424b17bcd55fe3575plougher		}
2060443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2061443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2062443c15812032991c98b33b5424b17bcd55fe3575plougher
206371add234b27054974d5e29f95b3fab3072792a62plougher	for(n = i + 1; n < argc; n++)
2064a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, argv[n], argv[n]);
2065b54566f5c433764830c29c83151691d0034de094plougher
2066443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fd = open(argv[i], O_RDONLY)) == -1) {
2067d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("Could not open %s, because %s\n", argv[i],
2068d4204758f77acb5a371fa1487a755b76a05d5476plougher			strerror(errno));
2069443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2070443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2071443c15812032991c98b33b5424b17bcd55fe3575plougher
207202bc3bcabf2b219f63961f07293b83629948f026plougher	if(read_super(argv[i]) == FALSE)
2073443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2074443c15812032991c98b33b5424b17bcd55fe3575plougher
2075b624936abba03d38b7e9245c647339d8f6f34274plougher	if(stat_sys) {
2076b624936abba03d38b7e9245c647339d8f6f34274plougher		squashfs_stat(argv[i]);
2077b624936abba03d38b7e9245c647339d8f6f34274plougher		exit(0);
2078b624936abba03d38b7e9245c647339d8f6f34274plougher	}
2079b624936abba03d38b7e9245c647339d8f6f34274plougher
2080443c15812032991c98b33b5424b17bcd55fe3575plougher	block_size = sBlk.block_size;
2081ae271cc93e3684d5314bcdc45b631e497ae43166plougher	block_log = sBlk.block_log;
2082ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2083ae271cc93e3684d5314bcdc45b631e497ae43166plougher	fragment_buffer_size <<= 20 - block_log;
2084ae271cc93e3684d5314bcdc45b631e497ae43166plougher	data_buffer_size <<= 20 - block_log;
20858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	initialise_threads(fragment_buffer_size, data_buffer_size);
20868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2087443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fragment_data = malloc(block_size)) == NULL)
2088443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate fragment_data\n");
2089443c15812032991c98b33b5424b17bcd55fe3575plougher
2090443c15812032991c98b33b5424b17bcd55fe3575plougher	if((file_data = malloc(block_size)) == NULL)
2091443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate file_data");
2092443c15812032991c98b33b5424b17bcd55fe3575plougher
2093443c15812032991c98b33b5424b17bcd55fe3575plougher	if((data = malloc(block_size)) == NULL)
2094eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		EXIT_UNSQUASH("failed to allocate data\n");
2095443c15812032991c98b33b5424b17bcd55fe3575plougher
2096443c15812032991c98b33b5424b17bcd55fe3575plougher	if((created_inode = malloc(sBlk.inodes * sizeof(char *))) == NULL)
2097443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate created_inode\n");
2098443c15812032991c98b33b5424b17bcd55fe3575plougher
2099443c15812032991c98b33b5424b17bcd55fe3575plougher	memset(created_inode, 0, sBlk.inodes * sizeof(char *));
2100443c15812032991c98b33b5424b17bcd55fe3575plougher
21011a7e7e871169a6cb6e3470a50b33db83830886e2plougher	if(s_ops.read_uids_guids() == FALSE)
21021a7e7e871169a6cb6e3470a50b33db83830886e2plougher		EXIT_UNSQUASH("failed to uid/gid table\n");
2103ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2104cce13b2f8f73a4224f9dcfe203c992a09f22c6bcplougher	if(s_ops.read_fragment_table() == FALSE)
2105cce13b2f8f73a4224f9dcfe203c992a09f22c6bcplougher		EXIT_UNSQUASH("failed to read fragment table\n");
2106ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2107d4204758f77acb5a371fa1487a755b76a05d5476plougher	uncompress_inode_table(sBlk.inode_table_start,
2108d4204758f77acb5a371fa1487a755b76a05d5476plougher		sBlk.directory_table_start);
2109ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2110d4204758f77acb5a371fa1487a755b76a05d5476plougher	uncompress_directory_table(sBlk.directory_table_start,
2111d4204758f77acb5a371fa1487a755b76a05d5476plougher		sBlk.fragment_table_start);
2112443c15812032991c98b33b5424b17bcd55fe3575plougher
2113a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if(path) {
2114a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = init_subdir();
2115a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = add_subdir(paths, path);
2116a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
2117a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
2118d4204758f77acb5a371fa1487a755b76a05d5476plougher	pre_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode),
2119d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_INODE_OFFSET(sBlk.root_inode), paths);
2120eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2121eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	memset(created_inode, 0, sBlk.inodes * sizeof(char *));
21229b58176e667b67770569c9076a410b27aaa3bcf5plougher	inode_number = 1;
2123eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2124d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("%d inodes (%d blocks) to write\n\n", total_inodes, total_inodes -
2125d4204758f77acb5a371fa1487a755b76a05d5476plougher		total_files + total_blocks);
2126eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
21271b42101056befe25b5f19d5b099e806a2ecee9cdplougher	if(progress)
21281b42101056befe25b5f19d5b099e806a2ecee9cdplougher		enable_progress_bar();
21291b42101056befe25b5f19d5b099e806a2ecee9cdplougher
2130d4204758f77acb5a371fa1487a755b76a05d5476plougher	dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode),
2131d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_INODE_OFFSET(sBlk.root_inode), paths);
2132443c15812032991c98b33b5424b17bcd55fe3575plougher
21338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_put(to_writer, NULL);
21348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_get(from_writer);
21358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
21365c7885bc293ab675812fd77a05f59c2917e3e8b4plougher	if(progress) {
21371b42101056befe25b5f19d5b099e806a2ecee9cdplougher		disable_progress_bar();
21385c7885bc293ab675812fd77a05f59c2917e3e8b4plougher		progress_bar(sym_count + dev_count + fifo_count + cur_blocks,
21391b42101056befe25b5f19d5b099e806a2ecee9cdplougher			total_inodes - total_files + total_blocks, columns);
21405c7885bc293ab675812fd77a05f59c2917e3e8b4plougher	}
2141eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2142443c15812032991c98b33b5424b17bcd55fe3575plougher	if(!lsonly) {
2143443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("\n");
2144443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d files\n", file_count);
2145443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d directories\n", dir_count);
2146443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d symlinks\n", sym_count);
2147443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d devices\n", dev_count);
2148443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d fifos\n", fifo_count);
2149443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2150eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
21519dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	return 0;
2152443c15812032991c98b33b5424b17bcd55fe3575plougher}
2153