unsquashfs.c revision 68ba26e4a9ee62315d5d2bf5c23bfbc02347b646
168ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher, size/*
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;
524dba330d7b952f2f044d38e342e2ae3ea78910d6plougherint lsonly = FALSE, info = FALSE, force = FALSE, short_ls = TRUE, use_regex = FALSE;
53443c15812032991c98b33b5424b17bcd55fe3575plougherchar **created_inode;
549dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint root_process;
55eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint columns;
56eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint rotate = 0;
571b42101056befe25b5f19d5b099e806a2ecee9cdplougherpthread_mutex_t	screen_mutex;
58eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherpthread_cond_t progress_wait;
591b42101056befe25b5f19d5b099e806a2ecee9cdplougherint progress = TRUE, progress_enabled = FALSE;
60eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int total_blocks = 0, total_files = 0, total_inodes = 0;
61eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int cur_blocks = 0;
62ed5124f016834932db2c63d60d259d846171c216plougherint inode_number = 1;
63443c15812032991c98b33b5424b17bcd55fe3575plougher
64476dcb48b24efff22caa970f000e151f1b28918dplougherint lookup_type[] = {
65476dcb48b24efff22caa970f000e151f1b28918dplougher	0,
66476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
67476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFREG,
68476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFLNK,
69476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFBLK,
70476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFCHR,
71476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFIFO,
72476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFSOCK,
73476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
74eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFREG,
75eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFLNK,
76eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFBLK,
77eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFCHR,
78eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFIFO,
79eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFSOCK
80476dcb48b24efff22caa970f000e151f1b28918dplougher};
81476dcb48b24efff22caa970f000e151f1b28918dplougher
82476dcb48b24efff22caa970f000e151f1b28918dplougherstruct test table[] = {
83476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFSOCK, 0, 's' },
84476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFLNK, 0, 'l' },
85476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFBLK, 0, 'b' },
86476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFDIR, 0, 'd' },
87476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFCHR, 0, 'c' },
88476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFIFO, 0, 'p' },
89476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRUSR, S_IRUSR, 1, 'r' },
90476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWUSR, S_IWUSR, 2, 'w' },
91476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRGRP, S_IRGRP, 4, 'r' },
92476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWGRP, S_IWGRP, 5, 'w' },
93476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IROTH, S_IROTH, 7, 'r' },
94476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWOTH, S_IWOTH, 8, 'w' },
95476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR | S_ISUID, 3, 's' },
96476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_ISUID, 3, 'S' },
97476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR, 3, 'x' },
98476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP | S_ISGID, 6, 's' },
99476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_ISGID, 6, 'S' },
100476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP, 6, 'x' },
101476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH | S_ISVTX, 9, 't' },
102476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_ISVTX, 9, 'T' },
103476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH, 9, 'x' },
1048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	{ 0, 0, 0, 0}
1058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher};
1068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
107eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns);
108eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar();
109eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
110eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid sigwinch_handler()
111eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
112eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct winsize winsize;
113eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
114eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
1151b42101056befe25b5f19d5b099e806a2ecee9cdplougher		ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 columns\n");
116eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = 80;
117eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	} else
118eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = winsize.ws_col;
119eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
120eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1221b5f6c5145f284683a2628b73ab5f8a0e37dd7b4ploughervoid sigalrm_handler()
1231b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher{
1241b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	rotate = (rotate + 1) % 4;
1251b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher}
1261b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
1271b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
1288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *queue_init(int size)
1298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct queue *queue = malloc(sizeof(struct queue));
1318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(queue == NULL)
1338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return NULL;
1348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if((queue->data = malloc(sizeof(void *) * (size + 1))) == NULL) {
1368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		free(queue);
1378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return NULL;
1388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
1398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->size = size + 1;
1418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = queue->writep = 0;
1428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&queue->mutex, NULL);
1438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->empty, NULL);
1448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->full, NULL);
1458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return queue;
1478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1508888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid queue_put(struct queue *queue, void *data)
1518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int nextp;
1538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
1558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
1578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->full, &queue->mutex);
1588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->data[queue->writep] = data;
1608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->writep = nextp;
1618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->empty);
1628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
1638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1668888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *queue_get(struct queue *queue)
1678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	void *data;
1698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
1708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(queue->readp == queue->writep)
1728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->empty, &queue->mutex);
1738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data = queue->data[queue->readp];
1758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = (queue->readp + 1) % queue->size;
1768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->full);
1778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
1788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return data;
1808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
1848888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_hash_table(struct cache *cache, struct cache_entry *entry)
1858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(entry->block);
1878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_next = cache->hash_table[hash];
1898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->hash_table[hash] = entry;
1908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = NULL;
1918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
1928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry;
1938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
1978888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_hash_table(struct cache *cache, struct cache_entry *entry)
1988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_prev)
2008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_prev->hash_next = entry->hash_next;
2018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	else
2028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->hash_table[CALCULATE_HASH(entry->block)] = entry->hash_next;
2038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
2048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry->hash_prev;
2058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = entry->hash_next = NULL;
2078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2118888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_free_list(struct cache *cache, struct cache_entry *entry)
2128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache->free_list) {
2148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next = cache->free_list;
2158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = cache->free_list->free_prev;
2168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev->free_next = entry;
2178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev = entry;
2188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
2198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = entry;
2208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = entry->free_next = entry;
2218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
2228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2268888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_free_list(struct cache *cache, struct cache_entry *entry)
2278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->free_prev == NULL && entry->free_next == NULL)
2298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* not in free list */
2308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return;
231222e49e257bccb10c0e608f071778f26fce28f01plougher	else if(entry->free_prev == entry && entry->free_next == entry) {
2328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* only this entry in the free list */
2338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = NULL;
2348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
2358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* more than one entry in the free list */
2368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next->free_prev = entry->free_prev;
2378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev->free_next = entry->free_next;
2388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->free_list == entry)
2398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->free_list = entry->free_next;
2408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
2418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->free_prev = entry->free_next = NULL;
2438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *cache_init(int buffer_size, int max_buffers)
2478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache *cache = malloc(sizeof(struct cache));
2498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache == NULL)
2518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return NULL;
2528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->max_buffers = max_buffers;
2548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->buffer_size = buffer_size;
2558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->count = 0;
2568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->free_list = NULL;
2578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536);
2588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_free = FALSE;
2598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_pending = FALSE;
2608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&cache->mutex, NULL);
2618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_free, NULL);
2628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_pending, NULL);
2638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return cache;
2658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache_entry *cache_get(struct cache *cache, long long block, int size)
2698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* Get a block out of the cache.  If the block isn't in the cache
2718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * it is added and queued to the reader() and deflate() threads for reading
2728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * off disk and decompression.  The cache grows until max_blocks is reached,
2738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * once this occurs existing discarded blocks on the free list are reused */
2748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(block);
2758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *entry;
2768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&cache->mutex);
2788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
2808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->block == block)
2818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			break;
2828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry) {
2848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* found the block in the cache, increment used count and
2858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * if necessary remove from free list so it won't disappear
2868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
2878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used ++;
2888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		remove_free_list(cache, entry);
2898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
2908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
2918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* not in the cache */
2928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* first try to allocate new block */
2948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->count < cache->max_buffers) {
2958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = malloc(sizeof(struct cache_entry));
2968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(entry == NULL)
2978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				goto failed;
2988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data = malloc(cache->buffer_size);
2998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(entry->data == NULL) {
3008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				free(entry);
3018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				goto failed;
3028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
3038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache = cache;
3048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->free_prev = entry->free_next = NULL;
3058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->count ++;
3068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		} else {
3078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			/* try to get from free list */
3088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			while(cache->free_list == NULL) {
3098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				cache->wait_free = TRUE;
3108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
3118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
3128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = cache->free_list;
3138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_free_list(cache, entry);
3148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_hash_table(cache, entry);
3158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
3168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* initialise block and insert into the hash table */
3188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->block = block;
3198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->size = size;
3208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used = 1;
3218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->error = FALSE;
3228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->pending = TRUE;
3238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_hash_table(cache, entry);
3248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* queue to read thread to read and ultimately (via the decompress
3268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * threads) decompress the buffer
3278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
3288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
3298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_reader, entry);
3308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return entry;
3338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherfailed:
3358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&cache->mutex);
3368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return NULL;
3378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3408888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_ready(struct cache_entry *entry, int error)
3418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
3428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* mark cache entry as being complete, reading and (if necessary)
3438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * decompression has taken place, and the buffer is valid for use.
3448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * If an error occurs reading or decompressing, the buffer also
3458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * becomes ready but with an error... */
3468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
3478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->pending = FALSE;
3488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->error = error;
3498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* if the wait_pending flag is set, one or more threads may be waiting on
3518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * this buffer */
3528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->cache->wait_pending) {
3538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = FALSE;
3548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_broadcast(&entry->cache->wait_for_pending);
3558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
3588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3618888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_wait(struct cache_entry *entry)
3628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
3638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* wait for this cache entry to become ready, when reading and (if necessary)
3648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * decompression has taken place */
3658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
3668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(entry->pending) {
3688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = TRUE;
3698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&entry->cache->wait_for_pending, &entry->cache->mutex);
3708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
3738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3768888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_put(struct cache_entry *entry)
3778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
3788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* finished with this cache entry, once the usage count reaches zero it
3798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * can be reused and is put onto the free list.  As it remains accessible
3808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * via the hash table it can be found getting a new lease of life before it
3818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * is reused. */
3828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
3838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->used --;
3858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->used == 0) {
3868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_free_list(entry->cache, entry);
3878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* if the wait_free flag is set, one or more threads may be waiting on
3898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 	 * this buffer */
3908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->cache->wait_free) {
3918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache->wait_free = FALSE;
3928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			pthread_cond_broadcast(&entry->cache->wait_for_free);
3938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
3948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
3978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
398476dcb48b24efff22caa970f000e151f1b28918dplougher
399476dcb48b24efff22caa970f000e151f1b28918dplougher
400476dcb48b24efff22caa970f000e151f1b28918dplougherchar *modestr(char *str, int mode)
401476dcb48b24efff22caa970f000e151f1b28918dplougher{
402476dcb48b24efff22caa970f000e151f1b28918dplougher	int i;
403476dcb48b24efff22caa970f000e151f1b28918dplougher
404476dcb48b24efff22caa970f000e151f1b28918dplougher	strcpy(str, "----------");
405476dcb48b24efff22caa970f000e151f1b28918dplougher
406476dcb48b24efff22caa970f000e151f1b28918dplougher	for(i = 0; table[i].mask != 0; i++) {
407476dcb48b24efff22caa970f000e151f1b28918dplougher		if((mode & table[i].mask) == table[i].value)
408476dcb48b24efff22caa970f000e151f1b28918dplougher			str[table[i].position] = table[i].mode;
409476dcb48b24efff22caa970f000e151f1b28918dplougher	}
410476dcb48b24efff22caa970f000e151f1b28918dplougher
411476dcb48b24efff22caa970f000e151f1b28918dplougher	return str;
412476dcb48b24efff22caa970f000e151f1b28918dplougher}
413476dcb48b24efff22caa970f000e151f1b28918dplougher
414476dcb48b24efff22caa970f000e151f1b28918dplougher
4153edfa57b6a463f7d441d995559143f4861d62e98plougher#define TOTALCHARS  25
4166f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint print_filename(char *pathname, struct inode *inode)
417476dcb48b24efff22caa970f000e151f1b28918dplougher{
4186f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	char str[11], dummy[100], dummy2[100], *userstr, *groupstr;
4196f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int padchars;
420476dcb48b24efff22caa970f000e151f1b28918dplougher	struct passwd *user;
421476dcb48b24efff22caa970f000e151f1b28918dplougher	struct group *group;
42288facddfd83e48a907b82210ddccbb4f84d80aecplougher	struct tm *t;
423476dcb48b24efff22caa970f000e151f1b28918dplougher
424476dcb48b24efff22caa970f000e151f1b28918dplougher	if(short_ls) {
425476dcb48b24efff22caa970f000e151f1b28918dplougher		printf("%s\n", pathname);
426476dcb48b24efff22caa970f000e151f1b28918dplougher		return 1;
427476dcb48b24efff22caa970f000e151f1b28918dplougher	}
428476dcb48b24efff22caa970f000e151f1b28918dplougher
4296f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((user = getpwuid(inode->uid)) == NULL) {
4306f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		sprintf(dummy, "%d", inode->uid);
4313edfa57b6a463f7d441d995559143f4861d62e98plougher		userstr = dummy;
4323edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
4333edfa57b6a463f7d441d995559143f4861d62e98plougher		userstr = user->pw_name;
4343edfa57b6a463f7d441d995559143f4861d62e98plougher
4356f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((group = getgrgid(inode->gid)) == NULL) {
4366f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		sprintf(dummy2, "%d", inode->gid);
4373edfa57b6a463f7d441d995559143f4861d62e98plougher		groupstr = dummy2;
4383edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
4393edfa57b6a463f7d441d995559143f4861d62e98plougher		groupstr = group->gr_name;
4403edfa57b6a463f7d441d995559143f4861d62e98plougher
4416f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	printf("%s %s/%s ", modestr(str, inode->mode), userstr, groupstr);
4423edfa57b6a463f7d441d995559143f4861d62e98plougher
4436f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(inode->mode & S_IFMT) {
4443edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFREG:
4453edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFDIR:
4463edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFSOCK:
4473edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFIFO:
4483edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFLNK:
4493edfa57b6a463f7d441d995559143f4861d62e98plougher			padchars = TOTALCHARS - strlen(userstr) - strlen(groupstr);
4503edfa57b6a463f7d441d995559143f4861d62e98plougher
451caf2f0f593c7f14a4e7e151eeeed773c72578f69plougher			printf("%*lld ", padchars > 0 ? padchars : 0, inode->data);
4523edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
4533edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFCHR:
4543edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFBLK:
4553edfa57b6a463f7d441d995559143f4861d62e98plougher			padchars = TOTALCHARS - strlen(userstr) - strlen(groupstr) - 7;
4563edfa57b6a463f7d441d995559143f4861d62e98plougher
45747fc2f0b451e12cddb0cc482019e6abe5bd59d46plougher			printf("%*s%3d,%3d ", padchars > 0 ? padchars : 0, " ", (int) inode->data >> 8, (int) inode->data & 0xff);
4583edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
4593edfa57b6a463f7d441d995559143f4861d62e98plougher	}
460476dcb48b24efff22caa970f000e151f1b28918dplougher
4616f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	t = localtime(&inode->time);
46288facddfd83e48a907b82210ddccbb4f84d80aecplougher
46388facddfd83e48a907b82210ddccbb4f84d80aecplougher	printf("%d-%02d-%02d %02d:%02d %s", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, pathname);
4646f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((inode->mode & S_IFMT) == S_IFLNK)
4656f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		printf(" -> %s", inode->symlink);
4663edfa57b6a463f7d441d995559143f4861d62e98plougher	printf("\n");
4673edfa57b6a463f7d441d995559143f4861d62e98plougher
468476dcb48b24efff22caa970f000e151f1b28918dplougher	return 1;
469476dcb48b24efff22caa970f000e151f1b28918dplougher}
470476dcb48b24efff22caa970f000e151f1b28918dplougher
471443c15812032991c98b33b5424b17bcd55fe3575plougher
472f404f4914fdb272a70e18664e8963d793cc90f44plougherint add_entry(struct hash_table_entry *hash_table[], long long start, int bytes)
473443c15812032991c98b33b5424b17bcd55fe3575plougher{
474443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
475443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
476443c15812032991c98b33b5424b17bcd55fe3575plougher
477443c15812032991c98b33b5424b17bcd55fe3575plougher	if((hash_table_entry = malloc(sizeof(struct hash_table_entry))) == NULL) {
478443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("add_hash: out of memory in malloc\n");
479443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
480443c15812032991c98b33b5424b17bcd55fe3575plougher	}
481443c15812032991c98b33b5424b17bcd55fe3575plougher
482443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->start = start;
483443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->bytes = bytes;
484443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->next = hash_table[hash];
485443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table[hash] = hash_table_entry;
486443c15812032991c98b33b5424b17bcd55fe3575plougher
487443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
488443c15812032991c98b33b5424b17bcd55fe3575plougher}
489443c15812032991c98b33b5424b17bcd55fe3575plougher
490443c15812032991c98b33b5424b17bcd55fe3575plougher
491f404f4914fdb272a70e18664e8963d793cc90f44plougherint lookup_entry(struct hash_table_entry *hash_table[], long long start)
492443c15812032991c98b33b5424b17bcd55fe3575plougher{
493443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
494443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
495443c15812032991c98b33b5424b17bcd55fe3575plougher
4969dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	for(hash_table_entry = hash_table[hash]; hash_table_entry;
4979dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				hash_table_entry = hash_table_entry->next)
4987a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher
499443c15812032991c98b33b5424b17bcd55fe3575plougher		if(hash_table_entry->start == start)
500443c15812032991c98b33b5424b17bcd55fe3575plougher			return hash_table_entry->bytes;
501443c15812032991c98b33b5424b17bcd55fe3575plougher
502443c15812032991c98b33b5424b17bcd55fe3575plougher	return -1;
503443c15812032991c98b33b5424b17bcd55fe3575plougher}
504443c15812032991c98b33b5424b17bcd55fe3575plougher
505443c15812032991c98b33b5424b17bcd55fe3575plougher
506443c15812032991c98b33b5424b17bcd55fe3575plougherint read_bytes(long long byte, int bytes, char *buff)
507443c15812032991c98b33b5424b17bcd55fe3575plougher{
508443c15812032991c98b33b5424b17bcd55fe3575plougher	off_t off = byte;
509443c15812032991c98b33b5424b17bcd55fe3575plougher
510fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes);
511fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
512443c15812032991c98b33b5424b17bcd55fe3575plougher	if(lseek(fd, off, SEEK_SET) == -1) {
5135d415c6659faaa7a69c9baa7175610d889747142plougher		ERROR("Lseek failed because %s\n", strerror(errno));
514443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
515443c15812032991c98b33b5424b17bcd55fe3575plougher	}
516443c15812032991c98b33b5424b17bcd55fe3575plougher
517443c15812032991c98b33b5424b17bcd55fe3575plougher	if(read(fd, buff, bytes) == -1) {
518443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("Read on destination failed because %s\n", strerror(errno));
519443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
520443c15812032991c98b33b5424b17bcd55fe3575plougher	}
521443c15812032991c98b33b5424b17bcd55fe3575plougher
522443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
523443c15812032991c98b33b5424b17bcd55fe3575plougher}
524443c15812032991c98b33b5424b17bcd55fe3575plougher
525443c15812032991c98b33b5424b17bcd55fe3575plougher
52602bc3bcabf2b219f63961f07293b83629948f026plougherint read_block(long long start, long long *next, char *block)
527443c15812032991c98b33b5424b17bcd55fe3575plougher{
528443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned short c_byte;
529443c15812032991c98b33b5424b17bcd55fe3575plougher	int offset = 2;
530443c15812032991c98b33b5424b17bcd55fe3575plougher
531443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
532443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, 2, block) == FALSE)
533fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
534443c15812032991c98b33b5424b17bcd55fe3575plougher		((unsigned char *) &c_byte)[1] = block[0];
535443c15812032991c98b33b5424b17bcd55fe3575plougher		((unsigned char *) &c_byte)[0] = block[1];
536443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
537443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, 2, (char *)&c_byte) == FALSE)
538fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
539fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
540fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ? "compressed" : "uncompressed");
541443c15812032991c98b33b5424b17bcd55fe3575plougher
54202bc3bcabf2b219f63961f07293b83629948f026plougher	if(SQUASHFS_CHECK_DATA(sBlk.flags))
543443c15812032991c98b33b5424b17bcd55fe3575plougher		offset = 3;
544443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED(c_byte)) {
545443c15812032991c98b33b5424b17bcd55fe3575plougher		char buffer[SQUASHFS_METADATA_SIZE];
546443c15812032991c98b33b5424b17bcd55fe3575plougher		int res;
547443c15812032991c98b33b5424b17bcd55fe3575plougher		unsigned long bytes = SQUASHFS_METADATA_SIZE;
548443c15812032991c98b33b5424b17bcd55fe3575plougher
549443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
550443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start + offset, c_byte, buffer) == FALSE)
551fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
552443c15812032991c98b33b5424b17bcd55fe3575plougher
553545404219cdd79c1e06ac7d0698d02a15240c4c3plougher		res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) buffer, c_byte);
554545404219cdd79c1e06ac7d0698d02a15240c4c3plougher
555545404219cdd79c1e06ac7d0698d02a15240c4c3plougher		if(res != Z_OK) {
556443c15812032991c98b33b5424b17bcd55fe3575plougher			if(res == Z_MEM_ERROR)
557443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough memory\n");
558443c15812032991c98b33b5424b17bcd55fe3575plougher			else if(res == Z_BUF_ERROR)
559443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough room in output buffer\n");
560443c15812032991c98b33b5424b17bcd55fe3575plougher			else
561443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, unknown error %d\n", res);
562fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
563443c15812032991c98b33b5424b17bcd55fe3575plougher		}
564443c15812032991c98b33b5424b17bcd55fe3575plougher		if(next)
565443c15812032991c98b33b5424b17bcd55fe3575plougher			*next = start + offset + c_byte;
566443c15812032991c98b33b5424b17bcd55fe3575plougher		return bytes;
567443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
568443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
569443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start + offset, c_byte, block) == FALSE)
570fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
571443c15812032991c98b33b5424b17bcd55fe3575plougher		if(next)
572443c15812032991c98b33b5424b17bcd55fe3575plougher			*next = start + offset + c_byte;
573443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
574443c15812032991c98b33b5424b17bcd55fe3575plougher	}
575fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
576fe3ca0609d02d78bcd11637c1220b2ff428f466aplougherfailed:
57768ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher	ERROR("read_block: failed to read block @0x%llx\n", start);
578fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	return FALSE;
579443c15812032991c98b33b5424b17bcd55fe3575plougher}
580443c15812032991c98b33b5424b17bcd55fe3575plougher
581443c15812032991c98b33b5424b17bcd55fe3575plougher
582443c15812032991c98b33b5424b17bcd55fe3575plougherint read_data_block(long long start, unsigned int size, char *block)
583443c15812032991c98b33b5424b17bcd55fe3575plougher{
584443c15812032991c98b33b5424b17bcd55fe3575plougher	int res;
585443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned long bytes = block_size;
586443c15812032991c98b33b5424b17bcd55fe3575plougher	int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
587443c15812032991c98b33b5424b17bcd55fe3575plougher
588fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte), SQUASHFS_COMPRESSED_BLOCK(c_byte) ? "compressed" : "uncompressed");
589fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
590443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED_BLOCK(size)) {
591443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, c_byte, data) == FALSE)
59268ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
593443c15812032991c98b33b5424b17bcd55fe3575plougher
594545404219cdd79c1e06ac7d0698d02a15240c4c3plougher		res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) data, c_byte);
595545404219cdd79c1e06ac7d0698d02a15240c4c3plougher
596545404219cdd79c1e06ac7d0698d02a15240c4c3plougher		if(res != Z_OK) {
597443c15812032991c98b33b5424b17bcd55fe3575plougher			if(res == Z_MEM_ERROR)
598443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough memory\n");
599443c15812032991c98b33b5424b17bcd55fe3575plougher			else if(res == Z_BUF_ERROR)
600443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough room in output buffer\n");
601443c15812032991c98b33b5424b17bcd55fe3575plougher			else
602443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, unknown error %d\n", res);
60368ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
604443c15812032991c98b33b5424b17bcd55fe3575plougher		}
605443c15812032991c98b33b5424b17bcd55fe3575plougher
606443c15812032991c98b33b5424b17bcd55fe3575plougher		return bytes;
607443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
608443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, c_byte, block) == FALSE)
60968ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
610443c15812032991c98b33b5424b17bcd55fe3575plougher
611443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
612443c15812032991c98b33b5424b17bcd55fe3575plougher	}
61368ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher
61468ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougherfailed:
61568ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher	ERROR("read_data_block: failed to read block @0x%llx, size %d\n", start, size);
61668ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher	return FALSE;
617443c15812032991c98b33b5424b17bcd55fe3575plougher}
618443c15812032991c98b33b5424b17bcd55fe3575plougher
619443c15812032991c98b33b5424b17bcd55fe3575plougher
62002bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_inode_table(long long start, long long end)
621443c15812032991c98b33b5424b17bcd55fe3575plougher{
622443c15812032991c98b33b5424b17bcd55fe3575plougher	int size = 0, bytes = 0, res;
623443c15812032991c98b33b5424b17bcd55fe3575plougher
624443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
625443c15812032991c98b33b5424b17bcd55fe3575plougher		if((size - bytes < SQUASHFS_METADATA_SIZE) &&
6269dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				((inode_table = realloc(inode_table, size +=
6279dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				SQUASHFS_METADATA_SIZE)) == NULL))
628443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_inode_table: out of memory in realloc\n");
629443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("uncompress_inode_table: reading block 0x%llx\n", start);
630443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(inode_table_hash, start, bytes);
63102bc3bcabf2b219f63961f07293b83629948f026plougher		if((res = read_block(start, &start, inode_table + bytes)) == 0) {
632443c15812032991c98b33b5424b17bcd55fe3575plougher			free(inode_table);
633443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_inode_table: failed to read block\n");
634443c15812032991c98b33b5424b17bcd55fe3575plougher		}
635443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
636443c15812032991c98b33b5424b17bcd55fe3575plougher	}
637443c15812032991c98b33b5424b17bcd55fe3575plougher}
638443c15812032991c98b33b5424b17bcd55fe3575plougher
639443c15812032991c98b33b5424b17bcd55fe3575plougher
6406f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time, unsigned int set_mode)
641443c15812032991c98b33b5424b17bcd55fe3575plougher{
6426f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	struct utimbuf times = { time, time };
643443c15812032991c98b33b5424b17bcd55fe3575plougher
644443c15812032991c98b33b5424b17bcd55fe3575plougher	if(utime(pathname, &times) == -1) {
645443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("set_attributes: failed to set time on %s, because %s\n", pathname, strerror(errno));
646443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
647443c15812032991c98b33b5424b17bcd55fe3575plougher	}
648443c15812032991c98b33b5424b17bcd55fe3575plougher
6499dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if(root_process) {
6506f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(chown(pathname, uid, guid) == -1) {
651443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("set_attributes: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno));
652443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
653443c15812032991c98b33b5424b17bcd55fe3575plougher		}
6549dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	} else
6559dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		mode &= ~07000;
6569dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
6579dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) {
6589dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		ERROR("set_attributes: failed to change mode %s, because %s\n", pathname, strerror(errno));
6599dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		return FALSE;
660443c15812032991c98b33b5424b17bcd55fe3575plougher	}
661443c15812032991c98b33b5424b17bcd55fe3575plougher
662443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
663443c15812032991c98b33b5424b17bcd55fe3575plougher}
664443c15812032991c98b33b5424b17bcd55fe3575plougher
665443c15812032991c98b33b5424b17bcd55fe3575plougher
666b9cee889506e674726856035dba52d5e1cceeb99plougherint lseek_broken = FALSE;
667c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougherchar *zero_data = NULL;
668b9cee889506e674726856035dba52d5e1cceeb99plougher
669c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougherint write_block(int file_fd, char *buffer, int size, int hole, int sparse)
670b9cee889506e674726856035dba52d5e1cceeb99plougher{
671b9cee889506e674726856035dba52d5e1cceeb99plougher	off_t off = hole;
672b9cee889506e674726856035dba52d5e1cceeb99plougher
673b9cee889506e674726856035dba52d5e1cceeb99plougher	if(hole) {
674c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if(sparse && lseek_broken == FALSE) {
675c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			 int error = lseek(file_fd, off, SEEK_CUR);
676c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			 if(error == -1)
677c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				/* failed to seek beyond end of file */
678c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				lseek_broken = TRUE;
679c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		}
680c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
681c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if((sparse == FALSE || lseek_broken) && zero_data == NULL) {
682b9cee889506e674726856035dba52d5e1cceeb99plougher			if((zero_data = malloc(block_size)) == NULL)
683b9cee889506e674726856035dba52d5e1cceeb99plougher				EXIT_UNSQUASH("write_block: failed to alloc zero data block\n");
684b9cee889506e674726856035dba52d5e1cceeb99plougher			memset(zero_data, 0, block_size);
685b9cee889506e674726856035dba52d5e1cceeb99plougher		}
686c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
687c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if(sparse == FALSE || lseek_broken) {
688b9cee889506e674726856035dba52d5e1cceeb99plougher			int blocks = (hole + block_size -1) / block_size;
689b9cee889506e674726856035dba52d5e1cceeb99plougher			int avail_bytes, i;
690b9cee889506e674726856035dba52d5e1cceeb99plougher			for(i = 0; i < blocks; i++, hole -= avail_bytes) {
691b9cee889506e674726856035dba52d5e1cceeb99plougher				avail_bytes = hole > block_size ? block_size : hole;
692b9cee889506e674726856035dba52d5e1cceeb99plougher				if(write(file_fd, zero_data, avail_bytes) < avail_bytes)
693b9cee889506e674726856035dba52d5e1cceeb99plougher					goto failure;
694b9cee889506e674726856035dba52d5e1cceeb99plougher			}
695b9cee889506e674726856035dba52d5e1cceeb99plougher		}
696b9cee889506e674726856035dba52d5e1cceeb99plougher	}
697b9cee889506e674726856035dba52d5e1cceeb99plougher
698b9cee889506e674726856035dba52d5e1cceeb99plougher	if(write(file_fd, buffer, size) < size)
699b9cee889506e674726856035dba52d5e1cceeb99plougher		goto failure;
700b9cee889506e674726856035dba52d5e1cceeb99plougher
701b9cee889506e674726856035dba52d5e1cceeb99plougher	return TRUE;
702b9cee889506e674726856035dba52d5e1cceeb99plougher
703b9cee889506e674726856035dba52d5e1cceeb99plougherfailure:
704b9cee889506e674726856035dba52d5e1cceeb99plougher	return FALSE;
705b9cee889506e674726856035dba52d5e1cceeb99plougher}
706b9cee889506e674726856035dba52d5e1cceeb99plougher
7078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
70879df93becb68081effabebba3006c794be308598plougherint write_file(struct inode *inode, char *pathname)
709443c15812032991c98b33b5424b17bcd55fe3575plougher{
7108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	unsigned int file_fd, i;
711f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher	unsigned int *block_list;
71279df93becb68081effabebba3006c794be308598plougher	int file_end = inode->data / block_size;
71379df93becb68081effabebba3006c794be308598plougher	long long start = inode->start;
7148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct squashfs_file *file;
715443c15812032991c98b33b5424b17bcd55fe3575plougher
71679df93becb68081effabebba3006c794be308598plougher	TRACE("write_file: regular file, blocks %d\n", inode->blocks);
717443c15812032991c98b33b5424b17bcd55fe3575plougher
71879df93becb68081effabebba3006c794be308598plougher	if((file_fd = open(pathname, O_CREAT | O_WRONLY | (force ? O_TRUNC : 0), (mode_t) inode->mode & 0777)) == -1) {
719443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("write_file: failed to create file %s, because %s\n", pathname,
720443c15812032991c98b33b5424b17bcd55fe3575plougher			strerror(errno));
721443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
722443c15812032991c98b33b5424b17bcd55fe3575plougher	}
723443c15812032991c98b33b5424b17bcd55fe3575plougher
72479df93becb68081effabebba3006c794be308598plougher	if((block_list = malloc(inode->blocks * sizeof(unsigned int))) == NULL)
7258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("write_file: unable to malloc block list\n");
726443c15812032991c98b33b5424b17bcd55fe3575plougher
72779df93becb68081effabebba3006c794be308598plougher	s_ops.read_block_list(block_list, inode->block_ptr, inode->blocks);
728443c15812032991c98b33b5424b17bcd55fe3575plougher
7298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if((file = malloc(sizeof(struct squashfs_file))) == NULL)
7308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("write_file: unable to malloc file\n");
731443c15812032991c98b33b5424b17bcd55fe3575plougher
7328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* the writer thread is queued a squashfs_file structure describing the
7338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * file.  If the file has one or more blocks or a fragments they are queued
7348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * separately (references to blocks in the cache). */
7358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	file->fd = file_fd;
73679df93becb68081effabebba3006c794be308598plougher	file->file_size = inode->data;
73779df93becb68081effabebba3006c794be308598plougher	file->mode = inode->mode;
73879df93becb68081effabebba3006c794be308598plougher	file->gid = inode->gid;
73979df93becb68081effabebba3006c794be308598plougher	file->uid = inode->uid;
74079df93becb68081effabebba3006c794be308598plougher	file->time = inode->time;
74179df93becb68081effabebba3006c794be308598plougher	file->pathname = strdup(pathname);
74279df93becb68081effabebba3006c794be308598plougher	file->blocks = inode->blocks + (inode->frag_bytes > 0);
7437f6692575a1b1c8d7d55afac647b72b84b79e378plougher	file->sparse = inode->sparse;
7448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_put(to_writer, file);
745443c15812032991c98b33b5424b17bcd55fe3575plougher
74679df93becb68081effabebba3006c794be308598plougher	for(i = 0; i < inode->blocks; i++) {
7478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
7488372232d2460411adaa2299c32a0a88665e44902plougher		struct file_entry *block = malloc(sizeof(struct file_entry));
7498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
7508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
7518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
7528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->offset = 0;
75379df93becb68081effabebba3006c794be308598plougher		block->size = i == file_end ? inode->data & (block_size - 1) : block_size;
7548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block_list[i] == 0) /* sparse file */
7558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			block->buffer = NULL;
7568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else {
7578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			block->buffer = cache_get(data_cache, start, block_list[i]);
7588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(block->buffer == NULL)
7598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				EXIT_UNSQUASH("write_file: cache_get failed\n");
7608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			start += c_byte;
761443c15812032991c98b33b5424b17bcd55fe3575plougher		}
7628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
763443c15812032991c98b33b5424b17bcd55fe3575plougher	}
764443c15812032991c98b33b5424b17bcd55fe3575plougher
76579df93becb68081effabebba3006c794be308598plougher	if(inode->frag_bytes) {
7668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int size;
7678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		long long start;
7688372232d2460411adaa2299c32a0a88665e44902plougher		struct file_entry *block = malloc(sizeof(struct file_entry));
7698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
7708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
7718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
77279df93becb68081effabebba3006c794be308598plougher		s_ops.read_fragment(inode->fragment, &start, &size);
7738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->buffer = cache_get(fragment_cache, start, size);
7748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block->buffer == NULL)
7758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: cache_get failed\n");
77679df93becb68081effabebba3006c794be308598plougher		block->offset = inode->offset;
77779df93becb68081effabebba3006c794be308598plougher		block->size = inode->frag_bytes;
7788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
779b9cee889506e674726856035dba52d5e1cceeb99plougher	}
780b9cee889506e674726856035dba52d5e1cceeb99plougher
781b9cee889506e674726856035dba52d5e1cceeb99plougher	free(block_list);
782443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
783443c15812032991c98b33b5424b17bcd55fe3575plougher}
784476dcb48b24efff22caa970f000e151f1b28918dplougher
785476dcb48b24efff22caa970f000e151f1b28918dplougher
7866f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint create_inode(char *pathname, struct inode *i)
787443c15812032991c98b33b5424b17bcd55fe3575plougher{
7886f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	TRACE("create_inode: pathname %s\n", pathname);
789443c15812032991c98b33b5424b17bcd55fe3575plougher
7906f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if(created_inode[i->inode_number - 1]) {
791443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("create_inode: hard link\n");
7926013a30bd39550decc2546a47e5168e57bfcfde8plougher		if(force)
7936013a30bd39550decc2546a47e5168e57bfcfde8plougher			unlink(pathname);
7946013a30bd39550decc2546a47e5168e57bfcfde8plougher
7956f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(link(created_inode[i->inode_number - 1], pathname) == -1) {
796443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("create_inode: failed to create hardlink, because %s\n", strerror(errno));
797443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
798443c15812032991c98b33b5424b17bcd55fe3575plougher		}
799443c15812032991c98b33b5424b17bcd55fe3575plougher
800443c15812032991c98b33b5424b17bcd55fe3575plougher		return TRUE;
801443c15812032991c98b33b5424b17bcd55fe3575plougher	}
802443c15812032991c98b33b5424b17bcd55fe3575plougher
8036f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(i->type) {
8046f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_FILE_TYPE:
8056f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_LREG_TYPE:
8066f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			TRACE("create_inode: regular file, file_size %lld, blocks %d\n", i->data, i->blocks);
807443c15812032991c98b33b5424b17bcd55fe3575plougher
80879df93becb68081effabebba3006c794be308598plougher			if(write_file(i, pathname))
809443c15812032991c98b33b5424b17bcd55fe3575plougher				file_count ++;
810443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
8116f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_SYMLINK_TYPE:
812545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			TRACE("create_inode: symlink, symlink_size %lld\n", i->data);
813443c15812032991c98b33b5424b17bcd55fe3575plougher
814a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
815a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
816a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
8176f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(symlink(i->symlink, pathname) == -1) {
818443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("create_inode: failed to create symlink %s, because %s\n", pathname,
819443c15812032991c98b33b5424b17bcd55fe3575plougher					strerror(errno));
820443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
821443c15812032991c98b33b5424b17bcd55fe3575plougher			}
822443c15812032991c98b33b5424b17bcd55fe3575plougher
8239dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
8246f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(lchown(pathname, i->uid, i->gid) == -1)
825443c15812032991c98b33b5424b17bcd55fe3575plougher					ERROR("create_inode: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno));
826443c15812032991c98b33b5424b17bcd55fe3575plougher			}
827443c15812032991c98b33b5424b17bcd55fe3575plougher
828443c15812032991c98b33b5424b17bcd55fe3575plougher			sym_count ++;
829443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
830443c15812032991c98b33b5424b17bcd55fe3575plougher 		case SQUASHFS_BLKDEV_TYPE:
831443c15812032991c98b33b5424b17bcd55fe3575plougher	 	case SQUASHFS_CHRDEV_TYPE: {
8326f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			int chrdev = i->type == SQUASHFS_CHRDEV_TYPE;
833545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			TRACE("create_inode: dev, rdev 0x%llx\n", i->data);
834443c15812032991c98b33b5424b17bcd55fe3575plougher
8359dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
836a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				if(force)
837a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher					unlink(pathname);
838a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
8396f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(mknod(pathname, chrdev ? S_IFCHR : S_IFBLK,
8406f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher					makedev((i->data >> 8) & 0xff, i->data & 0xff)) == -1) {
841443c15812032991c98b33b5424b17bcd55fe3575plougher					ERROR("create_inode: failed to create %s device %s, because %s\n",
8426f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher						chrdev ? "character" : "block", pathname, strerror(errno));
843443c15812032991c98b33b5424b17bcd55fe3575plougher					break;
844443c15812032991c98b33b5424b17bcd55fe3575plougher				}
8456f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				set_attributes(pathname, i->mode, i->uid, i->gid, i->time, TRUE);
846443c15812032991c98b33b5424b17bcd55fe3575plougher				dev_count ++;
847443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
848443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("create_inode: could not create %s device %s, because you're not superuser!\n",
849545404219cdd79c1e06ac7d0698d02a15240c4c3plougher					chrdev ? "character" : "block", pathname);
850443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
8516f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		}
852443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_FIFO_TYPE:
853443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: fifo\n");
854443c15812032991c98b33b5424b17bcd55fe3575plougher
855a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
856a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
857a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
858443c15812032991c98b33b5424b17bcd55fe3575plougher			if(mknod(pathname, S_IFIFO, 0) == -1) {
859443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("create_inode: failed to create fifo %s, because %s\n",
860443c15812032991c98b33b5424b17bcd55fe3575plougher					pathname, strerror(errno));
861443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
862443c15812032991c98b33b5424b17bcd55fe3575plougher			}
8636f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			set_attributes(pathname, i->mode, i->uid, i->gid, i->time, TRUE);
864443c15812032991c98b33b5424b17bcd55fe3575plougher			fifo_count ++;
865443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
866443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_SOCKET_TYPE:
867443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: socket\n");
868443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("create_inode: socket %s ignored\n", pathname);
869443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
870443c15812032991c98b33b5424b17bcd55fe3575plougher		default:
8716f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			ERROR("Unknown inode type %d in create_inode_table!\n", i->type);
872443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
873443c15812032991c98b33b5424b17bcd55fe3575plougher	}
874fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
8756f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	created_inode[i->inode_number - 1] = strdup(pathname);
876443c15812032991c98b33b5424b17bcd55fe3575plougher
877443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
878443c15812032991c98b33b5424b17bcd55fe3575plougher}
879443c15812032991c98b33b5424b17bcd55fe3575plougher
880443c15812032991c98b33b5424b17bcd55fe3575plougher
88102bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_directory_table(long long start, long long end)
882443c15812032991c98b33b5424b17bcd55fe3575plougher{
883443c15812032991c98b33b5424b17bcd55fe3575plougher	int bytes = 0, size = 0, res;
884443c15812032991c98b33b5424b17bcd55fe3575plougher
885443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
8869dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		if(size - bytes < SQUASHFS_METADATA_SIZE && (directory_table =
8879dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				realloc(directory_table, size +=
8889dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				SQUASHFS_METADATA_SIZE)) == NULL)
889443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_directory_table: out of memory in realloc\n");
890443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("uncompress_directory_table: reading block 0x%llx\n", start);
891443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(directory_table_hash, start, bytes);
89202bc3bcabf2b219f63961f07293b83629948f026plougher		if((res = read_block(start, &start, directory_table + bytes)) == 0)
893443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_directory_table: failed to read block\n");
894443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
895443c15812032991c98b33b5424b17bcd55fe3575plougher	}
896443c15812032991c98b33b5424b17bcd55fe3575plougher}
897443c15812032991c98b33b5424b17bcd55fe3575plougher
898443c15812032991c98b33b5424b17bcd55fe3575plougher
8999dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block,
9009dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherunsigned int *offset, unsigned int *type)
901443c15812032991c98b33b5424b17bcd55fe3575plougher{
902443c15812032991c98b33b5424b17bcd55fe3575plougher	if(dir->cur_entry == dir->dir_count)
903443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
904443c15812032991c98b33b5424b17bcd55fe3575plougher
905443c15812032991c98b33b5424b17bcd55fe3575plougher	*name = dir->dirs[dir->cur_entry].name;
906443c15812032991c98b33b5424b17bcd55fe3575plougher	*start_block = dir->dirs[dir->cur_entry].start_block;
907443c15812032991c98b33b5424b17bcd55fe3575plougher	*offset = dir->dirs[dir->cur_entry].offset;
908443c15812032991c98b33b5424b17bcd55fe3575plougher	*type = dir->dirs[dir->cur_entry].type;
909443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->cur_entry ++;
910443c15812032991c98b33b5424b17bcd55fe3575plougher
911443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
912443c15812032991c98b33b5424b17bcd55fe3575plougher}
913443c15812032991c98b33b5424b17bcd55fe3575plougher
914443c15812032991c98b33b5424b17bcd55fe3575plougher
915443c15812032991c98b33b5424b17bcd55fe3575ploughervoid squashfs_closedir(struct dir *dir)
916443c15812032991c98b33b5424b17bcd55fe3575plougher{
917443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir->dirs);
918443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir);
919443c15812032991c98b33b5424b17bcd55fe3575plougher}
920443c15812032991c98b33b5424b17bcd55fe3575plougher
921443c15812032991c98b33b5424b17bcd55fe3575plougher
922b54566f5c433764830c29c83151691d0034de094plougherchar *get_component(char *target, char *targname)
923b54566f5c433764830c29c83151691d0034de094plougher{
924b54566f5c433764830c29c83151691d0034de094plougher	while(*target == '/')
9253cef656655723444fb1e2de1a001e6c2a54cf81erlougher		target ++;
926b54566f5c433764830c29c83151691d0034de094plougher
927b54566f5c433764830c29c83151691d0034de094plougher	while(*target != '/' && *target!= '\0')
928b54566f5c433764830c29c83151691d0034de094plougher		*targname ++ = *target ++;
929b54566f5c433764830c29c83151691d0034de094plougher
930b54566f5c433764830c29c83151691d0034de094plougher	*targname = '\0';
931b54566f5c433764830c29c83151691d0034de094plougher
932b54566f5c433764830c29c83151691d0034de094plougher	return target;
933b54566f5c433764830c29c83151691d0034de094plougher}
934b54566f5c433764830c29c83151691d0034de094plougher
935b54566f5c433764830c29c83151691d0034de094plougher
9366ee88c6b5da9f7b3ea88ab7481db126efa01c8f4ploughervoid free_path(struct pathname *paths)
9376ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher{
9386ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	int i;
9396ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
9406ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	for(i = 0; i < paths->names; i++) {
9416ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths)
9426ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
9436ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		free(paths->name[i].name);
9446ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].preg) {
9456ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			regfree(paths->name[i].preg);
9466ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free(paths->name[i].preg);
9476ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		}
9486ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	}
9496ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
9506ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	free(paths);
9516ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher}
9526ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
9536ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
9544dba330d7b952f2f044d38e342e2ae3ea78910d6plougherstruct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
955b54566f5c433764830c29c83151691d0034de094plougher{
95671add234b27054974d5e29f95b3fab3072792a62plougher	char targname[1024];
9574dba330d7b952f2f044d38e342e2ae3ea78910d6plougher	int i, error;
95871add234b27054974d5e29f95b3fab3072792a62plougher
95971add234b27054974d5e29f95b3fab3072792a62plougher	target = get_component(target, targname);
96071add234b27054974d5e29f95b3fab3072792a62plougher
96171add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
9624dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		if((paths = malloc(sizeof(struct pathname))) == NULL)
9634dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			EXIT_UNSQUASH("failed to allocate paths\n");
9644dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
96571add234b27054974d5e29f95b3fab3072792a62plougher		paths->names = 0;
96671add234b27054974d5e29f95b3fab3072792a62plougher		paths->name = NULL;
96771add234b27054974d5e29f95b3fab3072792a62plougher	}
96871add234b27054974d5e29f95b3fab3072792a62plougher
96971add234b27054974d5e29f95b3fab3072792a62plougher	for(i = 0; i < paths->names; i++)
97071add234b27054974d5e29f95b3fab3072792a62plougher		if(strcmp(paths->name[i].name, targname) == 0)
97171add234b27054974d5e29f95b3fab3072792a62plougher			break;
97271add234b27054974d5e29f95b3fab3072792a62plougher
9736ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	if(i == paths->names) {
9746ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		/* allocate new name entry */
97571add234b27054974d5e29f95b3fab3072792a62plougher		paths->names ++;
97671add234b27054974d5e29f95b3fab3072792a62plougher		paths->name = realloc(paths->name, (i + 1) * sizeof(struct path_entry));
97771add234b27054974d5e29f95b3fab3072792a62plougher		paths->name[i].name = strdup(targname);
9786ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		paths->name[i].paths = NULL;
9794dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		if(use_regex) {
9804dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = malloc(sizeof(regex_t));
981545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			error = regcomp(paths->name[i].preg, targname, REG_EXTENDED|REG_NOSUB);
982545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			if(error) {
9834dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				char str[1024];
9844dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
9854dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				regerror(error, paths->name[i].preg, str, 1024);
9864dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				EXIT_UNSQUASH("invalid regex %s in export %s, because %s\n", targname, alltarget, str);
9874dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			}
9884dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		} else
9894dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = NULL;
9906ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
9916ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(target[0] == '\0')
9926ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			/* at leaf pathname component */
99371add234b27054974d5e29f95b3fab3072792a62plougher			paths->name[i].paths = NULL;
99471add234b27054974d5e29f95b3fab3072792a62plougher		else
9956ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			/* recurse adding child components */
9964dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].paths = add_path(NULL, target, alltarget);
9976ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	} else {
9986ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		/* existing matching entry */
9996ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths == NULL) {
10006ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			/* No sub-directory which means this is the leaf component of a
10016ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		   	   pre-existing extract which subsumes the extract currently
10026ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		   	   being added, in which case stop adding components */
10036ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else if(target[0] == '\0') {
10046ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			/* at leaf pathname component and child components exist from more
10056ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		       specific extracts, delete as they're subsumed by this extract
10066ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			*/
10076ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
10086ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			paths->name[i].paths = NULL;
10096ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else
10106ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			/* recurse adding child components */
10116ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			add_path(paths->name[i].paths, target, alltarget);
101271add234b27054974d5e29f95b3fab3072792a62plougher	}
101371add234b27054974d5e29f95b3fab3072792a62plougher
101471add234b27054974d5e29f95b3fab3072792a62plougher	return paths;
101571add234b27054974d5e29f95b3fab3072792a62plougher}
10166ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
10176ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
1018a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *init_subdir()
101971add234b27054974d5e29f95b3fab3072792a62plougher{
10208372232d2460411adaa2299c32a0a88665e44902plougher	struct pathnames *new = malloc(sizeof(struct pathnames));
1021a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	new->count = 0;
1022a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return new;
1023a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1024a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1025a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1026a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
1027a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1028a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if(paths->count % PATHS_ALLOC_SIZE == 0)
1029a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = realloc(paths, sizeof(struct pathnames *) + (paths->count + PATHS_ALLOC_SIZE) * sizeof(struct pathname *));
1030a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1031a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	paths->path[paths->count++] = path;
1032a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return paths;
1033a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1034a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1035a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1036a706f1b6bb48f288ecaf74e218ce20504bda52c6ploughervoid free_subdir(struct pathnames *paths)
1037a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1038a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free(paths);
1039a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1040a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1041a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1042a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherint matches(struct pathnames *paths, char *name, struct pathnames **new)
1043a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1044a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	int i, n;
104571add234b27054974d5e29f95b3fab3072792a62plougher
104671add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
104771add234b27054974d5e29f95b3fab3072792a62plougher		*new = NULL;
1048b54566f5c433764830c29c83151691d0034de094plougher		return TRUE;
104971add234b27054974d5e29f95b3fab3072792a62plougher	}
105071add234b27054974d5e29f95b3fab3072792a62plougher
1051a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = init_subdir();
1052a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1053a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	for(n = 0; n < paths->count; n++) {
1054a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		struct pathname *path = paths->path[n];
1055a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		for(i = 0; i < path->names; i++) {
1056a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			int match = use_regex ?
1057a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				regexec(path->name[i].preg, name, (size_t) 0, NULL, 0) == 0 :
1058a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				fnmatch(path->name[i].name, name, FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;
1059a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match && path->name[i].paths == NULL)
1060a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				/* match on a leaf component, any subdirectories will
1061a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				 * implicitly match, therefore return an empty new search set */
1062a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				goto empty_set;
1063a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1064a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match)
1065a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				/* match on a non-leaf component, add any subdirectories to
1066a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				 * the new set of subdirectories to scan for this name */
1067a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				*new = add_subdir(*new, path->name[i].paths);
1068a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		}
1069a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1070b54566f5c433764830c29c83151691d0034de094plougher
1071a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if((*new)->count == 0) {
1072a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		/* no matching names found, delete empty search set, and return
1073a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher        * FALSE */
1074a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(*new);
1075a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		*new = NULL;
1076a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		return FALSE;
1077a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1078a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1079a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	/* one or more matches with sub-directories found (no leaf matches),
1080a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher     * return new search set and return TRUE */
1081a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
1082a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1083a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherempty_set:
1084a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher   /* found matching leaf exclude, return empty search set and return TRUE */
1085a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free_subdir(*new);
1086a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = NULL;
1087a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
1088b54566f5c433764830c29c83151691d0034de094plougher}
1089b54566f5c433764830c29c83151691d0034de094plougher
1090b54566f5c433764830c29c83151691d0034de094plougher
1091eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint pre_scan(char *parent_name, unsigned int start_block, unsigned int offset, struct pathnames *paths)
1092eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1093eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	unsigned int type;
1094eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	char *name, pathname[1024];
1095eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct pathnames *new;
1096eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
1097eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1098eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1099eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(dir == NULL) {
1100eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		ERROR("pre_scan: Failed to read directory %s (%x:%x)\n", parent_name, start_block, offset);
1101eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		return FALSE;
1102eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
1103eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1104eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
1105eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		struct inode *i;
1106eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1107eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		TRACE("pre_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type);
1108eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1109eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(!matches(paths, name, &new))
1110eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			continue;
1111eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1112eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
1113eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1114eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(type == SQUASHFS_DIR_TYPE)
1115eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			pre_scan(parent_name, start_block, offset, new);
1116eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		else if(new == NULL) {
1117eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			if(type == SQUASHFS_FILE_TYPE || type == SQUASHFS_LREG_TYPE) {
1118eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				if((i = s_ops.read_inode(start_block, offset)) == NULL) {
1119eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher					ERROR("failed to read header\n");
1120eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher					continue;
1121eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
1122eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				if(created_inode[i->inode_number - 1] == NULL) {
1123eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher					created_inode[i->inode_number - 1] = (char *) i;
1124eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher					total_blocks += (i->data + (block_size - 1)) >> block_log;
1125eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
1126eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				total_files ++;
1127eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			}
1128eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			total_inodes ++;
1129eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		}
1130eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1131eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		free_subdir(new);
1132eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
1133eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1134eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	squashfs_closedir(dir);
1135eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1136eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	return TRUE;
1137eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1138eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1139eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1140a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherint dir_scan(char *parent_name, unsigned int start_block, unsigned int offset, struct pathnames *paths)
1141443c15812032991c98b33b5424b17bcd55fe3575plougher{
1142443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int type;
1143443c15812032991c98b33b5424b17bcd55fe3575plougher	char *name, pathname[1024];
1144a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *new;
1145eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
1146eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1147443c15812032991c98b33b5424b17bcd55fe3575plougher
1148443c15812032991c98b33b5424b17bcd55fe3575plougher	if(dir == NULL) {
1149fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher		ERROR("dir_scan: Failed to read directory %s (%x:%x)\n", parent_name, start_block, offset);
1150443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
1151443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1152443c15812032991c98b33b5424b17bcd55fe3575plougher
1153eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(lsonly || info)
1154eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		print_filename(parent_name, i);
1155eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1156a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher	if(!lsonly && mkdir(parent_name, (mode_t) dir->mode) == -1 && (!force || errno != EEXIST)) {
1157443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("dir_scan: failed to open directory %s, because %s\n", parent_name, strerror(errno));
1158443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
1159443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1160443c15812032991c98b33b5424b17bcd55fe3575plougher
1161443c15812032991c98b33b5424b17bcd55fe3575plougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
11626f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type);
1163b54566f5c433764830c29c83151691d0034de094plougher
116471add234b27054974d5e29f95b3fab3072792a62plougher
116571add234b27054974d5e29f95b3fab3072792a62plougher		if(!matches(paths, name, &new))
1166b54566f5c433764830c29c83151691d0034de094plougher			continue;
1167b54566f5c433764830c29c83151691d0034de094plougher
1168443c15812032991c98b33b5424b17bcd55fe3575plougher		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
1169fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
1170443c15812032991c98b33b5424b17bcd55fe3575plougher		if(type == SQUASHFS_DIR_TYPE)
117171add234b27054974d5e29f95b3fab3072792a62plougher			dir_scan(pathname, start_block, offset, new);
1172a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		else if(new == NULL) {
11736f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if((i = s_ops.read_inode(start_block, offset)) == NULL) {
11746f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				ERROR("failed to read header\n");
11756f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				continue;
11766f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			}
11776f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
11786f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(lsonly || info)
11796f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				print_filename(pathname, i);
11806f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
1181eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			if(!lsonly) {
11826f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				create_inode(pathname, i);
1183eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				update_progress_bar();
1184eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
1185427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher
1186427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher			if(i->type == SQUASHFS_SYMLINK_TYPE || i->type == SQUASHFS_LSYMLINK_TYPE)
1187427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher				free(i->symlink);
11886f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		}
1189a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1190a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(new);
1191443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1192443c15812032991c98b33b5424b17bcd55fe3575plougher
1193074d3f1129eae914655f6637773488052bf22327rlougher	if(!lsonly)
1194074d3f1129eae914655f6637773488052bf22327rlougher		set_attributes(parent_name, dir->mode, dir->uid, dir->guid, dir->mtime, force);
1195443c15812032991c98b33b5424b17bcd55fe3575plougher
1196443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_closedir(dir);
1197443c15812032991c98b33b5424b17bcd55fe3575plougher	dir_count ++;
1198443c15812032991c98b33b5424b17bcd55fe3575plougher
1199443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1200443c15812032991c98b33b5424b17bcd55fe3575plougher}
1201443c15812032991c98b33b5424b17bcd55fe3575plougher
1202443c15812032991c98b33b5424b17bcd55fe3575plougher
1203b624936abba03d38b7e9245c647339d8f6f34274ploughervoid squashfs_stat(char *source)
1204b624936abba03d38b7e9245c647339d8f6f34274plougher{
1205b624936abba03d38b7e9245c647339d8f6f34274plougher	time_t mkfs_time = (time_t) sBlk.mkfs_time;
1206b624936abba03d38b7e9245c647339d8f6f34274plougher	char *mkfs_str = ctime(&mkfs_time);
1207b624936abba03d38b7e9245c647339d8f6f34274plougher
1208b624936abba03d38b7e9245c647339d8f6f34274plougher#if __BYTE_ORDER == __BIG_ENDIAN
12090f74340e3b68533339adc60f418ddf59fa188f61plougher	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n", sBlk.s_major == 4 ? "" : swap ? "little endian " : "big endian ", sBlk.s_major, sBlk.s_minor, source);
1210b624936abba03d38b7e9245c647339d8f6f34274plougher#else
12110f74340e3b68533339adc60f418ddf59fa188f61plougher	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n", sBlk.s_major == 4 ? "" : swap ? "big endian " : "little endian ", sBlk.s_major, sBlk.s_minor, source);
1212b624936abba03d38b7e9245c647339d8f6f34274plougher#endif
1213b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Creation or last append time %s", mkfs_str ? mkfs_str : "failed to get time\n");
1214b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Filesystem is %sexportable via NFS\n", SQUASHFS_EXPORTABLE(sBlk.flags) ? "" : "not ");
1215b624936abba03d38b7e9245c647339d8f6f34274plougher
1216b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags) ? "un" : "");
1217b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags) ? "un" : "");
1218b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1 && !SQUASHFS_NO_FRAGMENTS(sBlk.flags))
1219b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Fragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags) ? "un" : "");
1220b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Check data is %spresent in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk.flags) ? "" : "not ");
1221b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1) {
1222b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Fragments are %spresent in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk.flags) ? "not " : "");
1223b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Always_use_fragments option is %sspecified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags) ? "" : "not ");
1224b624936abba03d38b7e9245c647339d8f6f34274plougher	} else
1225b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Fragments are not supported by the filesystem\n");
1226b624936abba03d38b7e9245c647339d8f6f34274plougher
12270337de3977eec74e6a3d28e0d0863299246de8b7plougher	if(sBlk.s_major > 1)
12280337de3977eec74e6a3d28e0d0863299246de8b7plougher		printf("Duplicates are %sremoved\n", SQUASHFS_DUPLICATES(sBlk.flags) ? "" : "not ");
12290337de3977eec74e6a3d28e0d0863299246de8b7plougher	else
12300337de3977eec74e6a3d28e0d0863299246de8b7plougher		printf("Duplicates are removed\n");
1231b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk.bytes_used / 1024.0, sBlk.bytes_used / (1024.0 * 1024.0));
1232b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Block size %d\n", sBlk.block_size);
1233b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1)
1234b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Number of fragments %d\n", sBlk.fragments);
1235b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Number of inodes %d\n", sBlk.inodes);
12360f74340e3b68533339adc60f418ddf59fa188f61plougher	if(sBlk.s_major == 4)
12370f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of ids %d\n", sBlk.no_ids);
12380f74340e3b68533339adc60f418ddf59fa188f61plougher	else {
12390f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of uids %d\n", sBlk.no_uids);
12400f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of gids %d\n", sBlk.no_guids);
12410f74340e3b68533339adc60f418ddf59fa188f61plougher	}
1242b624936abba03d38b7e9245c647339d8f6f34274plougher
1243b624936abba03d38b7e9245c647339d8f6f34274plougher	TRACE("sBlk.inode_table_start 0x%llx\n", sBlk.inode_table_start);
1244b624936abba03d38b7e9245c647339d8f6f34274plougher	TRACE("sBlk.directory_table_start 0x%llx\n", sBlk.directory_table_start);
12450f74340e3b68533339adc60f418ddf59fa188f61plougher	if(sBlk.s_major == 4)
12460f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.id_table_start 0x%llx\n", sBlk.id_table_start);
12470f74340e3b68533339adc60f418ddf59fa188f61plougher	else {
12480f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.uid_start 0x%llx\n", sBlk.uid_start);
12490f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.guid_start 0x%llx\n", sBlk.guid_start);
12500f74340e3b68533339adc60f418ddf59fa188f61plougher	}
1251b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1)
1252b624936abba03d38b7e9245c647339d8f6f34274plougher		TRACE("sBlk.fragment_table_start 0x%llx\n\n", sBlk.fragment_table_start);
1253b624936abba03d38b7e9245c647339d8f6f34274plougher}
1254b624936abba03d38b7e9245c647339d8f6f34274plougher
1255b624936abba03d38b7e9245c647339d8f6f34274plougher
125602bc3bcabf2b219f63961f07293b83629948f026plougherint read_super(char *source)
1257443c15812032991c98b33b5424b17bcd55fe3575plougher{
12586490378e5b5e8dc058daf28423a7465699a6ba7bplougher	squashfs_super_block_3 sBlk_3;
12596490378e5b5e8dc058daf28423a7465699a6ba7bplougher	squashfs_super_block sBlk_4;
12606490378e5b5e8dc058daf28423a7465699a6ba7bplougher
12616490378e5b5e8dc058daf28423a7465699a6ba7bplougher	/*
12626490378e5b5e8dc058daf28423a7465699a6ba7bplougher	 * Try to read a Squashfs 4 superblock
12636490378e5b5e8dc058daf28423a7465699a6ba7bplougher	 */
12646490378e5b5e8dc058daf28423a7465699a6ba7bplougher	read_bytes(SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk_4);
126554660e177ba40ab08ee2f3304b9f030eb5675677plougher	swap = sBlk_4.s_magic != SQUASHFS_MAGIC;
12666490378e5b5e8dc058daf28423a7465699a6ba7bplougher	SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4);
12676490378e5b5e8dc058daf28423a7465699a6ba7bplougher
126833277b81b13643bb3b89a710d6612c182f36d1a6plougher	if(sBlk_4.s_magic == SQUASHFS_MAGIC && sBlk_4.s_major == 4 && sBlk_4.s_minor == 0) {
12696490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.squashfs_opendir = squashfs_opendir_4;
12706490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_fragment = read_fragment_4;
12716490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_fragment_table = read_fragment_table_4;
12726490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_block_list = read_block_list_2;
12736490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_inode = read_inode_4;
12746490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_uids_guids = read_uids_guids_4;
12756490378e5b5e8dc058daf28423a7465699a6ba7bplougher		memcpy(&sBlk, &sBlk_4, sizeof(sBlk_4));
12766490378e5b5e8dc058daf28423a7465699a6ba7bplougher		return TRUE;
12776490378e5b5e8dc058daf28423a7465699a6ba7bplougher	}
12786490378e5b5e8dc058daf28423a7465699a6ba7bplougher
12796490378e5b5e8dc058daf28423a7465699a6ba7bplougher	/*
12806490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 * Not a Squashfs 4 superblock, try to read a squashfs 3 superblock
12816490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 * (compatible with 1 and 2 filesystems)
12826490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 */
12836490378e5b5e8dc058daf28423a7465699a6ba7bplougher	read_bytes(SQUASHFS_START, sizeof(squashfs_super_block_3), (char *) &sBlk_3);
1284443c15812032991c98b33b5424b17bcd55fe3575plougher
1285443c15812032991c98b33b5424b17bcd55fe3575plougher	/* Check it is a SQUASHFS superblock */
1286443c15812032991c98b33b5424b17bcd55fe3575plougher	swap = 0;
128721ee4773956342a8a7d0f14e430ae77ffbd10601plougher	if(sBlk_3.s_magic != SQUASHFS_MAGIC) {
128821ee4773956342a8a7d0f14e430ae77ffbd10601plougher		if(sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP) {
12897a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher			squashfs_super_block_3 sblk;
1290443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("Reading a different endian SQUASHFS filesystem on %s\n", source);
12916490378e5b5e8dc058daf28423a7465699a6ba7bplougher			SQUASHFS_SWAP_SUPER_BLOCK_3(&sblk, &sBlk_3);
12926490378e5b5e8dc058daf28423a7465699a6ba7bplougher			memcpy(&sBlk_3, &sblk, sizeof(squashfs_super_block_3));
1293443c15812032991c98b33b5424b17bcd55fe3575plougher			swap = 1;
1294443c15812032991c98b33b5424b17bcd55fe3575plougher		} else  {
1295443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("Can't find a SQUASHFS superblock on %s\n", source);
1296443c15812032991c98b33b5424b17bcd55fe3575plougher			goto failed_mount;
1297443c15812032991c98b33b5424b17bcd55fe3575plougher		}
1298443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1299443c15812032991c98b33b5424b17bcd55fe3575plougher
13006490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.s_magic = sBlk_3.s_magic;
13016490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.inodes = sBlk_3.inodes;
13026490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.mkfs_time = sBlk_3.mkfs_time;
13036490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.block_size = sBlk_3.block_size;
13046490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.fragments = sBlk_3.fragments;
13056490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.block_log = sBlk_3.block_log;
13066490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.flags = sBlk_3.flags;
13076490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.s_major = sBlk_3.s_major;
13086490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.s_minor = sBlk_3.s_minor;
13096490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.root_inode = sBlk_3.root_inode;
13106490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.bytes_used = sBlk_3.bytes_used;
13116490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.inode_table_start = sBlk_3.inode_table_start;
13126490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.directory_table_start = sBlk_3.directory_table_start;
13136490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.fragment_table_start = sBlk_3.fragment_table_start;
13146490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.lookup_table_start = sBlk_3.lookup_table_start;
13156490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.no_uids = sBlk_3.no_uids;
13166490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.no_guids = sBlk_3.no_guids;
13176490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.uid_start = sBlk_3.uid_start;
13186490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.guid_start = sBlk_3.guid_start;
13196490378e5b5e8dc058daf28423a7465699a6ba7bplougher
1320443c15812032991c98b33b5424b17bcd55fe3575plougher	/* Check the MAJOR & MINOR versions */
1321ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	if(sBlk.s_major == 1 || sBlk.s_major == 2) {
13226490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.bytes_used = sBlk_3.bytes_used_2;
13236490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.uid_start = sBlk_3.uid_start_2;
13246490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.guid_start = sBlk_3.guid_start_2;
13256490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.inode_table_start = sBlk_3.inode_table_start_2;
13266490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.directory_table_start = sBlk_3.directory_table_start_2;
132702bc3bcabf2b219f63961f07293b83629948f026plougher
1328ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		if(sBlk.s_major == 1) {
13296490378e5b5e8dc058daf28423a7465699a6ba7bplougher			sBlk.block_size = sBlk_3.block_size_1;
13305ff400bfbae6bb397cf3110190e83a29725fcd07plougher			sBlk.fragment_table_start = sBlk.uid_start;
1331ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.squashfs_opendir = squashfs_opendir_1;
1332ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_1;
1333ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_block_list = read_block_list_1;
13346f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_1;
133579e700efc62527661ce140bd1013a2b60577917eplougher			s_ops.read_uids_guids = read_uids_guids_1;
1336ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		} else {
13376490378e5b5e8dc058daf28423a7465699a6ba7bplougher			sBlk.fragment_table_start = sBlk_3.fragment_table_start_2;
1338ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.squashfs_opendir = squashfs_opendir_1;
1339ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment = read_fragment_2;
1340ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_2;
1341ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.read_block_list = read_block_list_2;
13426f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_2;
134379e700efc62527661ce140bd1013a2b60577917eplougher			s_ops.read_uids_guids = read_uids_guids_1;
1344ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		}
13454ce87501a1b07102cef9750060d9a53cd5b00a61plougher	} else if(sBlk.s_major == 3) {
1346ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.squashfs_opendir = squashfs_opendir_3;
1347ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_fragment = read_fragment_3;
1348ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_fragment_table = read_fragment_table_3;
1349ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_block_list = read_block_list_2;
1350ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_inode = read_inode_3;
135179e700efc62527661ce140bd1013a2b60577917eplougher		s_ops.read_uids_guids = read_uids_guids_1;
135202bc3bcabf2b219f63961f07293b83629948f026plougher	} else {
13534c99cb7f458d8e1c598f1c80793daf3696c9b528plougher		ERROR("Filesystem on %s is (%d:%d), ", source, sBlk.s_major, sBlk.s_minor);
13544c99cb7f458d8e1c598f1c80793daf3696c9b528plougher		ERROR("which is a later filesystem version than I support!\n");
1355443c15812032991c98b33b5424b17bcd55fe3575plougher		goto failed_mount;
1356443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1357443c15812032991c98b33b5424b17bcd55fe3575plougher
1358443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1359443c15812032991c98b33b5424b17bcd55fe3575plougher
1360443c15812032991c98b33b5424b17bcd55fe3575plougherfailed_mount:
1361443c15812032991c98b33b5424b17bcd55fe3575plougher	return FALSE;
1362443c15812032991c98b33b5424b17bcd55fe3575plougher}
1363443c15812032991c98b33b5424b17bcd55fe3575plougher
1364443c15812032991c98b33b5424b17bcd55fe3575plougher
1365a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathname *process_extract_files(struct pathname *path, char *filename)
136671add234b27054974d5e29f95b3fab3072792a62plougher{
136771add234b27054974d5e29f95b3fab3072792a62plougher	FILE *fd;
136871add234b27054974d5e29f95b3fab3072792a62plougher	char name[16384];
136971add234b27054974d5e29f95b3fab3072792a62plougher
13704dba330d7b952f2f044d38e342e2ae3ea78910d6plougher	if((fd = fopen(filename, "r")) == NULL)
13714dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		EXIT_UNSQUASH("Could not open %s, because %s\n", filename, strerror(errno));
137271add234b27054974d5e29f95b3fab3072792a62plougher
137371add234b27054974d5e29f95b3fab3072792a62plougher	while(fscanf(fd, "%16384[^\n]\n", name) != EOF)
1374a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, name, name);
137571add234b27054974d5e29f95b3fab3072792a62plougher
137671add234b27054974d5e29f95b3fab3072792a62plougher	fclose(fd);
1377a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return path;
137871add234b27054974d5e29f95b3fab3072792a62plougher}
137971add234b27054974d5e29f95b3fab3072792a62plougher
138071add234b27054974d5e29f95b3fab3072792a62plougher
13818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* reader thread.  This thread processes read requests queued by the
13828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * cache_get() routine. */
13838888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *reader(void *arg)
13848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
13858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
13868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct cache_entry *entry = queue_get(to_reader);
13878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int res = read_bytes(entry->block,
13888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size),
13898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data);
13908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
13918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(res && SQUASHFS_COMPRESSED_BLOCK(entry->size))
13928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			/* queue successfully read block to the deflate thread(s)
13938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 			 * for further processing */
13948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			queue_put(to_deflate, entry);
13958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else
13968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			/* block has either been successfully read and is uncompressed,
13978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 			 * or an error has occurred, clear pending flag, set
13988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 			 * error appropriately, and wake up any threads waiting on
13998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 			 * this buffer */
14008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_ready(entry, !res);
14018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
14028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
14038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* writer thread.  This processes file write requests queued by the
14068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * write_file() routine. */
14078888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *writer(void *arg)
14088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
14098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int i;
14108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
14128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct squashfs_file *file = queue_get(to_writer);
14138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int file_fd;
14148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int hole = 0;
141527636cb2cec37a68313f9eb825c0548245eecad0plougher		int failed = FALSE;
1416c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		int error;
14178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(file == NULL) {
14198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			queue_put(from_writer, NULL);
14208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			continue;
14218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
14228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		TRACE("writer: regular file, blocks %d\n", file->blocks);
14248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		file_fd = file->fd;
14268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1427eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		for(i = 0; i < file->blocks; i++, cur_blocks ++) {
14288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			struct file_entry *block = queue_get(to_writer);
14298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(block->buffer == 0) { /* sparse file */
14318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole += block->size;
14328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				free(block);
14338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				continue;
14348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
14358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_wait(block->buffer);
143727636cb2cec37a68313f9eb825c0548245eecad0plougher
143827636cb2cec37a68313f9eb825c0548245eecad0plougher			if(block->buffer->error)
143927636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
144027636cb2cec37a68313f9eb825c0548245eecad0plougher
1441c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			if(failed)
1442c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				continue;
1443c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
1444c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			error = write_block(file_fd, block->buffer->data +
1445c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				block->offset, block->size, hole, file->sparse);
1446c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
1447c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			if(error == FALSE) {
14488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				ERROR("writer: failed to write data block %d\n", i);
144927636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
14508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
1451c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
14528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			hole = 0;
14538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_put(block->buffer);
14548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			free(block);
14558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
14568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
145727636cb2cec37a68313f9eb825c0548245eecad0plougher		if(hole && failed == FALSE) {
14588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			/* corner case for hole extending to end of file */
1459c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			if(file->sparse == FALSE || lseek(file_fd, hole, SEEK_CUR) == -1) {
1460c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				/* for files which we don't want to write
1461c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * sparsely, or for broken lseeks which cannot
1462c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * seek beyond end of file, write_block will do
1463c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * the right thing
1464c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 */
14658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole --;
1466c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				if(write_block(file_fd, "\0", 1, hole, file->sparse) == FALSE) {
14678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher					ERROR("writer: failed to write sparse data block\n");
146827636cb2cec37a68313f9eb825c0548245eecad0plougher					failed = TRUE;
14698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				}
14708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			} else if(ftruncate(file_fd, file->file_size) == -1) {
14718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				ERROR("writer: failed to write sparse data block\n");
147227636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
14738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
14748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
14758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		close(file_fd);
147727636cb2cec37a68313f9eb825c0548245eecad0plougher		if(failed == FALSE)
147827636cb2cec37a68313f9eb825c0548245eecad0plougher			set_attributes(file->pathname, file->mode, file->uid, file->gid, file->time, force);
147927636cb2cec37a68313f9eb825c0548245eecad0plougher		else {
148027636cb2cec37a68313f9eb825c0548245eecad0plougher			ERROR("Failed to write %s, skipping\n", file->pathname);
148127636cb2cec37a68313f9eb825c0548245eecad0plougher			unlink(file->pathname);
148227636cb2cec37a68313f9eb825c0548245eecad0plougher		}
148379df93becb68081effabebba3006c794be308598plougher		free(file->pathname);
14848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		free(file);
148527636cb2cec37a68313f9eb825c0548245eecad0plougher
14868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
14878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
14888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* decompress thread.  This decompresses buffers queued by the read thread */
14918888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *deflator(void *arg)
14928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
14938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	char tmp[block_size];
14948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
14958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
14968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct cache_entry *entry = queue_get(to_deflate);
14978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int res;
14988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		unsigned long bytes = block_size;
14998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		res = uncompress((unsigned char *) tmp, &bytes, (const unsigned char *) entry->data, SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size));
15018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(res != Z_OK) {
15038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(res == Z_MEM_ERROR)
15048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				ERROR("zlib::uncompress failed, not enough memory\n");
15058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			else if(res == Z_BUF_ERROR)
15068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				ERROR("zlib::uncompress failed, not enough room in output buffer\n");
15078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			else
15088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				ERROR("zlib::uncompress failed, unknown error %d\n", res);
15098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		} else
15108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			memcpy(entry->data, tmp, bytes);
15118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* block has been either successfully decompressed, or an error
15138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * occurred, clear pending flag, set error appropriately and
15148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * wake up any threads waiting on this block */
15158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache_block_ready(entry, res != Z_OK);
15168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
15178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
15188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1520eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid *progress_thread(void *arg)
1521eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1522eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct timeval timeval;
1523eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct timespec timespec;
15241b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct itimerval itimerval;
15251b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct winsize winsize;
15261b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
15271b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
15281b42101056befe25b5f19d5b099e806a2ecee9cdplougher		ERROR("TIOCGWINZ ioctl failed, defaulting to 80 columns\n");
15291b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = 80;
15301b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	} else
15311b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = winsize.ws_col;
15321b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGWINCH, sigwinch_handler);
15331b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGALRM, sigalrm_handler);
15341b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
15351b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_sec = 0;
15361b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_usec = 250000;
15371b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_sec = 0;
15381b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_usec = 250000;
15391b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	setitimer(ITIMER_REAL, &itimerval, NULL);
1540eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1541eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_cond_init(&progress_wait, NULL);
1542eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
15431b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
1544eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(1) {
1545eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		gettimeofday(&timeval, NULL);
1546eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		timespec.tv_sec = timeval.tv_sec;
1547eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(timeval.tv_usec + 250000 > 999999)
1548eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			timespec.tv_sec++;
1549eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) * 1000;
15501b42101056befe25b5f19d5b099e806a2ecee9cdplougher		pthread_cond_timedwait(&progress_wait, &screen_mutex, &timespec);
15511b42101056befe25b5f19d5b099e806a2ecee9cdplougher		if(progress_enabled)
15521b42101056befe25b5f19d5b099e806a2ecee9cdplougher			progress_bar(sym_count + dev_count +
15531b42101056befe25b5f19d5b099e806a2ecee9cdplougher				fifo_count + cur_blocks, total_inodes - total_files +
15541b42101056befe25b5f19d5b099e806a2ecee9cdplougher				total_blocks, columns);
1555eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
1556eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1557eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1558eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
15598888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid initialise_threads(int fragment_buffer_size, int data_buffer_size)
15608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
15618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int i;
15628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigset_t sigmask, old_mask;
15638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int all_buffers_size = fragment_buffer_size + data_buffer_size;
15648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigemptyset(&sigmask);
15668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigaddset(&sigmask, SIGINT);
15678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigaddset(&sigmask, SIGQUIT);
15688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
15698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads\n");
15708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(processors == -1) {
15728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifndef linux
15738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int mib[2];
15748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		size_t len = sizeof(processors);
15758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[0] = CTL_HW;
15778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifdef HW_AVAILCPU
15788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_AVAILCPU;
15798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
15808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_NCPU;
15818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
15828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
15848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			ERROR("Failed to get number of available processors.  Defaulting to 1\n");
15858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors = 1;
15868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
15878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
15888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		processors = get_nprocs();
15898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
15908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
15918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1592eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if((thread = malloc((3 + processors) * sizeof(pthread_t))) == NULL)
15938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
1594eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	deflator_thread = &thread[3];
15958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
15968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	to_reader = queue_init(all_buffers_size);
15978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	to_deflate = queue_init(all_buffers_size);
1598eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	to_writer = queue_init(1000);
15998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	from_writer = queue_init(1);
16008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	fragment_cache = cache_init(block_size, fragment_buffer_size);
16018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data_cache = cache_init(block_size, data_buffer_size);
16028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[0], NULL, reader, NULL);
16038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[1], NULL, writer, NULL);
1604eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_create(&thread[2], NULL, progress_thread, NULL);
16058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&fragment_mutex, NULL);
16068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(i = 0; i < processors; i++) {
16088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) != 0 )
16098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("Failed to create thread\n");
16108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
16118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	printf("Parallel unsquashfs: Using %d processor%s\n", processors,
16138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors == 1 ? "" : "s");
16148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
16168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads\n");
16178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
16188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
16201b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid enable_progress_bar()
16211b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
16221b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
16231b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_enabled = TRUE;
16241b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
16251b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
16261b42101056befe25b5f19d5b099e806a2ecee9cdplougher
16271b42101056befe25b5f19d5b099e806a2ecee9cdplougher
16281b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid disable_progress_bar()
16291b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
16301b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
16311b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_enabled = FALSE;
16321b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
16331b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
16341b42101056befe25b5f19d5b099e806a2ecee9cdplougher
16351b42101056befe25b5f19d5b099e806a2ecee9cdplougher
1636eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar()
1637eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
16381b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
1639eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_cond_signal(&progress_wait);
16401b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
1641eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1642eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1643eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1644eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns)
1645eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1646eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	char rotate_list[] = { '|', '/', '-', '\\' };
164784ece5dece9234d3ec58f988690c02aa41b41eb0plougher	int max_digits = floor(log10(max)) + 1;
1648eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	int used = max_digits * 2 + 11;
1649eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	int hashes = (current * (columns - used)) / max;
1650eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	int spaces = columns - used - hashes;
1651eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1652eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(current > max) {
1653eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		printf("%lld %lld\n", current, max);
1654eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		return;
1655eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
1656eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
16575c7885bc293ab675812fd77a05f59c2917e3e8b4plougher	if(columns - used < 0)
1658eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		return;
1659eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1660eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("\r[");
1661eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1662eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while (hashes --)
1663eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar('=');
1664eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1665eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	putchar(rotate_list[rotate]);
1666eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1667eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(spaces --)
1668eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar(' ');
1669eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1670eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("] %*lld/%*lld", max_digits, current, max_digits, max);
1671eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf(" %3lld%%", current * 100 / max);
1672eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	fflush(stdout);
1673eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1674eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1675eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1676443c15812032991c98b33b5424b17bcd55fe3575plougher#define VERSION() \
1677c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher	printf("unsquashfs version 4.0-CVS (2009/03/24)\n");\
1678f6bc3209482f955de1d37bc8f877c6ec399736ecplougher	printf("copyright (C) 2009 Phillip Lougher <phillip@lougher.demon.co.uk>\n\n"); \
1679443c15812032991c98b33b5424b17bcd55fe3575plougher    	printf("This program is free software; you can redistribute it and/or\n");\
1680443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("modify it under the terms of the GNU General Public License\n");\
1681443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("as published by the Free Software Foundation; either version 2,\n");\
1682443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("or (at your option) any later version.\n\n");\
1683443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("This program is distributed in the hope that it will be useful,\n");\
1684443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\
1685443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");\
1686443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("GNU General Public License for more details.\n");
1687443c15812032991c98b33b5424b17bcd55fe3575plougherint main(int argc, char *argv[])
1688443c15812032991c98b33b5424b17bcd55fe3575plougher{
1689443c15812032991c98b33b5424b17bcd55fe3575plougher	char *dest = "squashfs-root";
1690b624936abba03d38b7e9245c647339d8f6f34274plougher	int i, stat_sys = FALSE, version = FALSE;
1691545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	int n;
1692a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *paths = NULL;
1693a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathname *path = NULL;
1694ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int fragment_buffer_size = FRAGMENT_BUFFER_DEFAULT;
1695ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int data_buffer_size = DATA_BUFFER_DEFAULT;
16960cf5c297bec42c7c220d2825f12f9499f2293279plougher	char *b;
1697eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct winsize winsize;
1698443c15812032991c98b33b5424b17bcd55fe3575plougher
16991b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_init(&screen_mutex, NULL);
1700545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	root_process = geteuid() == 0;
1701545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	if(root_process)
17029dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		umask(0);
17039dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
1704443c15812032991c98b33b5424b17bcd55fe3575plougher	for(i = 1; i < argc; i++) {
1705443c15812032991c98b33b5424b17bcd55fe3575plougher		if(*argv[i] != '-')
1706443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1707a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher		if(strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) {
1708443c15812032991c98b33b5424b17bcd55fe3575plougher			VERSION();
1709443c15812032991c98b33b5424b17bcd55fe3575plougher			version = TRUE;
1710a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher		} else if(strcmp(argv[i], "-info") == 0 || strcmp(argv[i], "-i") == 0)
1711443c15812032991c98b33b5424b17bcd55fe3575plougher			info = TRUE;
1712a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher		else if(strcmp(argv[i], "-ls") == 0 || strcmp(argv[i], "-l") == 0)
1713443c15812032991c98b33b5424b17bcd55fe3575plougher			lsonly = TRUE;
1714296d7d8a68e33341d68f4354b5e1fe2f3aa275a6plougher		else if(strcmp(argv[i], "-no-progress") == 0 || strcmp(argv[i], "-n") == 0)
1715296d7d8a68e33341d68f4354b5e1fe2f3aa275a6plougher			progress = FALSE;
1716a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher		else if(strcmp(argv[i], "-dest") == 0 || strcmp(argv[i], "-d") == 0) {
171771add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
171871add234b27054974d5e29f95b3fab3072792a62plougher				fprintf(stderr, "%s: -dest missing filename\n", argv[0]);
171971add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
172071add234b27054974d5e29f95b3fab3072792a62plougher			}
1721443c15812032991c98b33b5424b17bcd55fe3575plougher			dest = argv[i];
17220cf5c297bec42c7c220d2825f12f9499f2293279plougher		} else if(strcmp(argv[i], "-processors") == 0 || strcmp(argv[i], "-p") == 0) {
17230cf5c297bec42c7c220d2825f12f9499f2293279plougher			if((++i == argc) || (processors = strtol(argv[i], &b, 10), *b != '\0')) {
17240cf5c297bec42c7c220d2825f12f9499f2293279plougher				ERROR("%s: -processors missing or invalid processor number\n", argv[0]);
17250cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
17260cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
17270cf5c297bec42c7c220d2825f12f9499f2293279plougher			if(processors < 1) {
17280cf5c297bec42c7c220d2825f12f9499f2293279plougher				ERROR("%s: -processors should be 1 or larger\n", argv[0]);
17290cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
17300cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
1731ae271cc93e3684d5314bcdc45b631e497ae43166plougher		} else if(strcmp(argv[i], "-data-queue") == 0 || strcmp(argv[i], "-da") == 0) {
1732ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if((++i == argc) || (data_buffer_size = strtol(argv[i], &b, 10), *b != '\0')) {
1733ae271cc93e3684d5314bcdc45b631e497ae43166plougher				ERROR("%s: -data-queue missing or invalid queue size\n", argv[0]);
1734ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
1735ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
1736ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(data_buffer_size < 1) {
1737ae271cc93e3684d5314bcdc45b631e497ae43166plougher				ERROR("%s: -data-queue should be 1 Mbyte or larger\n", argv[0]);
1738ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
1739ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
1740ae271cc93e3684d5314bcdc45b631e497ae43166plougher		} else if(strcmp(argv[i], "-frag-queue") == 0 || strcmp(argv[i], "-fr") == 0) {
1741ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if((++i == argc) || (fragment_buffer_size = strtol(argv[i], &b, 10), *b != '\0')) {
1742ae271cc93e3684d5314bcdc45b631e497ae43166plougher				ERROR("%s: -frag-queue missing or invalid queue size\n", argv[0]);
1743ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
1744ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
1745ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(fragment_buffer_size < 1) {
1746ae271cc93e3684d5314bcdc45b631e497ae43166plougher				ERROR("%s: -frag-queue should be 1 Mbyte or larger\n", argv[0]);
1747ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
1748ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
1749a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher		} else if(strcmp(argv[i], "-force") == 0 || strcmp(argv[i], "-f") == 0)
1750a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			force = TRUE;
1751b624936abba03d38b7e9245c647339d8f6f34274plougher		else if(strcmp(argv[i], "-stat") == 0 || strcmp(argv[i], "-s") == 0)
1752b624936abba03d38b7e9245c647339d8f6f34274plougher			stat_sys = TRUE;
17539baf35a00f38816d2054deb70184943d0686d03eplougher		else if(strcmp(argv[i], "-lls") == 0 || strcmp(argv[i], "-ll") == 0) {
17549baf35a00f38816d2054deb70184943d0686d03eplougher			lsonly = TRUE;
17559baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
17563edfa57b6a463f7d441d995559143f4861d62e98plougher		} else if(strcmp(argv[i], "-linfo") == 0 || strcmp(argv[i], "-li") == 0) {
17579baf35a00f38816d2054deb70184943d0686d03eplougher			info = TRUE;
17589baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
175971add234b27054974d5e29f95b3fab3072792a62plougher		} else if(strcmp(argv[i], "-ef") == 0 || strcmp(argv[i], "-e") == 0) {
176071add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
176171add234b27054974d5e29f95b3fab3072792a62plougher				fprintf(stderr, "%s: -ef missing filename\n", argv[0]);
176271add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
176371add234b27054974d5e29f95b3fab3072792a62plougher			}
1764a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			path = process_extract_files(path, argv[i]);
17654dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		} else if(strcmp(argv[i], "-regex") == 0 || strcmp(argv[i], "-r") == 0)
17664dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			use_regex = TRUE;
17674dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		else
1768b624936abba03d38b7e9245c647339d8f6f34274plougher			goto options;
1769443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1770443c15812032991c98b33b5424b17bcd55fe3575plougher
1771feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher	if(lsonly || info)
1772feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher		progress = FALSE;
1773feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher
1774443c15812032991c98b33b5424b17bcd55fe3575plougher	if(i == argc) {
1775443c15812032991c98b33b5424b17bcd55fe3575plougher		if(!version) {
1776443c15812032991c98b33b5424b17bcd55fe3575plougheroptions:
177771add234b27054974d5e29f95b3fab3072792a62plougher			ERROR("SYNTAX: %s [options] filesystem [directories or files to extract]\n", argv[0]);
1778a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			ERROR("\t-v[ersion]\t\tprint version, licence and copyright information\n");
17790cf5c297bec42c7c220d2825f12f9499f2293279plougher			ERROR("\t-d[est] <pathname>\tunsquash to <pathname>, default \"squashfs-root\"\n");
1780296d7d8a68e33341d68f4354b5e1fe2f3aa275a6plougher			ERROR("\t-n[o-progress]\t\tdon't display the progress bar\n");
17810cf5c297bec42c7c220d2825f12f9499f2293279plougher			ERROR("\t-p[rocessors] <number>\tuse <number> processors.  By default will use\n\t\t\t\tnumber of processors available\n");
1782a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			ERROR("\t-i[nfo]\t\t\tprint files as they are unsquashed\n");
17839baf35a00f38816d2054deb70184943d0686d03eplougher			ERROR("\t-li[nfo]\t\tprint files as they are unsquashed with file\n\t\t\t\tattributes (like ls -l output)\n");
17849baf35a00f38816d2054deb70184943d0686d03eplougher			ERROR("\t-l[s]\t\t\tlist filesystem, but don't unsquash\n");
17859baf35a00f38816d2054deb70184943d0686d03eplougher			ERROR("\t-ll[s]\t\t\tlist filesystem with file attributes (like\n\t\t\t\tls -l output), but don't unsquash\n");
1786a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			ERROR("\t-f[orce]\t\tif file already exists then overwrite\n");
17870337de3977eec74e6a3d28e0d0863299246de8b7plougher			ERROR("\t-s[tat]\t\t\tdisplay filesystem superblock information\n");
178871add234b27054974d5e29f95b3fab3072792a62plougher			ERROR("\t-e[f] <extract file>\tlist of directories or files to extract.\n\t\t\t\tOne per line\n");
1789ae271cc93e3684d5314bcdc45b631e497ae43166plougher			ERROR("\t-da[ta-queue] <size>\tSet data queue to <size> Mbytes.  Default %d\n\t\t\t\tMbytes\n", DATA_BUFFER_DEFAULT);
1790ae271cc93e3684d5314bcdc45b631e497ae43166plougher			ERROR("\t-fr[ag-queue] <size>\tSet fagment queue to <size> Mbytes.  Default %d\n\t\t\t\tMbytes\n", FRAGMENT_BUFFER_DEFAULT);
17914dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			ERROR("\t-r[egex]\t\ttreat extract names as POSIX regular expressions\n\t\t\t\trather than use the default shell wildcard\n\t\t\t\texpansion (globbing)\n");
1792443c15812032991c98b33b5424b17bcd55fe3575plougher		}
1793443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
1794443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1795443c15812032991c98b33b5424b17bcd55fe3575plougher
179671add234b27054974d5e29f95b3fab3072792a62plougher	for(n = i + 1; n < argc; n++)
1797a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, argv[n], argv[n]);
1798b54566f5c433764830c29c83151691d0034de094plougher
1799443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fd = open(argv[i], O_RDONLY)) == -1) {
1800443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("Could not open %s, because %s\n", argv[i], strerror(errno));
1801443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
1802443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1803443c15812032991c98b33b5424b17bcd55fe3575plougher
180402bc3bcabf2b219f63961f07293b83629948f026plougher	if(read_super(argv[i]) == FALSE)
1805443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
1806443c15812032991c98b33b5424b17bcd55fe3575plougher
1807b624936abba03d38b7e9245c647339d8f6f34274plougher	if(stat_sys) {
1808b624936abba03d38b7e9245c647339d8f6f34274plougher		squashfs_stat(argv[i]);
1809b624936abba03d38b7e9245c647339d8f6f34274plougher		exit(0);
1810b624936abba03d38b7e9245c647339d8f6f34274plougher	}
1811b624936abba03d38b7e9245c647339d8f6f34274plougher
1812443c15812032991c98b33b5424b17bcd55fe3575plougher	block_size = sBlk.block_size;
1813ae271cc93e3684d5314bcdc45b631e497ae43166plougher	block_log = sBlk.block_log;
1814ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
1815ae271cc93e3684d5314bcdc45b631e497ae43166plougher	fragment_buffer_size <<= 20 - block_log;
1816ae271cc93e3684d5314bcdc45b631e497ae43166plougher	data_buffer_size <<= 20 - block_log;
18178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	initialise_threads(fragment_buffer_size, data_buffer_size);
18188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1819443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fragment_data = malloc(block_size)) == NULL)
1820443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate fragment_data\n");
1821443c15812032991c98b33b5424b17bcd55fe3575plougher
1822443c15812032991c98b33b5424b17bcd55fe3575plougher	if((file_data = malloc(block_size)) == NULL)
1823443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate file_data");
1824443c15812032991c98b33b5424b17bcd55fe3575plougher
1825443c15812032991c98b33b5424b17bcd55fe3575plougher	if((data = malloc(block_size)) == NULL)
1826eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		EXIT_UNSQUASH("failed to allocate data\n");
1827443c15812032991c98b33b5424b17bcd55fe3575plougher
1828443c15812032991c98b33b5424b17bcd55fe3575plougher	if((created_inode = malloc(sBlk.inodes * sizeof(char *))) == NULL)
1829443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate created_inode\n");
1830443c15812032991c98b33b5424b17bcd55fe3575plougher
1831443c15812032991c98b33b5424b17bcd55fe3575plougher	memset(created_inode, 0, sBlk.inodes * sizeof(char *));
1832443c15812032991c98b33b5424b17bcd55fe3575plougher
183379e700efc62527661ce140bd1013a2b60577917eplougher	s_ops.read_uids_guids();
1834ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
183502bc3bcabf2b219f63961f07293b83629948f026plougher	s_ops.read_fragment_table();
1836ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
183702bc3bcabf2b219f63961f07293b83629948f026plougher	uncompress_inode_table(sBlk.inode_table_start, sBlk.directory_table_start);
1838ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
183902bc3bcabf2b219f63961f07293b83629948f026plougher	uncompress_directory_table(sBlk.directory_table_start, sBlk.fragment_table_start);
1840443c15812032991c98b33b5424b17bcd55fe3575plougher
1841a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if(path) {
1842a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = init_subdir();
1843a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = add_subdir(paths, path);
1844a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1845a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1846eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pre_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode), SQUASHFS_INODE_OFFSET(sBlk.root_inode), paths);
1847eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1848eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	memset(created_inode, 0, sBlk.inodes * sizeof(char *));
18499b58176e667b67770569c9076a410b27aaa3bcf5plougher	inode_number = 1;
1850eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1851b336488f2497ba8da6dcf9086e4b0b104f8fe072plougher	printf("%d inodes (%d blocks) to write\n\n", total_inodes, total_inodes - total_files + total_blocks);
1852eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
18531b42101056befe25b5f19d5b099e806a2ecee9cdplougher	if(progress)
18541b42101056befe25b5f19d5b099e806a2ecee9cdplougher		enable_progress_bar();
18551b42101056befe25b5f19d5b099e806a2ecee9cdplougher
185671add234b27054974d5e29f95b3fab3072792a62plougher	dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode), SQUASHFS_INODE_OFFSET(sBlk.root_inode), paths);
1857443c15812032991c98b33b5424b17bcd55fe3575plougher
18588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_put(to_writer, NULL);
18598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_get(from_writer);
18608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18615c7885bc293ab675812fd77a05f59c2917e3e8b4plougher	if(progress) {
18621b42101056befe25b5f19d5b099e806a2ecee9cdplougher		disable_progress_bar();
18635c7885bc293ab675812fd77a05f59c2917e3e8b4plougher		progress_bar(sym_count + dev_count + fifo_count + cur_blocks,
18641b42101056befe25b5f19d5b099e806a2ecee9cdplougher			total_inodes - total_files + total_blocks, columns);
18655c7885bc293ab675812fd77a05f59c2917e3e8b4plougher	}
1866eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1867443c15812032991c98b33b5424b17bcd55fe3575plougher	if(!lsonly) {
1868443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("\n");
1869443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d files\n", file_count);
1870443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d directories\n", dir_count);
1871443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d symlinks\n", sym_count);
1872443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d devices\n", dev_count);
1873443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d fifos\n", fifo_count);
1874443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1875eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
18769dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	return 0;
1877443c15812032991c98b33b5424b17bcd55fe3575plougher}
1878