unsquashfs.c revision afbbfbf11bc846056666d073c94a9c8e84fcb1ca
12f60990fb0352f7a30e0281a066458dbf033618bplougher/*
2e3206fad5b70e7e0527db2a627ad26616a8a2429plougher * Unsquash a squashfs filesystem.  This is a highly compressed read only
3e3206fad5b70e7e0527db2a627ad26616a8a2429plougher * filesystem.
4443c15812032991c98b33b5424b17bcd55fe3575plougher *
50ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
60ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher * 2012
783d42a3fc898962aa1f1e8387f2ccb1114e0d294Phillip Lougher * Phillip Lougher <phillip@squashfs.org.uk>
8443c15812032991c98b33b5424b17bcd55fe3575plougher *
9443c15812032991c98b33b5424b17bcd55fe3575plougher * This program is free software; you can redistribute it and/or
10443c15812032991c98b33b5424b17bcd55fe3575plougher * modify it under the terms of the GNU General Public License
11443c15812032991c98b33b5424b17bcd55fe3575plougher * as published by the Free Software Foundation; either version 2,
12443c15812032991c98b33b5424b17bcd55fe3575plougher * or (at your option) any later version.
13443c15812032991c98b33b5424b17bcd55fe3575plougher *
14443c15812032991c98b33b5424b17bcd55fe3575plougher * This program is distributed in the hope that it will be useful,
15443c15812032991c98b33b5424b17bcd55fe3575plougher * but WITHOUT ANY WARRANTY; without even the implied warranty of
16443c15812032991c98b33b5424b17bcd55fe3575plougher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17443c15812032991c98b33b5424b17bcd55fe3575plougher * GNU General Public License for more details.
18443c15812032991c98b33b5424b17bcd55fe3575plougher *
19443c15812032991c98b33b5424b17bcd55fe3575plougher * You should have received a copy of the GNU General Public License
20443c15812032991c98b33b5424b17bcd55fe3575plougher * along with this program; if not, write to the Free Software
21443c15812032991c98b33b5424b17bcd55fe3575plougher * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22443c15812032991c98b33b5424b17bcd55fe3575plougher *
23ed5124f016834932db2c63d60d259d846171c216plougher * unsquashfs.c
24443c15812032991c98b33b5424b17bcd55fe3575plougher */
25443c15812032991c98b33b5424b17bcd55fe3575plougher
26ed5124f016834932db2c63d60d259d846171c216plougher#include "unsquashfs.h"
276490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "squashfs_swap.h"
286490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "squashfs_compat.h"
296490378e5b5e8dc058daf28423a7465699a6ba7bplougher#include "read_fs.h"
30efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher#include "compressor.h"
312ef25cb004cc6995bd36f781863aa844fe8c358dplougher#include "xattr.h"
328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
33cdebd2b8ae4b1ac39eefb5f0c556f0d2e3dc3d24plougher#include <sys/sysinfo.h>
342ef25cb004cc6995bd36f781863aa844fe8c358dplougher#include <sys/types.h>
35cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher#include <sys/time.h>
36cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher#include <sys/resource.h>
372b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher#include <limits.h>
38e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher#include <ctype.h>
39cdebd2b8ae4b1ac39eefb5f0c556f0d2e3dc3d24plougher
408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *fragment_cache, *data_cache;
418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *to_reader, *to_deflate, *to_writer, *from_writer;
428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherpthread_t *thread, *deflator_thread;
438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherpthread_mutex_t	fragment_mutex;
448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* user options that control parallelisation */
468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherint processors = -1;
478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
486490378e5b5e8dc058daf28423a7465699a6ba7bplougherstruct super_block sBlk;
4902bc3bcabf2b219f63961f07293b83629948f026ploughersquashfs_operations s_ops;
50efda88fd6fbb19543a86b5f8d15b437bba8c4674plougherstruct compressor *comp;
5102bc3bcabf2b219f63961f07293b83629948f026plougher
529dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0,
539dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	dev_count = 0, fifo_count = 0;
54443c15812032991c98b33b5424b17bcd55fe3575plougherchar *inode_table = NULL, *directory_table = NULL;
55443c15812032991c98b33b5424b17bcd55fe3575plougherstruct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536];
56443c15812032991c98b33b5424b17bcd55fe3575plougherint fd;
57443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int *uid_table, *guid_table;
58443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int cached_frag = SQUASHFS_INVALID_FRAG;
59443c15812032991c98b33b5424b17bcd55fe3575plougherchar *fragment_data;
60443c15812032991c98b33b5424b17bcd55fe3575plougherchar *file_data;
61443c15812032991c98b33b5424b17bcd55fe3575plougherchar *data;
62443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int block_size;
63ae271cc93e3684d5314bcdc45b631e497ae43166plougherunsigned int block_log;
64d4204758f77acb5a371fa1487a755b76a05d5476plougherint lsonly = FALSE, info = FALSE, force = FALSE, short_ls = TRUE;
65d4204758f77acb5a371fa1487a755b76a05d5476plougherint use_regex = FALSE;
66443c15812032991c98b33b5424b17bcd55fe3575plougherchar **created_inode;
679dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint root_process;
68eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint columns;
69eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint rotate = 0;
701b42101056befe25b5f19d5b099e806a2ecee9cdplougherpthread_mutex_t	screen_mutex;
71eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherpthread_cond_t progress_wait;
721b42101056befe25b5f19d5b099e806a2ecee9cdplougherint progress = TRUE, progress_enabled = FALSE;
73eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int total_blocks = 0, total_files = 0, total_inodes = 0;
74eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int cur_blocks = 0;
75ed5124f016834932db2c63d60d259d846171c216plougherint inode_number = 1;
76df9d38a515489c2c573754ad81abd230dfd8b1f0plougherint no_xattrs = XATTR_DEF;
77443c15812032991c98b33b5424b17bcd55fe3575plougher
78476dcb48b24efff22caa970f000e151f1b28918dplougherint lookup_type[] = {
79476dcb48b24efff22caa970f000e151f1b28918dplougher	0,
80476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
81476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFREG,
82476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFLNK,
83476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFBLK,
84476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFCHR,
85476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFIFO,
86476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFSOCK,
87476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
88eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFREG,
89eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFLNK,
90eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFBLK,
91eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFCHR,
92eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFIFO,
93eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFSOCK
94476dcb48b24efff22caa970f000e151f1b28918dplougher};
95476dcb48b24efff22caa970f000e151f1b28918dplougher
96476dcb48b24efff22caa970f000e151f1b28918dplougherstruct test table[] = {
97476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFSOCK, 0, 's' },
98476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFLNK, 0, 'l' },
99476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFBLK, 0, 'b' },
100476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFDIR, 0, 'd' },
101476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFCHR, 0, 'c' },
102476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFIFO, 0, 'p' },
103476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRUSR, S_IRUSR, 1, 'r' },
104476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWUSR, S_IWUSR, 2, 'w' },
105476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRGRP, S_IRGRP, 4, 'r' },
106476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWGRP, S_IWGRP, 5, 'w' },
107476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IROTH, S_IROTH, 7, 'r' },
108476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWOTH, S_IWOTH, 8, 'w' },
109476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR | S_ISUID, 3, 's' },
110476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_ISUID, 3, 'S' },
111476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR, 3, 'x' },
112476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP | S_ISGID, 6, 's' },
113476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_ISGID, 6, 'S' },
114476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP, 6, 'x' },
115476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH | S_ISVTX, 9, 't' },
116476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_ISVTX, 9, 'T' },
117476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH, 9, 'x' },
1188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	{ 0, 0, 0, 0}
1198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher};
1208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
121eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns);
122eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar();
123eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
124afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher#define MAX_LINE 16384
125afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher
126eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid sigwinch_handler()
127eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
128eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct winsize winsize;
129eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
130eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
131c27a3d72b339d80d38623a4ee5a42601338fb4c9plougher		if(isatty(STDOUT_FILENO))
132d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
133d4204758f77acb5a371fa1487a755b76a05d5476plougher				"columns\n");
134eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = 80;
135eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	} else
136eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = winsize.ws_col;
137eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
138eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1401b5f6c5145f284683a2628b73ab5f8a0e37dd7b4ploughervoid sigalrm_handler()
1411b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher{
1421b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	rotate = (rotate + 1) % 4;
1431b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher}
1441b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
1451b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
1462b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougherint add_overflow(int a, int b)
1472b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher{
1482b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	return (INT_MAX - a) < b;
1492b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher}
1502b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1512b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1522b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougherint shift_overflow(int a, int shift)
1532b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher{
1542b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	return (INT_MAX >> shift) < a;
1552b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher}
1562b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1572b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1582b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougherint multiply_overflow(int a, int multiplier)
1592b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher{
1602b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	return (INT_MAX / multiplier) < a;
1612b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher}
1622b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1632b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *queue_init(int size)
1658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct queue *queue = malloc(sizeof(struct queue));
1678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(queue == NULL)
16962b2d7649ad84234afd928a43f9a2c1612eef361plougher		EXIT_UNSQUASH("Out of memory in queue_init\n");
1708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1712b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(add_overflow(size, 1) ||
1722b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher				multiply_overflow(size + 1, sizeof(void *)))
1732b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		EXIT_UNSQUASH("Size too large in queue_init\n");
1742b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1757b53be8c83b949517c343d9c6d88243578753c3aplougher	queue->data = malloc(sizeof(void *) * (size + 1));
1767b53be8c83b949517c343d9c6d88243578753c3aplougher	if(queue->data == NULL)
1770e0cc6f6dccdc5460c292b0a5accc1184a07f3f5plougher		EXIT_UNSQUASH("Out of memory in queue_init\n");
1788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->size = size + 1;
1808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = queue->writep = 0;
1818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&queue->mutex, NULL);
1828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->empty, NULL);
1838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->full, NULL);
1848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return queue;
1868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1898888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid queue_put(struct queue *queue, void *data)
1908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int nextp;
1928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
1948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
1968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->full, &queue->mutex);
1978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->data[queue->writep] = data;
1998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->writep = nextp;
2008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->empty);
2018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
2028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2058888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *queue_get(struct queue *queue)
2068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	void *data;
2088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
2098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(queue->readp == queue->writep)
2118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->empty, &queue->mutex);
2128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data = queue->data[queue->readp];
2148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = (queue->readp + 1) % queue->size;
2158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->full);
2168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
2178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return data;
2198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2238888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_hash_table(struct cache *cache, struct cache_entry *entry)
2248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(entry->block);
2268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_next = cache->hash_table[hash];
2288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->hash_table[hash] = entry;
2298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = NULL;
2308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
2318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry;
2328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2368888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_hash_table(struct cache *cache, struct cache_entry *entry)
2378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_prev)
2398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_prev->hash_next = entry->hash_next;
2408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	else
241c435240f52b78b0ef498118727ba8dad186db26bplougher		cache->hash_table[CALCULATE_HASH(entry->block)] =
242c435240f52b78b0ef498118727ba8dad186db26bplougher			entry->hash_next;
2438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
2448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry->hash_prev;
2458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = entry->hash_next = NULL;
2478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2518888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_free_list(struct cache *cache, struct cache_entry *entry)
2528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache->free_list) {
2548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next = cache->free_list;
2558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = cache->free_list->free_prev;
2568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev->free_next = entry;
2578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev = entry;
2588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
2598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = entry;
2608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = entry->free_next = entry;
2618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
2628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2668888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_free_list(struct cache *cache, struct cache_entry *entry)
2678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->free_prev == NULL && entry->free_next == NULL)
2698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* not in free list */
2708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return;
271222e49e257bccb10c0e608f071778f26fce28f01plougher	else if(entry->free_prev == entry && entry->free_next == entry) {
2728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* only this entry in the free list */
2738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = NULL;
2748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
2758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* more than one entry in the free list */
2768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next->free_prev = entry->free_prev;
2778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev->free_next = entry->free_next;
2788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->free_list == entry)
2798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->free_list = entry->free_next;
2808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
2818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->free_prev = entry->free_next = NULL;
2838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *cache_init(int buffer_size, int max_buffers)
2878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache *cache = malloc(sizeof(struct cache));
2898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache == NULL)
291360570574b8f7786728d91d5fe4a0a4aa291fa03plougher		EXIT_UNSQUASH("Out of memory in cache_init\n");
2928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->max_buffers = max_buffers;
2948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->buffer_size = buffer_size;
2958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->count = 0;
2968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->free_list = NULL;
2978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536);
2988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_free = FALSE;
2998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_pending = FALSE;
3008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&cache->mutex, NULL);
3018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_free, NULL);
3028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_pending, NULL);
3038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return cache;
3058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache_entry *cache_get(struct cache *cache, long long block, int size)
3098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
310d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
311d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * Get a block out of the cache.  If the block isn't in the cache
312d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * it is added and queued to the reader() and deflate() threads for
313c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * reading off disk and decompression.  The cache grows until max_blocks
314c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * is reached, once this occurs existing discarded blocks on the free
315c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * list are reused
316d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
3178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(block);
3188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *entry;
3198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&cache->mutex);
3218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
3238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->block == block)
3248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			break;
3258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry) {
327d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
3280a0d045642e8e413f90b770539193d3fd1522786plougher 		 * found the block in the cache, increment used count and
3298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * if necessary remove from free list so it won't disappear
3308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
3318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used ++;
3328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		remove_free_list(cache, entry);
3338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
3348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
335d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
336d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 * not in the cache
337d4204758f77acb5a371fa1487a755b76a05d5476plougher		 *
338d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * first try to allocate new block
339d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
3408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->count < cache->max_buffers) {
3418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = malloc(sizeof(struct cache_entry));
3428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(entry == NULL)
3437227416360c2f249a0783dffef6725ad03b61c99plougher				EXIT_UNSQUASH("Out of memory in cache_get\n");
3448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data = malloc(cache->buffer_size);
3457227416360c2f249a0783dffef6725ad03b61c99plougher			if(entry->data == NULL)
3467227416360c2f249a0783dffef6725ad03b61c99plougher				EXIT_UNSQUASH("Out of memory in cache_get\n");
3478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache = cache;
3488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->free_prev = entry->free_next = NULL;
3498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->count ++;
3508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		} else {
351d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
352d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * try to get from free list
353d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
3548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			while(cache->free_list == NULL) {
3558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				cache->wait_free = TRUE;
356d4204758f77acb5a371fa1487a755b76a05d5476plougher				pthread_cond_wait(&cache->wait_for_free,
357d4204758f77acb5a371fa1487a755b76a05d5476plougher					&cache->mutex);
3588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
3598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = cache->free_list;
3608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_free_list(cache, entry);
3618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_hash_table(cache, entry);
3628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
3638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
364d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
365d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * initialise block and insert into the hash table
366d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
3678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->block = block;
3688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->size = size;
3698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used = 1;
3708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->error = FALSE;
3718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->pending = TRUE;
3728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_hash_table(cache, entry);
3738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
374d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
375c435240f52b78b0ef498118727ba8dad186db26bplougher		 * queue to read thread to read and ultimately (via the
376c435240f52b78b0ef498118727ba8dad186db26bplougher		 * decompress threads) decompress the buffer
3778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
3788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
3798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_reader, entry);
3808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return entry;
3838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3868888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_ready(struct cache_entry *entry, int error)
3878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
388d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
389d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * mark cache entry as being complete, reading and (if necessary)
3908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * decompression has taken place, and the buffer is valid for use.
3918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * If an error occurs reading or decompressing, the buffer also
392d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * becomes ready but with an error...
393d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
3948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
3958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->pending = FALSE;
3968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->error = error;
3978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
398d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
399c435240f52b78b0ef498118727ba8dad186db26bplougher	 * if the wait_pending flag is set, one or more threads may be waiting
400c435240f52b78b0ef498118727ba8dad186db26bplougher	 * on this buffer
401d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
4028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->cache->wait_pending) {
4038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = FALSE;
4048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_broadcast(&entry->cache->wait_for_pending);
4058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
4068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
4088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
4098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4118888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_wait(struct cache_entry *entry)
4128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
413d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
414d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * wait for this cache entry to become ready, when reading and (if
415d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * necessary) decompression has taken place
416d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
4178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
4188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(entry->pending) {
4208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = TRUE;
421d4204758f77acb5a371fa1487a755b76a05d5476plougher		pthread_cond_wait(&entry->cache->wait_for_pending,
422d4204758f77acb5a371fa1487a755b76a05d5476plougher			&entry->cache->mutex);
4238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
4248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
4268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
4278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4298888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_put(struct cache_entry *entry)
4308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
431d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
432d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * finished with this cache entry, once the usage count reaches zero it
433c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * can be reused and is put onto the free list.  As it remains
434c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * accessible via the hash table it can be found getting a new lease of
435c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * life before it is reused.
436d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
4378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
4388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->used --;
4408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->used == 0) {
4418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_free_list(entry->cache, entry);
4428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
443d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
444c435240f52b78b0ef498118727ba8dad186db26bplougher		 * if the wait_free flag is set, one or more threads may be
445c435240f52b78b0ef498118727ba8dad186db26bplougher		 * waiting on this buffer
446d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
4478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->cache->wait_free) {
4488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache->wait_free = FALSE;
4498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			pthread_cond_broadcast(&entry->cache->wait_for_free);
4508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
4518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
4528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
4548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
455476dcb48b24efff22caa970f000e151f1b28918dplougher
456476dcb48b24efff22caa970f000e151f1b28918dplougher
457476dcb48b24efff22caa970f000e151f1b28918dplougherchar *modestr(char *str, int mode)
458476dcb48b24efff22caa970f000e151f1b28918dplougher{
459476dcb48b24efff22caa970f000e151f1b28918dplougher	int i;
460476dcb48b24efff22caa970f000e151f1b28918dplougher
461476dcb48b24efff22caa970f000e151f1b28918dplougher	strcpy(str, "----------");
462476dcb48b24efff22caa970f000e151f1b28918dplougher
463476dcb48b24efff22caa970f000e151f1b28918dplougher	for(i = 0; table[i].mask != 0; i++) {
464476dcb48b24efff22caa970f000e151f1b28918dplougher		if((mode & table[i].mask) == table[i].value)
465476dcb48b24efff22caa970f000e151f1b28918dplougher			str[table[i].position] = table[i].mode;
466476dcb48b24efff22caa970f000e151f1b28918dplougher	}
467476dcb48b24efff22caa970f000e151f1b28918dplougher
468476dcb48b24efff22caa970f000e151f1b28918dplougher	return str;
469476dcb48b24efff22caa970f000e151f1b28918dplougher}
470476dcb48b24efff22caa970f000e151f1b28918dplougher
471476dcb48b24efff22caa970f000e151f1b28918dplougher
4723edfa57b6a463f7d441d995559143f4861d62e98plougher#define TOTALCHARS  25
4736f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint print_filename(char *pathname, struct inode *inode)
474476dcb48b24efff22caa970f000e151f1b28918dplougher{
475afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher	char str[11], dummy[12], dummy2[12]; /* overflow safe */
476afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher	char *userstr, *groupstr;
4776f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int padchars;
478476dcb48b24efff22caa970f000e151f1b28918dplougher	struct passwd *user;
479476dcb48b24efff22caa970f000e151f1b28918dplougher	struct group *group;
48088facddfd83e48a907b82210ddccbb4f84d80aecplougher	struct tm *t;
481476dcb48b24efff22caa970f000e151f1b28918dplougher
482476dcb48b24efff22caa970f000e151f1b28918dplougher	if(short_ls) {
483476dcb48b24efff22caa970f000e151f1b28918dplougher		printf("%s\n", pathname);
484476dcb48b24efff22caa970f000e151f1b28918dplougher		return 1;
485476dcb48b24efff22caa970f000e151f1b28918dplougher	}
486476dcb48b24efff22caa970f000e151f1b28918dplougher
487266b83c3b162a6764407753909712fcaade951f2plougher	user = getpwuid(inode->uid);
488266b83c3b162a6764407753909712fcaade951f2plougher	if(user == NULL) {
489afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		int res = snprintf(dummy, 12, "%d", inode->uid);
490afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		if(res < 0)
491afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			EXIT_UNSQUASH("snprintf failed in print_filename()\n");
492afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		else if(res >= 12)
493afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			/* unsigned int shouldn't ever need more than 11 bytes
494afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			 * (including terminating '\0') to print in base 10 */
495afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			userstr = "*";
496afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		else
497afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			userstr = dummy;
4983edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
4993edfa57b6a463f7d441d995559143f4861d62e98plougher		userstr = user->pw_name;
5003edfa57b6a463f7d441d995559143f4861d62e98plougher
501266b83c3b162a6764407753909712fcaade951f2plougher	group = getgrgid(inode->gid);
502266b83c3b162a6764407753909712fcaade951f2plougher	if(group == NULL) {
503afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		int res = snprintf(dummy2, 12, "%d", inode->gid);
504afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		if(res < 0)
505afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			EXIT_UNSQUASH("snprintf failed in print_filename()\n");
506afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		else if(res >= 12)
507afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			/* unsigned int shouldn't ever need more than 11 bytes
508afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			 * (including terminating '\0') to print in base 10 */
509afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			groupstr = "*";
510afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		else
511afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			groupstr = dummy2;
5123edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
5133edfa57b6a463f7d441d995559143f4861d62e98plougher		groupstr = group->gr_name;
5143edfa57b6a463f7d441d995559143f4861d62e98plougher
5156f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	printf("%s %s/%s ", modestr(str, inode->mode), userstr, groupstr);
5163edfa57b6a463f7d441d995559143f4861d62e98plougher
5176f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(inode->mode & S_IFMT) {
5183edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFREG:
5193edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFDIR:
5203edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFSOCK:
5213edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFIFO:
5223edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFLNK:
523c435240f52b78b0ef498118727ba8dad186db26bplougher			padchars = TOTALCHARS - strlen(userstr) -
524c435240f52b78b0ef498118727ba8dad186db26bplougher				strlen(groupstr);
5253edfa57b6a463f7d441d995559143f4861d62e98plougher
526c435240f52b78b0ef498118727ba8dad186db26bplougher			printf("%*lld ", padchars > 0 ? padchars : 0,
527c435240f52b78b0ef498118727ba8dad186db26bplougher				inode->data);
5283edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
5293edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFCHR:
5303edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFBLK:
531c435240f52b78b0ef498118727ba8dad186db26bplougher			padchars = TOTALCHARS - strlen(userstr) -
532c435240f52b78b0ef498118727ba8dad186db26bplougher				strlen(groupstr) - 7;
5333edfa57b6a463f7d441d995559143f4861d62e98plougher
534d4204758f77acb5a371fa1487a755b76a05d5476plougher			printf("%*s%3d,%3d ", padchars > 0 ? padchars : 0, " ",
535c435240f52b78b0ef498118727ba8dad186db26bplougher				(int) inode->data >> 8, (int) inode->data &
536c435240f52b78b0ef498118727ba8dad186db26bplougher				0xff);
5373edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
5383edfa57b6a463f7d441d995559143f4861d62e98plougher	}
539476dcb48b24efff22caa970f000e151f1b28918dplougher
5406f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	t = localtime(&inode->time);
54188facddfd83e48a907b82210ddccbb4f84d80aecplougher
542d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("%d-%02d-%02d %02d:%02d %s", t->tm_year + 1900, t->tm_mon + 1,
543d4204758f77acb5a371fa1487a755b76a05d5476plougher		t->tm_mday, t->tm_hour, t->tm_min, pathname);
5446f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((inode->mode & S_IFMT) == S_IFLNK)
5456f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		printf(" -> %s", inode->symlink);
5463edfa57b6a463f7d441d995559143f4861d62e98plougher	printf("\n");
5473edfa57b6a463f7d441d995559143f4861d62e98plougher
548476dcb48b24efff22caa970f000e151f1b28918dplougher	return 1;
549476dcb48b24efff22caa970f000e151f1b28918dplougher}
550476dcb48b24efff22caa970f000e151f1b28918dplougher
551443c15812032991c98b33b5424b17bcd55fe3575plougher
552e3206fad5b70e7e0527db2a627ad26616a8a2429ploughervoid add_entry(struct hash_table_entry *hash_table[], long long start,
553e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	int bytes)
554443c15812032991c98b33b5424b17bcd55fe3575plougher{
555443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
556443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
557443c15812032991c98b33b5424b17bcd55fe3575plougher
558cb2cff9a58d8d92fc6edb95049469188ee49c6c9plougher	hash_table_entry = malloc(sizeof(struct hash_table_entry));
559cb2cff9a58d8d92fc6edb95049469188ee49c6c9plougher	if(hash_table_entry == NULL)
5604a39fa82d4614c18d2977be7898d78d20ba01a49plougher		EXIT_UNSQUASH("Out of memory in add_entry\n");
561443c15812032991c98b33b5424b17bcd55fe3575plougher
562443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->start = start;
563443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->bytes = bytes;
564443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->next = hash_table[hash];
565443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table[hash] = hash_table_entry;
566443c15812032991c98b33b5424b17bcd55fe3575plougher}
567443c15812032991c98b33b5424b17bcd55fe3575plougher
568443c15812032991c98b33b5424b17bcd55fe3575plougher
569f404f4914fdb272a70e18664e8963d793cc90f44plougherint lookup_entry(struct hash_table_entry *hash_table[], long long start)
570443c15812032991c98b33b5424b17bcd55fe3575plougher{
571443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
572443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
573443c15812032991c98b33b5424b17bcd55fe3575plougher
5749dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	for(hash_table_entry = hash_table[hash]; hash_table_entry;
5759dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				hash_table_entry = hash_table_entry->next)
5767a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher
577443c15812032991c98b33b5424b17bcd55fe3575plougher		if(hash_table_entry->start == start)
578443c15812032991c98b33b5424b17bcd55fe3575plougher			return hash_table_entry->bytes;
579443c15812032991c98b33b5424b17bcd55fe3575plougher
580443c15812032991c98b33b5424b17bcd55fe3575plougher	return -1;
581443c15812032991c98b33b5424b17bcd55fe3575plougher}
582443c15812032991c98b33b5424b17bcd55fe3575plougher
583443c15812032991c98b33b5424b17bcd55fe3575plougher
5843306cb2b54a60a32664617118336ac141e1471b6plougherint read_fs_bytes(int fd, long long byte, int bytes, void *buff)
585443c15812032991c98b33b5424b17bcd55fe3575plougher{
586443c15812032991c98b33b5424b17bcd55fe3575plougher	off_t off = byte;
587d7f3de3408089ce187d8bc26f6072730c77628daplougher	int res, count;
588443c15812032991c98b33b5424b17bcd55fe3575plougher
589c435240f52b78b0ef498118727ba8dad186db26bplougher	TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte,
590c435240f52b78b0ef498118727ba8dad186db26bplougher		bytes);
591fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
592443c15812032991c98b33b5424b17bcd55fe3575plougher	if(lseek(fd, off, SEEK_SET) == -1) {
5935d415c6659faaa7a69c9baa7175610d889747142plougher		ERROR("Lseek failed because %s\n", strerror(errno));
594443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
595443c15812032991c98b33b5424b17bcd55fe3575plougher	}
596443c15812032991c98b33b5424b17bcd55fe3575plougher
597d7f3de3408089ce187d8bc26f6072730c77628daplougher	for(count = 0; count < bytes; count += res) {
598d7f3de3408089ce187d8bc26f6072730c77628daplougher		res = read(fd, buff + count, bytes - count);
599d7f3de3408089ce187d8bc26f6072730c77628daplougher		if(res < 1) {
600d7f3de3408089ce187d8bc26f6072730c77628daplougher			if(res == 0) {
601e3206fad5b70e7e0527db2a627ad26616a8a2429plougher				ERROR("Read on filesystem failed because "
602e3206fad5b70e7e0527db2a627ad26616a8a2429plougher					"EOF\n");
603d7f3de3408089ce187d8bc26f6072730c77628daplougher				return FALSE;
604d7f3de3408089ce187d8bc26f6072730c77628daplougher			} else if(errno != EINTR) {
605d7f3de3408089ce187d8bc26f6072730c77628daplougher				ERROR("Read on filesystem failed because %s\n",
606d7f3de3408089ce187d8bc26f6072730c77628daplougher						strerror(errno));
607d7f3de3408089ce187d8bc26f6072730c77628daplougher				return FALSE;
608d7f3de3408089ce187d8bc26f6072730c77628daplougher			} else
609d7f3de3408089ce187d8bc26f6072730c77628daplougher				res = 0;
610d7f3de3408089ce187d8bc26f6072730c77628daplougher		}
611443c15812032991c98b33b5424b17bcd55fe3575plougher	}
612443c15812032991c98b33b5424b17bcd55fe3575plougher
613443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
614443c15812032991c98b33b5424b17bcd55fe3575plougher}
615443c15812032991c98b33b5424b17bcd55fe3575plougher
616443c15812032991c98b33b5424b17bcd55fe3575plougher
617923b301e304637fd5e587eb05a6f44558abae2bdplougherint read_block(int fd, long long start, long long *next, void *block)
618443c15812032991c98b33b5424b17bcd55fe3575plougher{
619443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned short c_byte;
620443c15812032991c98b33b5424b17bcd55fe3575plougher	int offset = 2;
621443c15812032991c98b33b5424b17bcd55fe3575plougher
622443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
623923b301e304637fd5e587eb05a6f44558abae2bdplougher		if(read_fs_bytes(fd, start, 2, &c_byte) == FALSE)
624fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
625923b301e304637fd5e587eb05a6f44558abae2bdplougher		c_byte = (c_byte >> 8) | ((c_byte & 0xff) << 8);
626443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
6273306cb2b54a60a32664617118336ac141e1471b6plougher		if(read_fs_bytes(fd, start, 2, &c_byte) == FALSE)
628fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
629fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
630d4204758f77acb5a371fa1487a755b76a05d5476plougher	TRACE("read_block: block @0x%llx, %d %s bytes\n", start,
631d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ?
632d4204758f77acb5a371fa1487a755b76a05d5476plougher		"compressed" : "uncompressed");
633443c15812032991c98b33b5424b17bcd55fe3575plougher
63427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(SQUASHFS_CHECK_DATA(sBlk.s.flags))
635443c15812032991c98b33b5424b17bcd55fe3575plougher		offset = 3;
636443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED(c_byte)) {
637443c15812032991c98b33b5424b17bcd55fe3575plougher		char buffer[SQUASHFS_METADATA_SIZE];
638efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		int error, res;
639443c15812032991c98b33b5424b17bcd55fe3575plougher
640443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
64186561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		if(read_fs_bytes(fd, start + offset, c_byte, buffer) == FALSE)
642fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
643443c15812032991c98b33b5424b17bcd55fe3575plougher
644b48442b2e37b3cb7efbffb032968f115eec7963cplougher		res = compressor_uncompress(comp, block, buffer, c_byte,
645efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			SQUASHFS_METADATA_SIZE, &error);
646efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
647efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		if(res == -1) {
648efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			ERROR("%s uncompress failed with error code %d\n",
649efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher				comp->name, error);
650fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
651443c15812032991c98b33b5424b17bcd55fe3575plougher		}
652443c15812032991c98b33b5424b17bcd55fe3575plougher		if(next)
653443c15812032991c98b33b5424b17bcd55fe3575plougher			*next = start + offset + c_byte;
654efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		return res;
655443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
656443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
65786561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		if(read_fs_bytes(fd, start + offset, c_byte, block) == FALSE)
658fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
659443c15812032991c98b33b5424b17bcd55fe3575plougher		if(next)
660443c15812032991c98b33b5424b17bcd55fe3575plougher			*next = start + offset + c_byte;
661443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
662443c15812032991c98b33b5424b17bcd55fe3575plougher	}
663fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
664fe3ca0609d02d78bcd11637c1220b2ff428f466aplougherfailed:
66568ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher	ERROR("read_block: failed to read block @0x%llx\n", start);
666fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	return FALSE;
667443c15812032991c98b33b5424b17bcd55fe3575plougher}
668443c15812032991c98b33b5424b17bcd55fe3575plougher
669443c15812032991c98b33b5424b17bcd55fe3575plougher
670443c15812032991c98b33b5424b17bcd55fe3575plougherint read_data_block(long long start, unsigned int size, char *block)
671443c15812032991c98b33b5424b17bcd55fe3575plougher{
672efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	int error, res;
673443c15812032991c98b33b5424b17bcd55fe3575plougher	int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
674443c15812032991c98b33b5424b17bcd55fe3575plougher
675d4204758f77acb5a371fa1487a755b76a05d5476plougher	TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start,
676c6ab26edb0c0da6b276281960d9c8748a70886feplougher		c_byte, SQUASHFS_COMPRESSED_BLOCK(size) ? "compressed" :
677c435240f52b78b0ef498118727ba8dad186db26bplougher		"uncompressed");
678fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
679443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED_BLOCK(size)) {
68086561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		if(read_fs_bytes(fd, start, c_byte, data) == FALSE)
68168ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
682443c15812032991c98b33b5424b17bcd55fe3575plougher
683b48442b2e37b3cb7efbffb032968f115eec7963cplougher		res = compressor_uncompress(comp, block, data, c_byte,
684b48442b2e37b3cb7efbffb032968f115eec7963cplougher			block_size, &error);
685efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
686efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		if(res == -1) {
687efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			ERROR("%s uncompress failed with error code %d\n",
688efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher				comp->name, error);
68968ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
690443c15812032991c98b33b5424b17bcd55fe3575plougher		}
691443c15812032991c98b33b5424b17bcd55fe3575plougher
692efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		return res;
693443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
69486561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		if(read_fs_bytes(fd, start, c_byte, block) == FALSE)
69568ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
696443c15812032991c98b33b5424b17bcd55fe3575plougher
697443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
698443c15812032991c98b33b5424b17bcd55fe3575plougher	}
69968ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher
70068ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougherfailed:
701d4204758f77acb5a371fa1487a755b76a05d5476plougher	ERROR("read_data_block: failed to read block @0x%llx, size %d\n", start,
702c6ab26edb0c0da6b276281960d9c8748a70886feplougher		c_byte);
70368ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher	return FALSE;
704443c15812032991c98b33b5424b17bcd55fe3575plougher}
705443c15812032991c98b33b5424b17bcd55fe3575plougher
706443c15812032991c98b33b5424b17bcd55fe3575plougher
70702bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_inode_table(long long start, long long end)
708443c15812032991c98b33b5424b17bcd55fe3575plougher{
709443c15812032991c98b33b5424b17bcd55fe3575plougher	int size = 0, bytes = 0, res;
710443c15812032991c98b33b5424b17bcd55fe3575plougher
71141da3230b2ac91a73f9190676f66b3d80b21c270plougher	TRACE("uncompress_inode_table: start %lld, end %lld\n", start, end);
712443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
713c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher		if(size - bytes < SQUASHFS_METADATA_SIZE) {
714c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher			inode_table = realloc(inode_table, size +=
715c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher				SQUASHFS_METADATA_SIZE);
716c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher			if(inode_table == NULL)
717c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher				EXIT_UNSQUASH("Out of memory in "
718c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher					"uncompress_inode_table");
719c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher		}
720443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("uncompress_inode_table: reading block 0x%llx\n", start);
721443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(inode_table_hash, start, bytes);
722176b325add10f6b9846f771f75d8543364d4c121plougher		res = read_block(fd, start, &start, inode_table + bytes);
723c435240f52b78b0ef498118727ba8dad186db26bplougher		if(res == 0) {
724443c15812032991c98b33b5424b17bcd55fe3575plougher			free(inode_table);
725d4204758f77acb5a371fa1487a755b76a05d5476plougher			EXIT_UNSQUASH("uncompress_inode_table: failed to read "
726d4204758f77acb5a371fa1487a755b76a05d5476plougher				"block \n");
727443c15812032991c98b33b5424b17bcd55fe3575plougher		}
728443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
729443c15812032991c98b33b5424b17bcd55fe3575plougher	}
730443c15812032991c98b33b5424b17bcd55fe3575plougher}
731443c15812032991c98b33b5424b17bcd55fe3575plougher
732443c15812032991c98b33b5424b17bcd55fe3575plougher
733d4204758f77acb5a371fa1487a755b76a05d5476plougherint set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time,
734fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher	unsigned int xattr, unsigned int set_mode)
735443c15812032991c98b33b5424b17bcd55fe3575plougher{
7366f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	struct utimbuf times = { time, time };
737443c15812032991c98b33b5424b17bcd55fe3575plougher
7382ef25cb004cc6995bd36f781863aa844fe8c358dplougher	write_xattr(pathname, xattr);
7392ef25cb004cc6995bd36f781863aa844fe8c358dplougher
740443c15812032991c98b33b5424b17bcd55fe3575plougher	if(utime(pathname, &times) == -1) {
741d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("set_attributes: failed to set time on %s, because %s\n",
742d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
743443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
744443c15812032991c98b33b5424b17bcd55fe3575plougher	}
745443c15812032991c98b33b5424b17bcd55fe3575plougher
7469dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if(root_process) {
7476f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(chown(pathname, uid, guid) == -1) {
748c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("set_attributes: failed to change uid and gids "
749c435240f52b78b0ef498118727ba8dad186db26bplougher				"on %s, because %s\n", pathname,
750c435240f52b78b0ef498118727ba8dad186db26bplougher				strerror(errno));
751443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
752443c15812032991c98b33b5424b17bcd55fe3575plougher		}
7539dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	} else
7549dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		mode &= ~07000;
7559dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
7569dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) {
757d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("set_attributes: failed to change mode %s, because %s\n",
758d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
7599dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		return FALSE;
760443c15812032991c98b33b5424b17bcd55fe3575plougher	}
761443c15812032991c98b33b5424b17bcd55fe3575plougher
762443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
763443c15812032991c98b33b5424b17bcd55fe3575plougher}
764443c15812032991c98b33b5424b17bcd55fe3575plougher
765443c15812032991c98b33b5424b17bcd55fe3575plougher
7661c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougherint write_bytes(int fd, char *buff, int bytes)
7671c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher{
7681c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	int res, count;
7691c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
7701c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	for(count = 0; count < bytes; count += res) {
7711c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		res = write(fd, buff + count, bytes - count);
7721c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		if(res == -1) {
7731c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			if(errno != EINTR) {
774c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("Write on output file failed because "
775c435240f52b78b0ef498118727ba8dad186db26bplougher					"%s\n", strerror(errno));
7761c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher				return -1;
7771c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			}
7781c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			res = 0;
7791c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		}
7801c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	}
7811c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
7821c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	return 0;
7831c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher}
7841c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
7851c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
786b9cee889506e674726856035dba52d5e1cceeb99plougherint lseek_broken = FALSE;
787c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougherchar *zero_data = NULL;
788b9cee889506e674726856035dba52d5e1cceeb99plougher
78987f5e0e29e5f56516daaa51b1d36cde3d86a0f1fplougherint write_block(int file_fd, char *buffer, int size, long long hole, int sparse)
790b9cee889506e674726856035dba52d5e1cceeb99plougher{
791b9cee889506e674726856035dba52d5e1cceeb99plougher	off_t off = hole;
792b9cee889506e674726856035dba52d5e1cceeb99plougher
793b9cee889506e674726856035dba52d5e1cceeb99plougher	if(hole) {
794c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if(sparse && lseek_broken == FALSE) {
795c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			 int error = lseek(file_fd, off, SEEK_CUR);
796c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			 if(error == -1)
797c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				/* failed to seek beyond end of file */
798c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				lseek_broken = TRUE;
799c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		}
800c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
801c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if((sparse == FALSE || lseek_broken) && zero_data == NULL) {
802b9cee889506e674726856035dba52d5e1cceeb99plougher			if((zero_data = malloc(block_size)) == NULL)
803c435240f52b78b0ef498118727ba8dad186db26bplougher				EXIT_UNSQUASH("write_block: failed to alloc "
804c435240f52b78b0ef498118727ba8dad186db26bplougher					"zero data block\n");
805b9cee889506e674726856035dba52d5e1cceeb99plougher			memset(zero_data, 0, block_size);
806b9cee889506e674726856035dba52d5e1cceeb99plougher		}
807c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
808c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if(sparse == FALSE || lseek_broken) {
809b9cee889506e674726856035dba52d5e1cceeb99plougher			int blocks = (hole + block_size -1) / block_size;
810b9cee889506e674726856035dba52d5e1cceeb99plougher			int avail_bytes, i;
811b9cee889506e674726856035dba52d5e1cceeb99plougher			for(i = 0; i < blocks; i++, hole -= avail_bytes) {
812d4204758f77acb5a371fa1487a755b76a05d5476plougher				avail_bytes = hole > block_size ? block_size :
813d4204758f77acb5a371fa1487a755b76a05d5476plougher					hole;
814d4204758f77acb5a371fa1487a755b76a05d5476plougher				if(write_bytes(file_fd, zero_data, avail_bytes)
815d4204758f77acb5a371fa1487a755b76a05d5476plougher						== -1)
816b9cee889506e674726856035dba52d5e1cceeb99plougher					goto failure;
817b9cee889506e674726856035dba52d5e1cceeb99plougher			}
818b9cee889506e674726856035dba52d5e1cceeb99plougher		}
819b9cee889506e674726856035dba52d5e1cceeb99plougher	}
820b9cee889506e674726856035dba52d5e1cceeb99plougher
8211c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	if(write_bytes(file_fd, buffer, size) == -1)
822b9cee889506e674726856035dba52d5e1cceeb99plougher		goto failure;
823b9cee889506e674726856035dba52d5e1cceeb99plougher
824b9cee889506e674726856035dba52d5e1cceeb99plougher	return TRUE;
825b9cee889506e674726856035dba52d5e1cceeb99plougher
826b9cee889506e674726856035dba52d5e1cceeb99plougherfailure:
827b9cee889506e674726856035dba52d5e1cceeb99plougher	return FALSE;
828b9cee889506e674726856035dba52d5e1cceeb99plougher}
829b9cee889506e674726856035dba52d5e1cceeb99plougher
8308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
831cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougherpthread_mutex_t open_mutex = PTHREAD_MUTEX_INITIALIZER;
832cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougherpthread_cond_t open_empty = PTHREAD_COND_INITIALIZER;
833cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougherint open_unlimited, open_count;
834cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher#define OPEN_FILE_MARGIN 10
835cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
836cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
837cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Loughervoid open_init(int count)
838cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher{
839cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	open_count = count;
840cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	open_unlimited = count == -1;
841cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher}
842cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
843cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
844cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougherint open_wait(char *pathname, int flags, mode_t mode)
845cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher{
846cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	if (!open_unlimited) {
847cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		pthread_mutex_lock(&open_mutex);
848cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		while (open_count == 0)
849cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher			pthread_cond_wait(&open_empty, &open_mutex);
850cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		open_count --;
851cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		pthread_mutex_unlock(&open_mutex);
852cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	}
853cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
854cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	return open(pathname, flags, mode);
855cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher}
856cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
857cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
858cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Loughervoid close_wake(int fd)
859cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher{
860cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	close(fd);
861cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
862cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	if (!open_unlimited) {
863cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		pthread_mutex_lock(&open_mutex);
864cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		open_count ++;
865cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		pthread_cond_signal(&open_empty);
866cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		pthread_mutex_unlock(&open_mutex);
867cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	}
868cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher}
869cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
870cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
8712c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Loughervoid queue_file(char *pathname, int file_fd, struct inode *inode)
8722c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher{
8732c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	struct squashfs_file *file = malloc(sizeof(struct squashfs_file));
8742c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	if(file == NULL)
8752c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		EXIT_UNSQUASH("queue_file: unable to malloc file\n");
8762c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
8772c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->fd = file_fd;
8782c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->file_size = inode->data;
8792c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->mode = inode->mode;
8802c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->gid = inode->gid;
8812c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->uid = inode->uid;
8822c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->time = inode->time;
8832c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->pathname = strdup(pathname);
8842c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->blocks = inode->blocks + (inode->frag_bytes > 0);
8852c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->sparse = inode->sparse;
8862c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->xattr = inode->xattr;
8872c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	queue_put(to_writer, file);
8882c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher}
8892c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
8902c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
8912c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Loughervoid queue_dir(char *pathname, struct dir *dir)
8922c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher{
8932c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	struct squashfs_file *file = malloc(sizeof(struct squashfs_file));
8942c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	if(file == NULL)
8952c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		EXIT_UNSQUASH("queue_dir: unable to malloc file\n");
8962c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
8972c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->fd = -1;
8982c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->mode = dir->mode;
8992c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->gid = dir->guid;
9002c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->uid = dir->uid;
9012c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->time = dir->mtime;
9022c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->pathname = strdup(pathname);
9032c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->xattr = dir->xattr;
9042c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	queue_put(to_writer, file);
9052c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher}
9062c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
9072c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
90879df93becb68081effabebba3006c794be308598plougherint write_file(struct inode *inode, char *pathname)
909443c15812032991c98b33b5424b17bcd55fe3575plougher{
9108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	unsigned int file_fd, i;
911f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher	unsigned int *block_list;
91279df93becb68081effabebba3006c794be308598plougher	int file_end = inode->data / block_size;
91379df93becb68081effabebba3006c794be308598plougher	long long start = inode->start;
914443c15812032991c98b33b5424b17bcd55fe3575plougher
91579df93becb68081effabebba3006c794be308598plougher	TRACE("write_file: regular file, blocks %d\n", inode->blocks);
916443c15812032991c98b33b5424b17bcd55fe3575plougher
917cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	file_fd = open_wait(pathname, O_CREAT | O_WRONLY |
918cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		(force ? O_TRUNC : 0), (mode_t) inode->mode & 0777);
919d4204758f77acb5a371fa1487a755b76a05d5476plougher	if(file_fd == -1) {
920d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("write_file: failed to create file %s, because %s\n",
921d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
922443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
923443c15812032991c98b33b5424b17bcd55fe3575plougher	}
924443c15812032991c98b33b5424b17bcd55fe3575plougher
9256037584bc3e861ff932f5244105959c56c8560e3plougher	block_list = malloc(inode->blocks * sizeof(unsigned int));
9266037584bc3e861ff932f5244105959c56c8560e3plougher	if(block_list == NULL)
9278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("write_file: unable to malloc block list\n");
928443c15812032991c98b33b5424b17bcd55fe3575plougher
92979df93becb68081effabebba3006c794be308598plougher	s_ops.read_block_list(block_list, inode->block_ptr, inode->blocks);
930443c15812032991c98b33b5424b17bcd55fe3575plougher
931d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
932d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * the writer thread is queued a squashfs_file structure describing the
933009263430d50ee32f3757c3c34d1f06262759f5dPhillip Lougher 	 * file.  If the file has one or more blocks or a fragment they are
934c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * queued separately (references to blocks in the cache).
935d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
9362c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	queue_file(pathname, file_fd, inode);
937443c15812032991c98b33b5424b17bcd55fe3575plougher
93879df93becb68081effabebba3006c794be308598plougher	for(i = 0; i < inode->blocks; i++) {
9398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
9408372232d2460411adaa2299c32a0a88665e44902plougher		struct file_entry *block = malloc(sizeof(struct file_entry));
9418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
9428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
9438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
9448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->offset = 0;
945d4204758f77acb5a371fa1487a755b76a05d5476plougher		block->size = i == file_end ? inode->data & (block_size - 1) :
946d4204758f77acb5a371fa1487a755b76a05d5476plougher			block_size;
947009263430d50ee32f3757c3c34d1f06262759f5dPhillip Lougher		if(block_list[i] == 0) /* sparse block */
9488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			block->buffer = NULL;
9498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else {
950d4204758f77acb5a371fa1487a755b76a05d5476plougher			block->buffer = cache_get(data_cache, start,
951d4204758f77acb5a371fa1487a755b76a05d5476plougher				block_list[i]);
9528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			start += c_byte;
953443c15812032991c98b33b5424b17bcd55fe3575plougher		}
9548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
955443c15812032991c98b33b5424b17bcd55fe3575plougher	}
956443c15812032991c98b33b5424b17bcd55fe3575plougher
95779df93becb68081effabebba3006c794be308598plougher	if(inode->frag_bytes) {
9588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int size;
9598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		long long start;
9608372232d2460411adaa2299c32a0a88665e44902plougher		struct file_entry *block = malloc(sizeof(struct file_entry));
9618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
9628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
9638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
96479df93becb68081effabebba3006c794be308598plougher		s_ops.read_fragment(inode->fragment, &start, &size);
9658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->buffer = cache_get(fragment_cache, start, size);
96679df93becb68081effabebba3006c794be308598plougher		block->offset = inode->offset;
96779df93becb68081effabebba3006c794be308598plougher		block->size = inode->frag_bytes;
9688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
969b9cee889506e674726856035dba52d5e1cceeb99plougher	}
970b9cee889506e674726856035dba52d5e1cceeb99plougher
971b9cee889506e674726856035dba52d5e1cceeb99plougher	free(block_list);
972443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
973443c15812032991c98b33b5424b17bcd55fe3575plougher}
974476dcb48b24efff22caa970f000e151f1b28918dplougher
975476dcb48b24efff22caa970f000e151f1b28918dplougher
9766f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint create_inode(char *pathname, struct inode *i)
977443c15812032991c98b33b5424b17bcd55fe3575plougher{
9786f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	TRACE("create_inode: pathname %s\n", pathname);
979443c15812032991c98b33b5424b17bcd55fe3575plougher
9806f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if(created_inode[i->inode_number - 1]) {
981443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("create_inode: hard link\n");
9826013a30bd39550decc2546a47e5168e57bfcfde8plougher		if(force)
9836013a30bd39550decc2546a47e5168e57bfcfde8plougher			unlink(pathname);
9846013a30bd39550decc2546a47e5168e57bfcfde8plougher
9856f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(link(created_inode[i->inode_number - 1], pathname) == -1) {
986c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("create_inode: failed to create hardlink, "
987c435240f52b78b0ef498118727ba8dad186db26bplougher				"because %s\n", strerror(errno));
988443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
989443c15812032991c98b33b5424b17bcd55fe3575plougher		}
990443c15812032991c98b33b5424b17bcd55fe3575plougher
991443c15812032991c98b33b5424b17bcd55fe3575plougher		return TRUE;
992443c15812032991c98b33b5424b17bcd55fe3575plougher	}
993443c15812032991c98b33b5424b17bcd55fe3575plougher
9946f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(i->type) {
9956f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_FILE_TYPE:
9966f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_LREG_TYPE:
997c435240f52b78b0ef498118727ba8dad186db26bplougher			TRACE("create_inode: regular file, file_size %lld, "
998c435240f52b78b0ef498118727ba8dad186db26bplougher				"blocks %d\n", i->data, i->blocks);
999443c15812032991c98b33b5424b17bcd55fe3575plougher
100079df93becb68081effabebba3006c794be308598plougher			if(write_file(i, pathname))
1001443c15812032991c98b33b5424b17bcd55fe3575plougher				file_count ++;
1002443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
10036f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_SYMLINK_TYPE:
100499ec5405b480bf852a0d9eed20693b750ed68943plougher		case SQUASHFS_LSYMLINK_TYPE:
1005d4204758f77acb5a371fa1487a755b76a05d5476plougher			TRACE("create_inode: symlink, symlink_size %lld\n",
1006d4204758f77acb5a371fa1487a755b76a05d5476plougher				i->data);
1007443c15812032991c98b33b5424b17bcd55fe3575plougher
1008a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
1009a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
1010a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
10116f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(symlink(i->symlink, pathname) == -1) {
1012c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("create_inode: failed to create symlink "
1013c435240f52b78b0ef498118727ba8dad186db26bplougher					"%s, because %s\n", pathname,
1014c435240f52b78b0ef498118727ba8dad186db26bplougher					strerror(errno));
1015443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
1016443c15812032991c98b33b5424b17bcd55fe3575plougher			}
1017443c15812032991c98b33b5424b17bcd55fe3575plougher
10182ef25cb004cc6995bd36f781863aa844fe8c358dplougher			write_xattr(pathname, i->xattr);
10192ef25cb004cc6995bd36f781863aa844fe8c358dplougher
10209dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
10216f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(lchown(pathname, i->uid, i->gid) == -1)
1022c435240f52b78b0ef498118727ba8dad186db26bplougher					ERROR("create_inode: failed to change "
1023c435240f52b78b0ef498118727ba8dad186db26bplougher						"uid and gids on %s, because "
1024c435240f52b78b0ef498118727ba8dad186db26bplougher						"%s\n", pathname,
1025c435240f52b78b0ef498118727ba8dad186db26bplougher						strerror(errno));
1026443c15812032991c98b33b5424b17bcd55fe3575plougher			}
1027443c15812032991c98b33b5424b17bcd55fe3575plougher
1028443c15812032991c98b33b5424b17bcd55fe3575plougher			sym_count ++;
1029443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1030443c15812032991c98b33b5424b17bcd55fe3575plougher 		case SQUASHFS_BLKDEV_TYPE:
103199ec5405b480bf852a0d9eed20693b750ed68943plougher	 	case SQUASHFS_CHRDEV_TYPE:
103299ec5405b480bf852a0d9eed20693b750ed68943plougher 		case SQUASHFS_LBLKDEV_TYPE:
103399ec5405b480bf852a0d9eed20693b750ed68943plougher	 	case SQUASHFS_LCHRDEV_TYPE: {
10346f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			int chrdev = i->type == SQUASHFS_CHRDEV_TYPE;
1035545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			TRACE("create_inode: dev, rdev 0x%llx\n", i->data);
1036443c15812032991c98b33b5424b17bcd55fe3575plougher
10379dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
1038a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				if(force)
1039a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher					unlink(pathname);
1040a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
10416f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(mknod(pathname, chrdev ? S_IFCHR : S_IFBLK,
1042d4204758f77acb5a371fa1487a755b76a05d5476plougher						makedev((i->data >> 8) & 0xff,
1043d4204758f77acb5a371fa1487a755b76a05d5476plougher						i->data & 0xff)) == -1) {
1044c435240f52b78b0ef498118727ba8dad186db26bplougher					ERROR("create_inode: failed to create "
1045c435240f52b78b0ef498118727ba8dad186db26bplougher						"%s device %s, because %s\n",
1046d4204758f77acb5a371fa1487a755b76a05d5476plougher						chrdev ? "character" : "block",
1047d4204758f77acb5a371fa1487a755b76a05d5476plougher						pathname, strerror(errno));
1048443c15812032991c98b33b5424b17bcd55fe3575plougher					break;
1049443c15812032991c98b33b5424b17bcd55fe3575plougher				}
1050c435240f52b78b0ef498118727ba8dad186db26bplougher				set_attributes(pathname, i->mode, i->uid,
1051fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher					i->gid, i->time, i->xattr, TRUE);
1052443c15812032991c98b33b5424b17bcd55fe3575plougher				dev_count ++;
1053443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
1054c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("create_inode: could not create %s "
1055c435240f52b78b0ef498118727ba8dad186db26bplougher					"device %s, because you're not "
1056c435240f52b78b0ef498118727ba8dad186db26bplougher					"superuser!\n", chrdev ? "character" :
1057c435240f52b78b0ef498118727ba8dad186db26bplougher					"block", pathname);
1058443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
10596f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		}
1060443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_FIFO_TYPE:
106199ec5405b480bf852a0d9eed20693b750ed68943plougher		case SQUASHFS_LFIFO_TYPE:
1062443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: fifo\n");
1063443c15812032991c98b33b5424b17bcd55fe3575plougher
1064a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
1065a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
1066a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
1067443c15812032991c98b33b5424b17bcd55fe3575plougher			if(mknod(pathname, S_IFIFO, 0) == -1) {
1068d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("create_inode: failed to create fifo %s, "
1069d4204758f77acb5a371fa1487a755b76a05d5476plougher					"because %s\n", pathname,
1070d4204758f77acb5a371fa1487a755b76a05d5476plougher					strerror(errno));
1071443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
1072443c15812032991c98b33b5424b17bcd55fe3575plougher			}
1073c435240f52b78b0ef498118727ba8dad186db26bplougher			set_attributes(pathname, i->mode, i->uid, i->gid,
1074fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher				i->time, i->xattr, TRUE);
1075443c15812032991c98b33b5424b17bcd55fe3575plougher			fifo_count ++;
1076443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1077443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_SOCKET_TYPE:
107899ec5405b480bf852a0d9eed20693b750ed68943plougher		case SQUASHFS_LSOCKET_TYPE:
1079443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: socket\n");
1080443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("create_inode: socket %s ignored\n", pathname);
1081443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1082443c15812032991c98b33b5424b17bcd55fe3575plougher		default:
1083d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("Unknown inode type %d in create_inode_table!\n",
1084d4204758f77acb5a371fa1487a755b76a05d5476plougher				i->type);
1085443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
1086443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1087fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
10886f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	created_inode[i->inode_number - 1] = strdup(pathname);
1089443c15812032991c98b33b5424b17bcd55fe3575plougher
1090443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1091443c15812032991c98b33b5424b17bcd55fe3575plougher}
1092443c15812032991c98b33b5424b17bcd55fe3575plougher
1093443c15812032991c98b33b5424b17bcd55fe3575plougher
109402bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_directory_table(long long start, long long end)
1095443c15812032991c98b33b5424b17bcd55fe3575plougher{
1096443c15812032991c98b33b5424b17bcd55fe3575plougher	int bytes = 0, size = 0, res;
1097443c15812032991c98b33b5424b17bcd55fe3575plougher
109841da3230b2ac91a73f9190676f66b3d80b21c270plougher	TRACE("uncompress_directory_table: start %lld, end %lld\n", start, end);
109941da3230b2ac91a73f9190676f66b3d80b21c270plougher
1100443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
110107d4d0dcafeb198a568f859b88034637e6e7a8e7plougher		if(size - bytes < SQUASHFS_METADATA_SIZE) {
110207d4d0dcafeb198a568f859b88034637e6e7a8e7plougher			directory_table = realloc(directory_table, size +=
110307d4d0dcafeb198a568f859b88034637e6e7a8e7plougher				SQUASHFS_METADATA_SIZE);
110407d4d0dcafeb198a568f859b88034637e6e7a8e7plougher			if(directory_table == NULL)
110507d4d0dcafeb198a568f859b88034637e6e7a8e7plougher				EXIT_UNSQUASH("Out of memory in "
110607d4d0dcafeb198a568f859b88034637e6e7a8e7plougher					"uncompress_directory_table\n");
110707d4d0dcafeb198a568f859b88034637e6e7a8e7plougher		}
1108c435240f52b78b0ef498118727ba8dad186db26bplougher		TRACE("uncompress_directory_table: reading block 0x%llx\n",
1109c435240f52b78b0ef498118727ba8dad186db26bplougher				start);
1110443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(directory_table_hash, start, bytes);
1111176b325add10f6b9846f771f75d8543364d4c121plougher		res = read_block(fd, start, &start, directory_table + bytes);
1112c435240f52b78b0ef498118727ba8dad186db26bplougher		if(res == 0)
1113c435240f52b78b0ef498118727ba8dad186db26bplougher			EXIT_UNSQUASH("uncompress_directory_table: failed to "
1114c435240f52b78b0ef498118727ba8dad186db26bplougher				"read block\n");
1115443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
1116443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1117443c15812032991c98b33b5424b17bcd55fe3575plougher}
1118443c15812032991c98b33b5424b17bcd55fe3575plougher
1119443c15812032991c98b33b5424b17bcd55fe3575plougher
11209dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block,
11219dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherunsigned int *offset, unsigned int *type)
1122443c15812032991c98b33b5424b17bcd55fe3575plougher{
1123443c15812032991c98b33b5424b17bcd55fe3575plougher	if(dir->cur_entry == dir->dir_count)
1124443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
1125443c15812032991c98b33b5424b17bcd55fe3575plougher
1126443c15812032991c98b33b5424b17bcd55fe3575plougher	*name = dir->dirs[dir->cur_entry].name;
1127443c15812032991c98b33b5424b17bcd55fe3575plougher	*start_block = dir->dirs[dir->cur_entry].start_block;
1128443c15812032991c98b33b5424b17bcd55fe3575plougher	*offset = dir->dirs[dir->cur_entry].offset;
1129443c15812032991c98b33b5424b17bcd55fe3575plougher	*type = dir->dirs[dir->cur_entry].type;
1130443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->cur_entry ++;
1131443c15812032991c98b33b5424b17bcd55fe3575plougher
1132443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1133443c15812032991c98b33b5424b17bcd55fe3575plougher}
1134443c15812032991c98b33b5424b17bcd55fe3575plougher
1135443c15812032991c98b33b5424b17bcd55fe3575plougher
1136443c15812032991c98b33b5424b17bcd55fe3575ploughervoid squashfs_closedir(struct dir *dir)
1137443c15812032991c98b33b5424b17bcd55fe3575plougher{
1138443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir->dirs);
1139443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir);
1140443c15812032991c98b33b5424b17bcd55fe3575plougher}
1141443c15812032991c98b33b5424b17bcd55fe3575plougher
1142443c15812032991c98b33b5424b17bcd55fe3575plougher
114304281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougherchar *get_component(char *target, char **targname)
1144b54566f5c433764830c29c83151691d0034de094plougher{
114504281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher	char *start;
114604281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher
1147b54566f5c433764830c29c83151691d0034de094plougher	while(*target == '/')
11483cef656655723444fb1e2de1a001e6c2a54cf81erlougher		target ++;
1149b54566f5c433764830c29c83151691d0034de094plougher
115004281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher	start = target;
1151b54566f5c433764830c29c83151691d0034de094plougher	while(*target != '/' && *target!= '\0')
115204281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher		target ++;
1153b54566f5c433764830c29c83151691d0034de094plougher
115404281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher	*targname = strndup(start, target - start);
1155b54566f5c433764830c29c83151691d0034de094plougher
1156b54566f5c433764830c29c83151691d0034de094plougher	return target;
1157b54566f5c433764830c29c83151691d0034de094plougher}
1158b54566f5c433764830c29c83151691d0034de094plougher
1159b54566f5c433764830c29c83151691d0034de094plougher
11606ee88c6b5da9f7b3ea88ab7481db126efa01c8f4ploughervoid free_path(struct pathname *paths)
11616ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher{
11626ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	int i;
11636ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
11646ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	for(i = 0; i < paths->names; i++) {
11656ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths)
11666ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
11676ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		free(paths->name[i].name);
11686ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].preg) {
11696ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			regfree(paths->name[i].preg);
11706ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free(paths->name[i].preg);
11716ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		}
11726ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	}
11736ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
11746ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	free(paths);
11756ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher}
11766ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
11776ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
11784dba330d7b952f2f044d38e342e2ae3ea78910d6plougherstruct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
1179b54566f5c433764830c29c83151691d0034de094plougher{
118004281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher	char *targname;
11814dba330d7b952f2f044d38e342e2ae3ea78910d6plougher	int i, error;
118271add234b27054974d5e29f95b3fab3072792a62plougher
1183b7bb000643cd21c615a0366a7365441aa9c433f2plougher	TRACE("add_path: adding \"%s\" extract file\n", target);
1184b7bb000643cd21c615a0366a7365441aa9c433f2plougher
118504281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher	target = get_component(target, &targname);
118671add234b27054974d5e29f95b3fab3072792a62plougher
118771add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
11889dd4507fac1c96098eda8abe699a813a59451633plougher		paths = malloc(sizeof(struct pathname));
11899dd4507fac1c96098eda8abe699a813a59451633plougher		if(paths == NULL)
11904dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			EXIT_UNSQUASH("failed to allocate paths\n");
11914dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
119271add234b27054974d5e29f95b3fab3072792a62plougher		paths->names = 0;
119371add234b27054974d5e29f95b3fab3072792a62plougher		paths->name = NULL;
119471add234b27054974d5e29f95b3fab3072792a62plougher	}
119571add234b27054974d5e29f95b3fab3072792a62plougher
119671add234b27054974d5e29f95b3fab3072792a62plougher	for(i = 0; i < paths->names; i++)
119771add234b27054974d5e29f95b3fab3072792a62plougher		if(strcmp(paths->name[i].name, targname) == 0)
119871add234b27054974d5e29f95b3fab3072792a62plougher			break;
119971add234b27054974d5e29f95b3fab3072792a62plougher
12006ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	if(i == paths->names) {
1201d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1202d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * allocate new name entry
1203d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
120471add234b27054974d5e29f95b3fab3072792a62plougher		paths->names ++;
1205d4204758f77acb5a371fa1487a755b76a05d5476plougher		paths->name = realloc(paths->name, (i + 1) *
1206d4204758f77acb5a371fa1487a755b76a05d5476plougher			sizeof(struct path_entry));
1207fd628227871aecb36bb2b4f9c7f664f731510cdeplougher		if(paths->name == NULL)
1208fd628227871aecb36bb2b4f9c7f664f731510cdeplougher			EXIT_UNSQUASH("Out of memory in add_path\n");
120904281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher		paths->name[i].name = targname;
12106ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		paths->name[i].paths = NULL;
12114dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		if(use_regex) {
12124dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = malloc(sizeof(regex_t));
12131f3cc42a2f77966d321a38d1709eba26f71104bdplougher			if(paths->name[i].preg == NULL)
12141f3cc42a2f77966d321a38d1709eba26f71104bdplougher				EXIT_UNSQUASH("Out of memory in add_path\n");
1215d4204758f77acb5a371fa1487a755b76a05d5476plougher			error = regcomp(paths->name[i].preg, targname,
1216d4204758f77acb5a371fa1487a755b76a05d5476plougher				REG_EXTENDED|REG_NOSUB);
1217545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			if(error) {
121862859d215e7f828ace8501f5863f0c3d8b48ebf3Phillip Lougher				char str[1024]; /* overflow safe */
12194dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
12204dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				regerror(error, paths->name[i].preg, str, 1024);
1221d4204758f77acb5a371fa1487a755b76a05d5476plougher				EXIT_UNSQUASH("invalid regex %s in export %s, "
1222c435240f52b78b0ef498118727ba8dad186db26bplougher					"because %s\n", targname, alltarget,
1223c435240f52b78b0ef498118727ba8dad186db26bplougher					str);
12244dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			}
12254dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		} else
12264dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = NULL;
12276ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
12286ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(target[0] == '\0')
1229d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1230d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * at leaf pathname component
1231d4204758f77acb5a371fa1487a755b76a05d5476plougher			*/
123271add234b27054974d5e29f95b3fab3072792a62plougher			paths->name[i].paths = NULL;
123371add234b27054974d5e29f95b3fab3072792a62plougher		else
1234d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1235d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * recurse adding child components
1236d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
12374dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].paths = add_path(NULL, target, alltarget);
12386ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	} else {
1239d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1240d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * existing matching entry
1241d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
124204281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher		free(targname);
124304281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher
12446ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths == NULL) {
1245d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1246c435240f52b78b0ef498118727ba8dad186db26bplougher			 * No sub-directory which means this is the leaf
1247c435240f52b78b0ef498118727ba8dad186db26bplougher			 * component of a pre-existing extract which subsumes
1248c435240f52b78b0ef498118727ba8dad186db26bplougher			 * the extract currently being added, in which case stop
1249c435240f52b78b0ef498118727ba8dad186db26bplougher			 * adding components
1250d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
12516ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else if(target[0] == '\0') {
1252d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1253d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * at leaf pathname component and child components exist
1254c435240f52b78b0ef498118727ba8dad186db26bplougher			 * from more specific extracts, delete as they're
1255c435240f52b78b0ef498118727ba8dad186db26bplougher			 * subsumed by this extract
1256d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
12576ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
12586ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			paths->name[i].paths = NULL;
12596ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else
1260d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1261d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * recurse adding child components
1262d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
12636ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			add_path(paths->name[i].paths, target, alltarget);
126471add234b27054974d5e29f95b3fab3072792a62plougher	}
126571add234b27054974d5e29f95b3fab3072792a62plougher
126671add234b27054974d5e29f95b3fab3072792a62plougher	return paths;
126771add234b27054974d5e29f95b3fab3072792a62plougher}
12686ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
12696ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
1270a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *init_subdir()
127171add234b27054974d5e29f95b3fab3072792a62plougher{
12728372232d2460411adaa2299c32a0a88665e44902plougher	struct pathnames *new = malloc(sizeof(struct pathnames));
1273c5671cbe8dffaff7062ceb7b75f8d96c657a67b7plougher	if(new == NULL)
1274c5671cbe8dffaff7062ceb7b75f8d96c657a67b7plougher		EXIT_UNSQUASH("Out of memory in init_subdir\n");
1275a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	new->count = 0;
1276a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return new;
1277a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1278a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1279a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1280a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
1281a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
12823488d3bb3b89c394534ad2be909b661771a9581bplougher	if(paths->count % PATHS_ALLOC_SIZE == 0) {
1283d4204758f77acb5a371fa1487a755b76a05d5476plougher		paths = realloc(paths, sizeof(struct pathnames *) +
12843488d3bb3b89c394534ad2be909b661771a9581bplougher			(paths->count + PATHS_ALLOC_SIZE) *
12853488d3bb3b89c394534ad2be909b661771a9581bplougher			sizeof(struct pathname *));
12863488d3bb3b89c394534ad2be909b661771a9581bplougher		if(paths == NULL)
12873488d3bb3b89c394534ad2be909b661771a9581bplougher			EXIT_UNSQUASH("Out of memory in add_subdir\n");
12883488d3bb3b89c394534ad2be909b661771a9581bplougher	}
1289a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1290a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	paths->path[paths->count++] = path;
1291a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return paths;
1292a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1293a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1294a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1295a706f1b6bb48f288ecaf74e218ce20504bda52c6ploughervoid free_subdir(struct pathnames *paths)
1296a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1297a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free(paths);
1298a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1299a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1300a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1301a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherint matches(struct pathnames *paths, char *name, struct pathnames **new)
1302a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1303a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	int i, n;
130471add234b27054974d5e29f95b3fab3072792a62plougher
130571add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
130671add234b27054974d5e29f95b3fab3072792a62plougher		*new = NULL;
1307b54566f5c433764830c29c83151691d0034de094plougher		return TRUE;
130871add234b27054974d5e29f95b3fab3072792a62plougher	}
130971add234b27054974d5e29f95b3fab3072792a62plougher
1310a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = init_subdir();
1311a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1312a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	for(n = 0; n < paths->count; n++) {
1313a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		struct pathname *path = paths->path[n];
1314a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		for(i = 0; i < path->names; i++) {
1315a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			int match = use_regex ?
1316c435240f52b78b0ef498118727ba8dad186db26bplougher				regexec(path->name[i].preg, name, (size_t) 0,
1317c435240f52b78b0ef498118727ba8dad186db26bplougher				NULL, 0) == 0 : fnmatch(path->name[i].name,
1318c435240f52b78b0ef498118727ba8dad186db26bplougher				name, FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) ==
1319c435240f52b78b0ef498118727ba8dad186db26bplougher				0;
1320a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match && path->name[i].paths == NULL)
1321d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
1322d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * match on a leaf component, any subdirectories
1323c435240f52b78b0ef498118727ba8dad186db26bplougher				 * will implicitly match, therefore return an
1324c435240f52b78b0ef498118727ba8dad186db26bplougher				 * empty new search set
1325d4204758f77acb5a371fa1487a755b76a05d5476plougher				 */
1326a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				goto empty_set;
1327a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1328a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match)
1329d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
1330d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * match on a non-leaf component, add any
1331c435240f52b78b0ef498118727ba8dad186db26bplougher				 * subdirectories to the new set of
1332c435240f52b78b0ef498118727ba8dad186db26bplougher				 * subdirectories to scan for this name
1333d4204758f77acb5a371fa1487a755b76a05d5476plougher				 */
1334a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				*new = add_subdir(*new, path->name[i].paths);
1335a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		}
1336a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1337b54566f5c433764830c29c83151691d0034de094plougher
1338a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if((*new)->count == 0) {
1339d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1340d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * no matching names found, delete empty search set, and return
1341d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * FALSE
1342d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
1343a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(*new);
1344a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		*new = NULL;
1345a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		return FALSE;
1346a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1347a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1348d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
13490a0d045642e8e413f90b770539193d3fd1522786plougher	 * one or more matches with sub-directories found (no leaf matches),
13500a0d045642e8e413f90b770539193d3fd1522786plougher	 * return new search set and return TRUE
13510a0d045642e8e413f90b770539193d3fd1522786plougher	 */
1352a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
1353a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1354a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherempty_set:
1355d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
1356d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * found matching leaf exclude, return empty search set and return TRUE
1357d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
1358a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free_subdir(*new);
1359a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = NULL;
1360a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
1361b54566f5c433764830c29c83151691d0034de094plougher}
1362b54566f5c433764830c29c83151691d0034de094plougher
1363b54566f5c433764830c29c83151691d0034de094plougher
1364b807ab3497c01a49fed6f9daafce3bfc599a9421ploughervoid pre_scan(char *parent_name, unsigned int start_block, unsigned int offset,
1365d4204758f77acb5a371fa1487a755b76a05d5476plougher	struct pathnames *paths)
1366eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1367eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	unsigned int type;
1368454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher	char *name;
1369eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct pathnames *new;
1370eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
1371eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1372eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1373cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher	if(dir == NULL)
1374cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher		return;
1375cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher
1376eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
1377eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		struct inode *i;
1378454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher		char *pathname;
1379454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher		int res;
1380eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1381d4204758f77acb5a371fa1487a755b76a05d5476plougher		TRACE("pre_scan: name %s, start_block %d, offset %d, type %d\n",
1382d4204758f77acb5a371fa1487a755b76a05d5476plougher			name, start_block, offset, type);
1383eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1384eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(!matches(paths, name, &new))
1385eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			continue;
1386eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1387454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher		res = asprintf(&pathname, "%s/%s", parent_name, name);
1388454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher		if(res == -1)
1389454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher			EXIT_UNSQUASH("asprintf failed in dir_scan\n");
1390eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1391eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(type == SQUASHFS_DIR_TYPE)
1392eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			pre_scan(parent_name, start_block, offset, new);
1393eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		else if(new == NULL) {
1394d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(type == SQUASHFS_FILE_TYPE ||
1395d4204758f77acb5a371fa1487a755b76a05d5476plougher					type == SQUASHFS_LREG_TYPE) {
1396312e50b7b8c9dd39577657bd3d79fcedf6e91a1bplougher				i = s_ops.read_inode(start_block, offset);
1397eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				if(created_inode[i->inode_number - 1] == NULL) {
1398d4204758f77acb5a371fa1487a755b76a05d5476plougher					created_inode[i->inode_number - 1] =
1399d4204758f77acb5a371fa1487a755b76a05d5476plougher						(char *) i;
1400d4204758f77acb5a371fa1487a755b76a05d5476plougher					total_blocks += (i->data +
1401d4204758f77acb5a371fa1487a755b76a05d5476plougher						(block_size - 1)) >> block_log;
1402eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
1403eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				total_files ++;
1404eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			}
1405eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			total_inodes ++;
1406eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		}
1407eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1408eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		free_subdir(new);
1409454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher		free(pathname);
1410eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
1411eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1412eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	squashfs_closedir(dir);
1413eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1414eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1415eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1416a2cff53655359b044ea88baa76cb16d1c8f44d2aploughervoid dir_scan(char *parent_name, unsigned int start_block, unsigned int offset,
1417d4204758f77acb5a371fa1487a755b76a05d5476plougher	struct pathnames *paths)
1418443c15812032991c98b33b5424b17bcd55fe3575plougher{
1419443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int type;
1420d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher	char *name;
1421a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *new;
1422eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
1423eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1424443c15812032991c98b33b5424b17bcd55fe3575plougher
1425cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher	if(dir == NULL) {
1426cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher		ERROR("dir_scan: failed to read directory %s, skipping\n",
1427cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher			parent_name);
1428cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher		return;
1429cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher	}
1430cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher
1431eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(lsonly || info)
1432eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		print_filename(parent_name, i);
1433eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
14342c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	if(!lsonly) {
14352c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		/*
14362c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		 * Make directory with default User rwx permissions rather than
14372c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		 * the permissions from the filesystem, as these may not have
14382c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		 * write/execute permission.  These are fixed up later in
14392c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		 * set_attributes().
14402c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		 */
14412c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		int res = mkdir(parent_name, S_IRUSR|S_IWUSR|S_IXUSR);
14422c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		if(res == -1) {
14432c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			/*
14442c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 * Skip directory if mkdir fails, unless we're
14452c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 * forcing and the error is -EEXIST
14462c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 */
14472c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			if(!force || errno != EEXIST) {
14482c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher				ERROR("dir_scan: failed to make directory %s, "
14492c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher					"because %s\n", parent_name,
14502c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher					strerror(errno));
14512c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher				squashfs_closedir(dir);
14522c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher				return;
14532c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			}
14542c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
14552c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			/*
14562c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 * Try to change permissions of existing directory so
14572c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 * that we can write to it
14582c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 */
14592c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			res = chmod(parent_name, S_IRUSR|S_IWUSR|S_IXUSR);
14602c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			if (res == -1)
14612c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher				ERROR("dir_scan: failed to change permissions "
14622c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher					"for directory %s, because %s\n",
14632c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher					parent_name, strerror(errno));
14642c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		}
146585917a285edbd4bb78f1b245f66c634d1e0d4029plougher	}
1466443c15812032991c98b33b5424b17bcd55fe3575plougher
1467443c15812032991c98b33b5424b17bcd55fe3575plougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
1468d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher		char *pathname;
1469d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher		int res;
1470d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher
1471d4204758f77acb5a371fa1487a755b76a05d5476plougher		TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n",
1472d4204758f77acb5a371fa1487a755b76a05d5476plougher			name, start_block, offset, type);
1473b54566f5c433764830c29c83151691d0034de094plougher
147471add234b27054974d5e29f95b3fab3072792a62plougher
147571add234b27054974d5e29f95b3fab3072792a62plougher		if(!matches(paths, name, &new))
1476b54566f5c433764830c29c83151691d0034de094plougher			continue;
1477b54566f5c433764830c29c83151691d0034de094plougher
1478d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher		res = asprintf(&pathname, "%s/%s", parent_name, name);
1479d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher		if(res == -1)
1480d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher			EXIT_UNSQUASH("asprintf failed in dir_scan\n");
1481fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
1482443c15812032991c98b33b5424b17bcd55fe3575plougher		if(type == SQUASHFS_DIR_TYPE)
148371add234b27054974d5e29f95b3fab3072792a62plougher			dir_scan(pathname, start_block, offset, new);
1484a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		else if(new == NULL) {
1485312e50b7b8c9dd39577657bd3d79fcedf6e91a1bplougher			i = s_ops.read_inode(start_block, offset);
14866f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
14876f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(lsonly || info)
14886f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				print_filename(pathname, i);
14896f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
1490eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			if(!lsonly) {
14916f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				create_inode(pathname, i);
1492eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				update_progress_bar();
1493eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
1494427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher
1495d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(i->type == SQUASHFS_SYMLINK_TYPE ||
1496d4204758f77acb5a371fa1487a755b76a05d5476plougher					i->type == SQUASHFS_LSYMLINK_TYPE)
1497427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher				free(i->symlink);
14986f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		}
1499a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1500a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(new);
1501d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher		free(pathname);
1502443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1503443c15812032991c98b33b5424b17bcd55fe3575plougher
1504074d3f1129eae914655f6637773488052bf22327rlougher	if(!lsonly)
15052c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		queue_dir(parent_name, dir);
1506443c15812032991c98b33b5424b17bcd55fe3575plougher
1507443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_closedir(dir);
1508443c15812032991c98b33b5424b17bcd55fe3575plougher	dir_count ++;
1509443c15812032991c98b33b5424b17bcd55fe3575plougher}
1510443c15812032991c98b33b5424b17bcd55fe3575plougher
1511443c15812032991c98b33b5424b17bcd55fe3575plougher
1512b624936abba03d38b7e9245c647339d8f6f34274ploughervoid squashfs_stat(char *source)
1513b624936abba03d38b7e9245c647339d8f6f34274plougher{
151427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	time_t mkfs_time = (time_t) sBlk.s.mkfs_time;
1515b624936abba03d38b7e9245c647339d8f6f34274plougher	char *mkfs_str = ctime(&mkfs_time);
1516b624936abba03d38b7e9245c647339d8f6f34274plougher
1517b624936abba03d38b7e9245c647339d8f6f34274plougher#if __BYTE_ORDER == __BIG_ENDIAN
1518d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n",
151927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.s_major == 4 ? "" : swap ? "little endian " :
152027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		"big endian ", sBlk.s.s_major, sBlk.s.s_minor, source);
1521b624936abba03d38b7e9245c647339d8f6f34274plougher#else
1522d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n",
152327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.s_major == 4 ? "" : swap ? "big endian " :
152427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		"little endian ", sBlk.s.s_major, sBlk.s.s_minor, source);
1525b624936abba03d38b7e9245c647339d8f6f34274plougher#endif
1526c766500607f1ea7494b8360409be3d8ea66f9761plougher
1527d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Creation or last append time %s", mkfs_str ? mkfs_str :
1528d4204758f77acb5a371fa1487a755b76a05d5476plougher		"failed to get time\n");
1529e5e5a7502f722fae4f057f49932fe4de2501f6e8plougher	printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n",
1530e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		sBlk.s.bytes_used / 1024.0, sBlk.s.bytes_used /
1531e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		(1024.0 * 1024.0));
1532c766500607f1ea7494b8360409be3d8ea66f9761plougher
153327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major == 4)
1534e5e5a7502f722fae4f057f49932fe4de2501f6e8plougher		printf("Compression %s\n", comp->name);
1535c766500607f1ea7494b8360409be3d8ea66f9761plougher
153627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	printf("Block size %d\n", sBlk.s.block_size);
1537d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Filesystem is %sexportable via NFS\n",
153827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_EXPORTABLE(sBlk.s.flags) ? "" : "not ");
1539d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Inodes are %scompressed\n",
154027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_UNCOMPRESSED_INODES(sBlk.s.flags) ? "un" : "");
1541d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Data is %scompressed\n",
154227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_UNCOMPRESSED_DATA(sBlk.s.flags) ? "un" : "");
1543c766500607f1ea7494b8360409be3d8ea66f9761plougher
15447ca09d1320cdc30a068f179b93ca5c141b55c395plougher	if(sBlk.s.s_major > 1) {
15457ca09d1320cdc30a068f179b93ca5c141b55c395plougher		if(SQUASHFS_NO_FRAGMENTS(sBlk.s.flags))
15467ca09d1320cdc30a068f179b93ca5c141b55c395plougher			printf("Fragments are not stored\n");
15477ca09d1320cdc30a068f179b93ca5c141b55c395plougher		else {
15487ca09d1320cdc30a068f179b93ca5c141b55c395plougher			printf("Fragments are %scompressed\n",
15497ca09d1320cdc30a068f179b93ca5c141b55c395plougher				SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.s.flags) ?
15507ca09d1320cdc30a068f179b93ca5c141b55c395plougher				"un" : "");
15517ca09d1320cdc30a068f179b93ca5c141b55c395plougher			printf("Always_use_fragments option is %sspecified\n",
15527ca09d1320cdc30a068f179b93ca5c141b55c395plougher				SQUASHFS_ALWAYS_FRAGMENTS(sBlk.s.flags) ? "" :
15537ca09d1320cdc30a068f179b93ca5c141b55c395plougher				"not ");
15547ca09d1320cdc30a068f179b93ca5c141b55c395plougher		}
15557ca09d1320cdc30a068f179b93ca5c141b55c395plougher	}
15567ca09d1320cdc30a068f179b93ca5c141b55c395plougher
1557de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher	if(sBlk.s.s_major == 4) {
1558de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher		if(SQUASHFS_NO_XATTRS(sBlk.s.flags))
1559de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher			printf("Xattrs are not stored\n");
1560de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher		else
1561de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher			printf("Xattrs are %scompressed\n",
1562de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher				SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.s.flags) ?
1563de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher				"un" : "");
1564de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher	}
1565de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher
1566ba95dd35ef0e9f618d926ddc1a595076adc23818plougher	if(sBlk.s.s_major < 4)
1567ba95dd35ef0e9f618d926ddc1a595076adc23818plougher			printf("Check data is %spresent in the filesystem\n",
1568ba95dd35ef0e9f618d926ddc1a595076adc23818plougher				SQUASHFS_CHECK_DATA(sBlk.s.flags) ? "" :
1569ba95dd35ef0e9f618d926ddc1a595076adc23818plougher				"not ");
1570c766500607f1ea7494b8360409be3d8ea66f9761plougher
157127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major > 1)
1572d4204758f77acb5a371fa1487a755b76a05d5476plougher		printf("Duplicates are %sremoved\n",
157327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			SQUASHFS_DUPLICATES(sBlk.s.flags) ? "" : "not ");
15740337de3977eec74e6a3d28e0d0863299246de8b7plougher	else
15750337de3977eec74e6a3d28e0d0863299246de8b7plougher		printf("Duplicates are removed\n");
1576c766500607f1ea7494b8360409be3d8ea66f9761plougher
157727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major > 1)
157827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		printf("Number of fragments %d\n", sBlk.s.fragments);
1579c766500607f1ea7494b8360409be3d8ea66f9761plougher
158027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	printf("Number of inodes %d\n", sBlk.s.inodes);
1581c766500607f1ea7494b8360409be3d8ea66f9761plougher
158227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major == 4)
158327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		printf("Number of ids %d\n", sBlk.s.no_ids);
15840f74340e3b68533339adc60f418ddf59fa188f61plougher	else {
15850f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of uids %d\n", sBlk.no_uids);
15860f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of gids %d\n", sBlk.no_guids);
15870f74340e3b68533339adc60f418ddf59fa188f61plougher	}
1588b624936abba03d38b7e9245c647339d8f6f34274plougher
158927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	TRACE("sBlk.s.inode_table_start 0x%llx\n", sBlk.s.inode_table_start);
159027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	TRACE("sBlk.s.directory_table_start 0x%llx\n",
159127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.directory_table_start);
1592c766500607f1ea7494b8360409be3d8ea66f9761plougher
15930ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher	if(sBlk.s.s_major > 1)
15940ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher		TRACE("sBlk.s.fragment_table_start 0x%llx\n\n",
15950ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher			sBlk.s.fragment_table_start);
15960ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher
15970ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher	if(sBlk.s.s_major > 2)
15980ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher		TRACE("sBlk.s.lookup_table_start 0x%llx\n\n",
15990ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher			sBlk.s.lookup_table_start);
16000ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher
1601053da34003852e494400c1ade35b526e1821b576plougher	if(sBlk.s.s_major == 4) {
160227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		TRACE("sBlk.s.id_table_start 0x%llx\n", sBlk.s.id_table_start);
1603053da34003852e494400c1ade35b526e1821b576plougher		TRACE("sBlk.s.xattr_id_table_start 0x%llx\n",
1604053da34003852e494400c1ade35b526e1821b576plougher			sBlk.s.xattr_id_table_start);
1605053da34003852e494400c1ade35b526e1821b576plougher	} else {
16060f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.uid_start 0x%llx\n", sBlk.uid_start);
16070f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.guid_start 0x%llx\n", sBlk.guid_start);
16080f74340e3b68533339adc60f418ddf59fa188f61plougher	}
1609b624936abba03d38b7e9245c647339d8f6f34274plougher}
1610b624936abba03d38b7e9245c647339d8f6f34274plougher
1611b624936abba03d38b7e9245c647339d8f6f34274plougher
161202bc3bcabf2b219f63961f07293b83629948f026plougherint read_super(char *source)
1613443c15812032991c98b33b5424b17bcd55fe3575plougher{
16146490378e5b5e8dc058daf28423a7465699a6ba7bplougher	squashfs_super_block_3 sBlk_3;
161564e83fda63a1b8408ffbfa466e6c67b0de7a8c99plougher	struct squashfs_super_block sBlk_4;
16166490378e5b5e8dc058daf28423a7465699a6ba7bplougher
16176490378e5b5e8dc058daf28423a7465699a6ba7bplougher	/*
16186490378e5b5e8dc058daf28423a7465699a6ba7bplougher	 * Try to read a Squashfs 4 superblock
16196490378e5b5e8dc058daf28423a7465699a6ba7bplougher	 */
162064e83fda63a1b8408ffbfa466e6c67b0de7a8c99plougher	read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
16213306cb2b54a60a32664617118336ac141e1471b6plougher		&sBlk_4);
162254660e177ba40ab08ee2f3304b9f030eb5675677plougher	swap = sBlk_4.s_magic != SQUASHFS_MAGIC;
16236490378e5b5e8dc058daf28423a7465699a6ba7bplougher	SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4);
16246490378e5b5e8dc058daf28423a7465699a6ba7bplougher
1625d4204758f77acb5a371fa1487a755b76a05d5476plougher	if(sBlk_4.s_magic == SQUASHFS_MAGIC && sBlk_4.s_major == 4 &&
1626d4204758f77acb5a371fa1487a755b76a05d5476plougher			sBlk_4.s_minor == 0) {
16276490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.squashfs_opendir = squashfs_opendir_4;
16286490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_fragment = read_fragment_4;
16296490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_fragment_table = read_fragment_table_4;
16306490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_block_list = read_block_list_2;
16316490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_inode = read_inode_4;
16326490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_uids_guids = read_uids_guids_4;
16336490378e5b5e8dc058daf28423a7465699a6ba7bplougher		memcpy(&sBlk, &sBlk_4, sizeof(sBlk_4));
1634efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
1635efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		/*
1636efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		 * Check the compression type
1637efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		 */
163827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		comp = lookup_compressor_id(sBlk.s.compression);
16396490378e5b5e8dc058daf28423a7465699a6ba7bplougher		return TRUE;
16406490378e5b5e8dc058daf28423a7465699a6ba7bplougher	}
16416490378e5b5e8dc058daf28423a7465699a6ba7bplougher
16426490378e5b5e8dc058daf28423a7465699a6ba7bplougher	/*
16436490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 * Not a Squashfs 4 superblock, try to read a squashfs 3 superblock
16446490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 * (compatible with 1 and 2 filesystems)
16456490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 */
164686561909d9ca51a4e4ce4efcfea30b41d1d08275plougher	read_fs_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block_3),
16473306cb2b54a60a32664617118336ac141e1471b6plougher		&sBlk_3);
1648443c15812032991c98b33b5424b17bcd55fe3575plougher
1649d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
1650d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * Check it is a SQUASHFS superblock
1651d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
1652443c15812032991c98b33b5424b17bcd55fe3575plougher	swap = 0;
165321ee4773956342a8a7d0f14e430ae77ffbd10601plougher	if(sBlk_3.s_magic != SQUASHFS_MAGIC) {
165421ee4773956342a8a7d0f14e430ae77ffbd10601plougher		if(sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP) {
16557a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher			squashfs_super_block_3 sblk;
1656c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("Reading a different endian SQUASHFS filesystem "
1657c435240f52b78b0ef498118727ba8dad186db26bplougher				"on %s\n", source);
16586490378e5b5e8dc058daf28423a7465699a6ba7bplougher			SQUASHFS_SWAP_SUPER_BLOCK_3(&sblk, &sBlk_3);
16596490378e5b5e8dc058daf28423a7465699a6ba7bplougher			memcpy(&sBlk_3, &sblk, sizeof(squashfs_super_block_3));
1660443c15812032991c98b33b5424b17bcd55fe3575plougher			swap = 1;
1661443c15812032991c98b33b5424b17bcd55fe3575plougher		} else  {
1662c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("Can't find a SQUASHFS superblock on %s\n",
1663c435240f52b78b0ef498118727ba8dad186db26bplougher				source);
1664443c15812032991c98b33b5424b17bcd55fe3575plougher			goto failed_mount;
1665443c15812032991c98b33b5424b17bcd55fe3575plougher		}
1666443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1667443c15812032991c98b33b5424b17bcd55fe3575plougher
166827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.s_magic = sBlk_3.s_magic;
166927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.inodes = sBlk_3.inodes;
167027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.mkfs_time = sBlk_3.mkfs_time;
167127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.block_size = sBlk_3.block_size;
167227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.fragments = sBlk_3.fragments;
167327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.block_log = sBlk_3.block_log;
167427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.flags = sBlk_3.flags;
167527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.s_major = sBlk_3.s_major;
167627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.s_minor = sBlk_3.s_minor;
167727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.root_inode = sBlk_3.root_inode;
167827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.bytes_used = sBlk_3.bytes_used;
167927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.inode_table_start = sBlk_3.inode_table_start;
168027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.directory_table_start = sBlk_3.directory_table_start;
168127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.fragment_table_start = sBlk_3.fragment_table_start;
168227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.lookup_table_start = sBlk_3.lookup_table_start;
16836490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.no_uids = sBlk_3.no_uids;
16846490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.no_guids = sBlk_3.no_guids;
16856490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.uid_start = sBlk_3.uid_start;
16866490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.guid_start = sBlk_3.guid_start;
168727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK;
16886490378e5b5e8dc058daf28423a7465699a6ba7bplougher
1689443c15812032991c98b33b5424b17bcd55fe3575plougher	/* Check the MAJOR & MINOR versions */
169027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major == 1 || sBlk.s.s_major == 2) {
169127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.bytes_used = sBlk_3.bytes_used_2;
16926490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.uid_start = sBlk_3.uid_start_2;
16936490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.guid_start = sBlk_3.guid_start_2;
169427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.inode_table_start = sBlk_3.inode_table_start_2;
169527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.directory_table_start = sBlk_3.directory_table_start_2;
169602bc3bcabf2b219f63961f07293b83629948f026plougher
169727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		if(sBlk.s.s_major == 1) {
169827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.block_size = sBlk_3.block_size_1;
169927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.fragment_table_start = sBlk.uid_start;
1700ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.squashfs_opendir = squashfs_opendir_1;
1701ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_1;
1702ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_block_list = read_block_list_1;
17036f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_1;
170479e700efc62527661ce140bd1013a2b60577917eplougher			s_ops.read_uids_guids = read_uids_guids_1;
1705ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		} else {
170627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.fragment_table_start =
1707c435240f52b78b0ef498118727ba8dad186db26bplougher				sBlk_3.fragment_table_start_2;
1708ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.squashfs_opendir = squashfs_opendir_1;
1709ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment = read_fragment_2;
1710ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_2;
1711ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.read_block_list = read_block_list_2;
17126f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_2;
171379e700efc62527661ce140bd1013a2b60577917eplougher			s_ops.read_uids_guids = read_uids_guids_1;
1714ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		}
171527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	} else if(sBlk.s.s_major == 3) {
1716ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.squashfs_opendir = squashfs_opendir_3;
1717ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_fragment = read_fragment_3;
1718ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_fragment_table = read_fragment_table_3;
1719ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_block_list = read_block_list_2;
1720ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_inode = read_inode_3;
172179e700efc62527661ce140bd1013a2b60577917eplougher		s_ops.read_uids_guids = read_uids_guids_1;
172202bc3bcabf2b219f63961f07293b83629948f026plougher	} else {
172327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		ERROR("Filesystem on %s is (%d:%d), ", source, sBlk.s.s_major,
172427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.s_minor);
17254c99cb7f458d8e1c598f1c80793daf3696c9b528plougher		ERROR("which is a later filesystem version than I support!\n");
1726443c15812032991c98b33b5424b17bcd55fe3575plougher		goto failed_mount;
1727443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1728443c15812032991c98b33b5424b17bcd55fe3575plougher
1729efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	/*
173099c8abf4de4297b3159355a0cefe9ad6f5182827plougher	 * 1.x, 2.x and 3.x filesystems use gzip compression.
1731efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	 */
1732efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	comp = lookup_compressor("gzip");
1733443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1734443c15812032991c98b33b5424b17bcd55fe3575plougher
1735443c15812032991c98b33b5424b17bcd55fe3575plougherfailed_mount:
1736443c15812032991c98b33b5424b17bcd55fe3575plougher	return FALSE;
1737443c15812032991c98b33b5424b17bcd55fe3575plougher}
1738443c15812032991c98b33b5424b17bcd55fe3575plougher
1739443c15812032991c98b33b5424b17bcd55fe3575plougher
1740a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathname *process_extract_files(struct pathname *path, char *filename)
174171add234b27054974d5e29f95b3fab3072792a62plougher{
174271add234b27054974d5e29f95b3fab3072792a62plougher	FILE *fd;
1743afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher	char buffer[MAX_LINE + 1]; /* overflow safe */
1744e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher	char *name;
174571add234b27054974d5e29f95b3fab3072792a62plougher
174663e21ee4b795bb900f82c18e7b5c6f7369907360plougher	fd = fopen(filename, "r");
174763e21ee4b795bb900f82c18e7b5c6f7369907360plougher	if(fd == NULL)
1748e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		EXIT_UNSQUASH("Failed to open extract file \"%s\" because %s\n",
1749e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			filename, strerror(errno));
1750e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1751afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher	while(fgets(name = buffer, MAX_LINE + 1, fd) != NULL) {
1752e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		int len = strlen(name);
1753e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1754afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher		if(len == MAX_LINE && name[len - 1] != '\n')
1755e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			/* line too large */
1756e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			EXIT_UNSQUASH("Line too long when reading "
1757afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher				"extract file \"%s\", larger than %d "
1758afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher				"bytes\n", MAX_LINE, filename);
1759e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1760e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		/*
1761e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		 * Remove '\n' terminator if it exists (the last line
1762e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		 * in the file may not be '\n' terminated)
1763e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		 */
1764e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		if(len && name[len - 1] == '\n')
1765e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			name[len - 1] = '\0';
1766e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1767e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		/* Skip any leading whitespace */
1768e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		while(isspace(*name))
1769e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			name ++;
1770e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1771e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		/* if comment line, skip */
1772e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		if(*name == '#')
1773e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			continue;
1774e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1775e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		/* check for initial backslash, to accommodate
1776e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		 * filenames with leading space or leading # character
1777e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		 */
1778e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		if(*name == '\\')
1779e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			name ++;
1780e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1781e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		/* if line is now empty after skipping characters, skip it */
1782e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		if(*name == '\0')
1783e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			continue;
178471add234b27054974d5e29f95b3fab3072792a62plougher
1785a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, name, name);
1786e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher	}
1787e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1788e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher	if(ferror(fd))
1789e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		EXIT_UNSQUASH("Reading extract file \"%s\" failed because %s\n",
1790e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			filename, strerror(errno));
179171add234b27054974d5e29f95b3fab3072792a62plougher
179271add234b27054974d5e29f95b3fab3072792a62plougher	fclose(fd);
1793a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return path;
179471add234b27054974d5e29f95b3fab3072792a62plougher}
179571add234b27054974d5e29f95b3fab3072792a62plougher
179671add234b27054974d5e29f95b3fab3072792a62plougher
1797d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
1798d4204758f77acb5a371fa1487a755b76a05d5476plougher * reader thread.  This thread processes read requests queued by the
1799d4204758f77acb5a371fa1487a755b76a05d5476plougher * cache_get() routine.
1800d4204758f77acb5a371fa1487a755b76a05d5476plougher */
18018888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *reader(void *arg)
18028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
18038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
18048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct cache_entry *entry = queue_get(to_reader);
180586561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		int res = read_fs_bytes(fd, entry->block,
18068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size),
18078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data);
18088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(res && SQUASHFS_COMPRESSED_BLOCK(entry->size))
1810d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1811c435240f52b78b0ef498118727ba8dad186db26bplougher			 * queue successfully read block to the deflate
1812c435240f52b78b0ef498118727ba8dad186db26bplougher			 * thread(s) for further processing
1813d4204758f77acb5a371fa1487a755b76a05d5476plougher 			 */
18148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			queue_put(to_deflate, entry);
18158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else
1816d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1817d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * block has either been successfully read and is
1818d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * uncompressed, or an error has occurred, clear pending
1819c435240f52b78b0ef498118727ba8dad186db26bplougher			 * flag, set error appropriately, and wake up any
1820c435240f52b78b0ef498118727ba8dad186db26bplougher			 * threads waiting on this buffer
1821d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
18228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_ready(entry, !res);
18238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
18248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
18258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1827d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
1828d4204758f77acb5a371fa1487a755b76a05d5476plougher * writer thread.  This processes file write requests queued by the
1829d4204758f77acb5a371fa1487a755b76a05d5476plougher * write_file() routine.
1830d4204758f77acb5a371fa1487a755b76a05d5476plougher */
18318888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *writer(void *arg)
18328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
18338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int i;
18348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
18368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct squashfs_file *file = queue_get(to_writer);
18378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int file_fd;
183887f5e0e29e5f56516daaa51b1d36cde3d86a0f1fplougher		long long hole = 0;
183927636cb2cec37a68313f9eb825c0548245eecad0plougher		int failed = FALSE;
1840c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		int error;
18418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(file == NULL) {
18438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			queue_put(from_writer, NULL);
18448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			continue;
18452c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		} else if(file->fd == -1) {
18462c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			/* write attributes for directory file->pathname */
18472c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			set_attributes(file->pathname, file->mode, file->uid,
18482c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher				file->gid, file->time, file->xattr, TRUE);
18492c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			free(file->pathname);
18502c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			free(file);
18512c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			continue;
18528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
18538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		TRACE("writer: regular file, blocks %d\n", file->blocks);
18558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		file_fd = file->fd;
18578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1858eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		for(i = 0; i < file->blocks; i++, cur_blocks ++) {
18598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			struct file_entry *block = queue_get(to_writer);
18608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(block->buffer == 0) { /* sparse file */
18628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole += block->size;
18638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				free(block);
18648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				continue;
18658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
18668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_wait(block->buffer);
186827636cb2cec37a68313f9eb825c0548245eecad0plougher
186927636cb2cec37a68313f9eb825c0548245eecad0plougher			if(block->buffer->error)
187027636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
187127636cb2cec37a68313f9eb825c0548245eecad0plougher
1872c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			if(failed)
1873c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				continue;
1874c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
1875c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			error = write_block(file_fd, block->buffer->data +
1876c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				block->offset, block->size, hole, file->sparse);
1877c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
1878c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			if(error == FALSE) {
1879d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("writer: failed to write data block %d\n",
1880d4204758f77acb5a371fa1487a755b76a05d5476plougher					i);
188127636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
18828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
1883c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
18848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			hole = 0;
18858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_put(block->buffer);
18868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			free(block);
18878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
18888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
188927636cb2cec37a68313f9eb825c0548245eecad0plougher		if(hole && failed == FALSE) {
1890d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1891d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * corner case for hole extending to end of file
1892d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
1893d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(file->sparse == FALSE ||
1894d4204758f77acb5a371fa1487a755b76a05d5476plougher					lseek(file_fd, hole, SEEK_CUR) == -1) {
1895d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
1896d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * for files which we don't want to write
1897c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * sparsely, or for broken lseeks which cannot
1898c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * seek beyond end of file, write_block will do
1899c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * the right thing
1900c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 */
19018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole --;
1902d4204758f77acb5a371fa1487a755b76a05d5476plougher				if(write_block(file_fd, "\0", 1, hole,
1903d4204758f77acb5a371fa1487a755b76a05d5476plougher						file->sparse) == FALSE) {
1904d4204758f77acb5a371fa1487a755b76a05d5476plougher					ERROR("writer: failed to write sparse "
1905d4204758f77acb5a371fa1487a755b76a05d5476plougher						"data block\n");
190627636cb2cec37a68313f9eb825c0548245eecad0plougher					failed = TRUE;
19078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				}
19088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			} else if(ftruncate(file_fd, file->file_size) == -1) {
1909d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("writer: failed to write sparse data "
1910d4204758f77acb5a371fa1487a755b76a05d5476plougher					"block\n");
191127636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
19128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
19138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
19148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1915cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		close_wake(file_fd);
191627636cb2cec37a68313f9eb825c0548245eecad0plougher		if(failed == FALSE)
1917d4204758f77acb5a371fa1487a755b76a05d5476plougher			set_attributes(file->pathname, file->mode, file->uid,
1918fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher				file->gid, file->time, file->xattr, force);
191927636cb2cec37a68313f9eb825c0548245eecad0plougher		else {
192027636cb2cec37a68313f9eb825c0548245eecad0plougher			ERROR("Failed to write %s, skipping\n", file->pathname);
192127636cb2cec37a68313f9eb825c0548245eecad0plougher			unlink(file->pathname);
192227636cb2cec37a68313f9eb825c0548245eecad0plougher		}
192379df93becb68081effabebba3006c794be308598plougher		free(file->pathname);
19248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		free(file);
192527636cb2cec37a68313f9eb825c0548245eecad0plougher
19268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
19278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
19288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
19298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1930d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
1931d4204758f77acb5a371fa1487a755b76a05d5476plougher * decompress thread.  This decompresses buffers queued by the read thread
1932d4204758f77acb5a371fa1487a755b76a05d5476plougher */
19338888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *deflator(void *arg)
19348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
19358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	char tmp[block_size];
19368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
19378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
19388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct cache_entry *entry = queue_get(to_deflate);
1939efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		int error, res;
1940efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
1941b48442b2e37b3cb7efbffb032968f115eec7963cplougher		res = compressor_uncompress(comp, tmp, entry->data,
1942efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size), block_size,
1943efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			&error);
1944efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
1945efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		if(res == -1)
1946efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			ERROR("%s uncompress failed with error code %d\n",
1947efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher				comp->name, error);
1948efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		else
1949efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			memcpy(entry->data, tmp, res);
19508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1951d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1952d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * block has been either successfully decompressed, or an error
19538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * occurred, clear pending flag, set error appropriately and
1954d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 * wake up any threads waiting on this block
1955d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 */
1956efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		cache_block_ready(entry, res == -1);
19578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
19588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
19598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
19608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1961eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid *progress_thread(void *arg)
1962eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1963eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct timeval timeval;
1964eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct timespec timespec;
19651b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct itimerval itimerval;
19661b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct winsize winsize;
19671b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
19681b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
196901b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher		if(isatty(STDOUT_FILENO))
197001b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher			ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
197101b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher				"columns\n");
19721b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = 80;
19731b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	} else
19741b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = winsize.ws_col;
19751b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGWINCH, sigwinch_handler);
19761b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGALRM, sigalrm_handler);
19771b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
19781b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_sec = 0;
19791b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_usec = 250000;
19801b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_sec = 0;
19811b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_usec = 250000;
19821b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	setitimer(ITIMER_REAL, &itimerval, NULL);
1983eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1984eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_cond_init(&progress_wait, NULL);
1985eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
19861b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
1987eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(1) {
1988eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		gettimeofday(&timeval, NULL);
1989eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		timespec.tv_sec = timeval.tv_sec;
1990eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(timeval.tv_usec + 250000 > 999999)
1991eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			timespec.tv_sec++;
1992c435240f52b78b0ef498118727ba8dad186db26bplougher		timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) *
1993c435240f52b78b0ef498118727ba8dad186db26bplougher			1000;
1994c435240f52b78b0ef498118727ba8dad186db26bplougher		pthread_cond_timedwait(&progress_wait, &screen_mutex,
1995c435240f52b78b0ef498118727ba8dad186db26bplougher			&timespec);
19961b42101056befe25b5f19d5b099e806a2ecee9cdplougher		if(progress_enabled)
19971b42101056befe25b5f19d5b099e806a2ecee9cdplougher			progress_bar(sym_count + dev_count +
1998d4204758f77acb5a371fa1487a755b76a05d5476plougher				fifo_count + cur_blocks, total_inodes -
1999d4204758f77acb5a371fa1487a755b76a05d5476plougher				total_files + total_blocks, columns);
2000eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
2001eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
2002eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2003eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
20048888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid initialise_threads(int fragment_buffer_size, int data_buffer_size)
20058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2006cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	struct rlimit rlim;
2007cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	int i, max_files, res;
20088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigset_t sigmask, old_mask;
20098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
20108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigemptyset(&sigmask);
20118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigaddset(&sigmask, SIGINT);
20128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigaddset(&sigmask, SIGQUIT);
20138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
2014c435240f52b78b0ef498118727ba8dad186db26bplougher		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
2015c435240f52b78b0ef498118727ba8dad186db26bplougher			"\n");
20168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
20178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(processors == -1) {
20188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifndef linux
20198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int mib[2];
20208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		size_t len = sizeof(processors);
20218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
20228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[0] = CTL_HW;
20238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifdef HW_AVAILCPU
20248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_AVAILCPU;
20258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
20268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_NCPU;
20278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
20288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
20298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
2030d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("Failed to get number of available processors.  "
2031d4204758f77acb5a371fa1487a755b76a05d5476plougher				"Defaulting to 1\n");
20328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors = 1;
20338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
20348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
20359cc26b77a61fefdeb45f5c487c2bfdefd394b66fplougher		processors = sysconf(_SC_NPROCESSORS_ONLN);
20368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
20378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
20388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
20396697cff2155192a3e0c182a3cef046ebf215ac32plougher	thread = malloc((3 + processors) * sizeof(pthread_t));
20406697cff2155192a3e0c182a3cef046ebf215ac32plougher	if(thread == NULL)
20418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
2042eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	deflator_thread = &thread[3];
20438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2044cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	/*
2045cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * dimensioning the to_reader and to_deflate queues.  The size of
2046cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * these queues is directly related to the amount of block
2047cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * read-ahead possible.  To_reader queues block read requests to
2048cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * the reader thread and to_deflate queues block decompression
2049cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * requests to the deflate thread(s) (once the block has been read by
2050cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * the reader thread).  The amount of read-ahead is determined by
2051cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * the combined size of the data_block and fragment caches which
2052cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * determine the total number of blocks which can be "in flight"
2053cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * at any one time (either being read or being decompressed)
2054cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 *
2055cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * The maximum file open limit, however, affects the read-ahead
2056cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * possible, in that for normal sizes of the fragment and data block
2057cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * caches, where the incoming files have few data blocks or one fragment
2058cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * only, the file open limit is likely to be reached before the
2059cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * caches are full.  This means the worst case sizing of the combined
2060cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * sizes of the caches is unlikely to ever be necessary.  However, is is
2061cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * obvious read-ahead up to the data block cache size is always possible
2062cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * irrespective of the file open limit, because a single file could
2063cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * contain that number of blocks.
2064cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 *
2065cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * Choosing the size as "file open limit + data block cache size" seems
2066cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * to be a reasonable estimate.  We can reasonably assume the maximum
2067cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * likely read-ahead possible is data block cache size + one fragment
2068cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * per open file.
2069cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 *
2070cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * dimensioning the to_writer queue.  The size of this queue is
2071cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * directly related to the amount of block read-ahead possible.
2072cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * However, unlike the to_reader and to_deflate queues, this is
2073cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * complicated by the fact the to_writer queue not only contains
2074cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * entries for fragments and data_blocks but it also contains
2075cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * file entries, one per open file in the read-ahead.
2076cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 *
2077cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * Choosing the size as "2 * (file open limit) +
2078cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * data block cache size" seems to be a reasonable estimate.
2079cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * We can reasonably assume the maximum likely read-ahead possible
2080cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * is data block cache size + one fragment per open file, and then
2081cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * we will have a file_entry for each open file.
2082cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 */
2083cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	res = getrlimit(RLIMIT_NOFILE, &rlim);
2084cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	if (res == -1) {
2085cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		ERROR("failed to get open file limit!  Defaulting to 1\n");
2086cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		rlim.rlim_cur = 1;
2087cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	}
2088cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
2089cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	if (rlim.rlim_cur != RLIM_INFINITY) {
2090cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		/*
2091cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		 * leave OPEN_FILE_MARGIN free (rlim_cur includes fds used by
2092cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		 * stdin, stdout, stderr and filesystem fd
2093cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		 */
2094cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		if (rlim.rlim_cur <= OPEN_FILE_MARGIN)
2095cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher			/* no margin, use minimum possible */
2096cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher			max_files = 1;
2097cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		else
2098cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher			max_files = rlim.rlim_cur - OPEN_FILE_MARGIN;
2099cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	} else
2100cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		max_files = -1;
2101cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
2102cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	/* set amount of available files for use by open_wait and close_wake */
2103cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	open_init(max_files);
2104cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
2105cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	/*
2106cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * allocate to_reader, to_deflate and to_writer queues.  Set based on
2107cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * open file limit and cache size, unless open file limit is unlimited,
2108cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * in which case set purely based on cache limits
21092b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 *
21102b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * In doing so, check that the user supplied values do not overflow
21112b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * a signed int
2112cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 */
2113cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	if (max_files != -1) {
21142b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		if(add_overflow(data_buffer_size, max_files) ||
21152b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher				add_overflow(data_buffer_size, max_files * 2))
21162b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher			EXIT_UNSQUASH("Data queue size is too large\n");
21172b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
2118cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		to_reader = queue_init(max_files + data_buffer_size);
2119cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		to_deflate = queue_init(max_files + data_buffer_size);
2120cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		to_writer = queue_init(max_files * 2 + data_buffer_size);
2121cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	} else {
21222b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		int all_buffers_size;
21232b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
21242b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		if(add_overflow(fragment_buffer_size, data_buffer_size))
21252b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher			EXIT_UNSQUASH("Data and fragment queues combined are"
21262b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher							" too large\n");
21272b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
21282b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		all_buffers_size = fragment_buffer_size + data_buffer_size;
21292b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
21302b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		if(add_overflow(all_buffers_size, all_buffers_size))
21312b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher			EXIT_UNSQUASH("Data and fragment queues combined are"
21322b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher							" too large\n");
2133cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
2134cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		to_reader = queue_init(all_buffers_size);
2135cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		to_deflate = queue_init(all_buffers_size);
2136cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		to_writer = queue_init(all_buffers_size * 2);
2137cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	}
2138cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
21398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	from_writer = queue_init(1);
2140cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
21418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	fragment_cache = cache_init(block_size, fragment_buffer_size);
21428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data_cache = cache_init(block_size, data_buffer_size);
21438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[0], NULL, reader, NULL);
21448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[1], NULL, writer, NULL);
2145eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_create(&thread[2], NULL, progress_thread, NULL);
21468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&fragment_mutex, NULL);
21478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
21488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(i = 0; i < processors; i++) {
2149c435240f52b78b0ef498118727ba8dad186db26bplougher		if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) !=
2150c435240f52b78b0ef498118727ba8dad186db26bplougher				 0)
21518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("Failed to create thread\n");
21528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
21538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
21548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	printf("Parallel unsquashfs: Using %d processor%s\n", processors,
21558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors == 1 ? "" : "s");
21568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
21578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
2158c435240f52b78b0ef498118727ba8dad186db26bplougher		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads"
2159c435240f52b78b0ef498118727ba8dad186db26bplougher			"\n");
21608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
21618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
21628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
21631b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid enable_progress_bar()
21641b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
21651b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
21661b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_enabled = TRUE;
21671b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
21681b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
21691b42101056befe25b5f19d5b099e806a2ecee9cdplougher
21701b42101056befe25b5f19d5b099e806a2ecee9cdplougher
21711b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid disable_progress_bar()
21721b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
21731b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
21741b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_enabled = FALSE;
21751b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
21761b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
21771b42101056befe25b5f19d5b099e806a2ecee9cdplougher
21781b42101056befe25b5f19d5b099e806a2ecee9cdplougher
2179eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar()
2180eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
21811b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
2182eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_cond_signal(&progress_wait);
21831b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
2184eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
2185eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2186eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2187eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns)
2188eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
2189eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	char rotate_list[] = { '|', '/', '-', '\\' };
2190b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	int max_digits, used, hashes, spaces;
2191dce832998340bea4236fddb5ba1525121044ce18plougher	static int tty = -1;
2192eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2193b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	if(max == 0)
2194b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher		return;
2195b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher
2196b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	max_digits = floor(log10(max)) + 1;
2197b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	used = max_digits * 2 + 11;
2198b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	hashes = (current * (columns - used)) / max;
2199b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	spaces = columns - used - hashes;
2200b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher
2201eaf639366792995c36ae7295bddf534f6f416643plougher	if((current > max) || (columns - used < 0))
2202eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		return;
2203eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2204dce832998340bea4236fddb5ba1525121044ce18plougher	if(tty == -1)
2205dce832998340bea4236fddb5ba1525121044ce18plougher		tty = isatty(STDOUT_FILENO);
2206dce832998340bea4236fddb5ba1525121044ce18plougher	if(!tty) {
2207dce832998340bea4236fddb5ba1525121044ce18plougher		static long long previous = -1;
2208dce832998340bea4236fddb5ba1525121044ce18plougher
22090a0d045642e8e413f90b770539193d3fd1522786plougher		/*
22100a0d045642e8e413f90b770539193d3fd1522786plougher		 * Updating much more frequently than this results in huge
22110a0d045642e8e413f90b770539193d3fd1522786plougher		 * log files.
22120a0d045642e8e413f90b770539193d3fd1522786plougher		 */
2213dce832998340bea4236fddb5ba1525121044ce18plougher		if((current % 100) != 0 && current != max)
2214dce832998340bea4236fddb5ba1525121044ce18plougher			return;
2215dce832998340bea4236fddb5ba1525121044ce18plougher		/* Don't update just to rotate the spinner. */
2216dce832998340bea4236fddb5ba1525121044ce18plougher		if(current == previous)
2217dce832998340bea4236fddb5ba1525121044ce18plougher			return;
2218dce832998340bea4236fddb5ba1525121044ce18plougher		previous = current;
2219dce832998340bea4236fddb5ba1525121044ce18plougher	}
2220dce832998340bea4236fddb5ba1525121044ce18plougher
2221eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("\r[");
2222eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2223eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while (hashes --)
2224eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar('=');
2225eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2226eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	putchar(rotate_list[rotate]);
2227eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2228eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(spaces --)
2229eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar(' ');
2230eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2231eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("] %*lld/%*lld", max_digits, current, max_digits, max);
2232eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf(" %3lld%%", current * 100 / max);
2233eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	fflush(stdout);
2234eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
2235eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2236eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
22372b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougherint parse_number(char *arg, int *res)
22382b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher{
22392b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	char *b;
22402b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	long number = strtol(arg, &b, 10);
22412b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
22422b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	/* check for trailing junk after number */
22432b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(*b != '\0')
22442b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		return 0;
22452b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
22467f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	/*
22477f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 * check for strtol underflow or overflow in conversion.
22487f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 * Note: strtol can validly return LONG_MIN and LONG_MAX
22497f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 * if the user entered these values, but, additional code
22507f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 * to distinguish this scenario is unnecessary, because for
22517f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 * our purposes LONG_MIN and LONG_MAX are too large anyway
22527f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 */
22532b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(number == LONG_MIN || number == LONG_MAX)
22542b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		return 0;
22552b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
22562b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	/* reject negative numbers as invalid */
22572b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(number < 0)
22582b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		return 0;
22592b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
22602b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	/* check if long result will overflow signed int */
22612b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(number > INT_MAX)
22622b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		return 0;
22632b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
22642b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	*res = number;
22652b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	return 1;
22662b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher}
22672b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
22682b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
2269443c15812032991c98b33b5424b17bcd55fe3575plougher#define VERSION() \
227009b269ae68dcc1ce96b8d17cf8a09a2b0dfcbf2aPhillip Lougher	printf("unsquashfs version 4.2-git (2012/12/21)\n");\
22710ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher	printf("copyright (C) 2012 Phillip Lougher "\
227283d42a3fc898962aa1f1e8387f2ccb1114e0d294Phillip Lougher		"<phillip@squashfs.org.uk>\n\n");\
2273e3206fad5b70e7e0527db2a627ad26616a8a2429plougher    	printf("This program is free software; you can redistribute it and/or"\
2274d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
2275e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("modify it under the terms of the GNU General Public License"\
2276d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
2277e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("as published by the Free Software Foundation; either version "\
2278e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		"2,\n");\
2279e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("or (at your option) any later version.\n\n");\
2280e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("This program is distributed in the hope that it will be "\
2281e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		"useful,\n");\
2282d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of"\
2283d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
2284d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the"\
2285d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
2286443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("GNU General Public License for more details.\n");
2287443c15812032991c98b33b5424b17bcd55fe3575plougherint main(int argc, char *argv[])
2288443c15812032991c98b33b5424b17bcd55fe3575plougher{
2289443c15812032991c98b33b5424b17bcd55fe3575plougher	char *dest = "squashfs-root";
2290b624936abba03d38b7e9245c647339d8f6f34274plougher	int i, stat_sys = FALSE, version = FALSE;
2291545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	int n;
2292a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *paths = NULL;
2293a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathname *path = NULL;
2294ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int fragment_buffer_size = FRAGMENT_BUFFER_DEFAULT;
2295ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int data_buffer_size = DATA_BUFFER_DEFAULT;
2296443c15812032991c98b33b5424b17bcd55fe3575plougher
22971b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_init(&screen_mutex, NULL);
2298545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	root_process = geteuid() == 0;
2299545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	if(root_process)
23009dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		umask(0);
23019dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
2302443c15812032991c98b33b5424b17bcd55fe3575plougher	for(i = 1; i < argc; i++) {
2303443c15812032991c98b33b5424b17bcd55fe3575plougher		if(*argv[i] != '-')
2304443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
2305d4204758f77acb5a371fa1487a755b76a05d5476plougher		if(strcmp(argv[i], "-version") == 0 ||
2306d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-v") == 0) {
2307443c15812032991c98b33b5424b17bcd55fe3575plougher			VERSION();
2308443c15812032991c98b33b5424b17bcd55fe3575plougher			version = TRUE;
2309d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-info") == 0 ||
2310d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-i") == 0)
2311443c15812032991c98b33b5424b17bcd55fe3575plougher			info = TRUE;
2312c435240f52b78b0ef498118727ba8dad186db26bplougher		else if(strcmp(argv[i], "-ls") == 0 ||
2313c435240f52b78b0ef498118727ba8dad186db26bplougher				strcmp(argv[i], "-l") == 0)
2314443c15812032991c98b33b5424b17bcd55fe3575plougher			lsonly = TRUE;
2315d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-no-progress") == 0 ||
2316d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-n") == 0)
2317296d7d8a68e33341d68f4354b5e1fe2f3aa275a6plougher			progress = FALSE;
231831638061a6de0cb89093672aa71ddeb42f2eb28aplougher		else if(strcmp(argv[i], "-no-xattrs") == 0 ||
231931638061a6de0cb89093672aa71ddeb42f2eb28aplougher				strcmp(argv[i], "-no") == 0)
232031638061a6de0cb89093672aa71ddeb42f2eb28aplougher			no_xattrs = TRUE;
2321df9d38a515489c2c573754ad81abd230dfd8b1f0plougher		else if(strcmp(argv[i], "-xattrs") == 0 ||
2322df9d38a515489c2c573754ad81abd230dfd8b1f0plougher				strcmp(argv[i], "-x") == 0)
2323df9d38a515489c2c573754ad81abd230dfd8b1f0plougher			no_xattrs = FALSE;
2324d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-dest") == 0 ||
2325d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-d") == 0) {
232671add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
2327d4204758f77acb5a371fa1487a755b76a05d5476plougher				fprintf(stderr, "%s: -dest missing filename\n",
2328d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
232971add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
233071add234b27054974d5e29f95b3fab3072792a62plougher			}
2331443c15812032991c98b33b5424b17bcd55fe3575plougher			dest = argv[i];
2332d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-processors") == 0 ||
2333d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-p") == 0) {
2334c435240f52b78b0ef498118727ba8dad186db26bplougher			if((++i == argc) ||
23352c7ffbdfb7ef17a2032864e074a43d00631eeb8ePhillip Lougher					!parse_number(argv[i],
23362c7ffbdfb7ef17a2032864e074a43d00631eeb8ePhillip Lougher						&processors)) {
2337d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -processors missing or invalid "
2338d4204758f77acb5a371fa1487a755b76a05d5476plougher					"processor number\n", argv[0]);
23390cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
23400cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
23410cf5c297bec42c7c220d2825f12f9499f2293279plougher			if(processors < 1) {
2342d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -processors should be 1 or larger\n",
2343d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
23440cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
23450cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
2346d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-data-queue") == 0 ||
2347d4204758f77acb5a371fa1487a755b76a05d5476plougher					 strcmp(argv[i], "-da") == 0) {
2348c435240f52b78b0ef498118727ba8dad186db26bplougher			if((++i == argc) ||
23492b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher					!parse_number(argv[i],
23502b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher						&data_buffer_size)) {
2351c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("%s: -data-queue missing or invalid "
2352c435240f52b78b0ef498118727ba8dad186db26bplougher					"queue size\n", argv[0]);
2353ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2354ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2355ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(data_buffer_size < 1) {
2356d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -data-queue should be 1 Mbyte or "
2357d4204758f77acb5a371fa1487a755b76a05d5476plougher					"larger\n", argv[0]);
2358ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2359ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2360d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-frag-queue") == 0 ||
2361d4204758f77acb5a371fa1487a755b76a05d5476plougher					strcmp(argv[i], "-fr") == 0) {
2362c435240f52b78b0ef498118727ba8dad186db26bplougher			if((++i == argc) ||
23632b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher					!parse_number(argv[i],
23642b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher						&fragment_buffer_size)) {
2365c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("%s: -frag-queue missing or invalid "
2366c435240f52b78b0ef498118727ba8dad186db26bplougher					"queue size\n", argv[0]);
2367ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2368ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2369ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(fragment_buffer_size < 1) {
2370d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -frag-queue should be 1 Mbyte or "
2371d4204758f77acb5a371fa1487a755b76a05d5476plougher					"larger\n", argv[0]);
2372ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2373ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2374d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-force") == 0 ||
2375d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-f") == 0)
2376a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			force = TRUE;
2377d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-stat") == 0 ||
2378d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-s") == 0)
2379b624936abba03d38b7e9245c647339d8f6f34274plougher			stat_sys = TRUE;
2380d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-lls") == 0 ||
2381d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-ll") == 0) {
23829baf35a00f38816d2054deb70184943d0686d03eplougher			lsonly = TRUE;
23839baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
2384d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-linfo") == 0 ||
2385d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-li") == 0) {
23869baf35a00f38816d2054deb70184943d0686d03eplougher			info = TRUE;
23879baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
2388d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-ef") == 0 ||
2389d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-e") == 0) {
239071add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
2391d4204758f77acb5a371fa1487a755b76a05d5476plougher				fprintf(stderr, "%s: -ef missing filename\n",
2392d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
239371add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
239471add234b27054974d5e29f95b3fab3072792a62plougher			}
2395a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			path = process_extract_files(path, argv[i]);
2396d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-regex") == 0 ||
2397d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-r") == 0)
23984dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			use_regex = TRUE;
23994dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		else
2400b624936abba03d38b7e9245c647339d8f6f34274plougher			goto options;
2401443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2402443c15812032991c98b33b5424b17bcd55fe3575plougher
2403feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher	if(lsonly || info)
2404feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher		progress = FALSE;
2405feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher
2406bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher#ifdef SQUASHFS_TRACE
2407bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher	progress = FALSE;
2408bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher#endif
2409bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher
2410443c15812032991c98b33b5424b17bcd55fe3575plougher	if(i == argc) {
2411443c15812032991c98b33b5424b17bcd55fe3575plougher		if(!version) {
2412443c15812032991c98b33b5424b17bcd55fe3575plougheroptions:
2413d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("SYNTAX: %s [options] filesystem [directories or "
2414d4204758f77acb5a371fa1487a755b76a05d5476plougher				"files to extract]\n", argv[0]);
2415d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-v[ersion]\t\tprint version, licence and "
2416d4204758f77acb5a371fa1487a755b76a05d5476plougher				"copyright information\n");
2417d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-d[est] <pathname>\tunsquash to <pathname>, "
2418d4204758f77acb5a371fa1487a755b76a05d5476plougher				"default \"squashfs-root\"\n");
2419c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-n[o-progress]\t\tdon't display the progress "
2420c435240f52b78b0ef498118727ba8dad186db26bplougher				"bar\n");
2421df9d38a515489c2c573754ad81abd230dfd8b1f0plougher			ERROR("\t-no[-xattrs]\t\tdon't extract xattrs in file system"
2422df9d38a515489c2c573754ad81abd230dfd8b1f0plougher				NOXOPT_STR"\n");
2423df9d38a515489c2c573754ad81abd230dfd8b1f0plougher			ERROR("\t-x[attrs]\t\textract xattrs in file system"
2424df9d38a515489c2c573754ad81abd230dfd8b1f0plougher				XOPT_STR "\n");
2425c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-p[rocessors] <number>\tuse <number> "
2426c435240f52b78b0ef498118727ba8dad186db26bplougher				"processors.  By default will use\n");
2427c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\tnumber of processors available\n");
2428c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-i[nfo]\t\t\tprint files as they are "
2429c435240f52b78b0ef498118727ba8dad186db26bplougher				"unsquashed\n");
2430c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-li[nfo]\t\tprint files as they are "
2431c435240f52b78b0ef498118727ba8dad186db26bplougher				"unsquashed with file\n");
2432c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\tattributes (like ls -l output)\n");
2433d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-l[s]\t\t\tlist filesystem, but don't unsquash"
2434d4204758f77acb5a371fa1487a755b76a05d5476plougher				"\n");
2435c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-ll[s]\t\t\tlist filesystem with file "
2436c435240f52b78b0ef498118727ba8dad186db26bplougher				"attributes (like\n");
2437c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\tls -l output), but don't unsquash\n");
2438c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-f[orce]\t\tif file already exists then "
2439c435240f52b78b0ef498118727ba8dad186db26bplougher				"overwrite\n");
2440d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-s[tat]\t\t\tdisplay filesystem superblock "
2441d4204758f77acb5a371fa1487a755b76a05d5476plougher				"information\n");
2442d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-e[f] <extract file>\tlist of directories or "
2443d4204758f77acb5a371fa1487a755b76a05d5476plougher				"files to extract.\n\t\t\t\tOne per line\n");
2444c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-da[ta-queue] <size>\tSet data queue to "
2445c435240f52b78b0ef498118727ba8dad186db26bplougher				"<size> Mbytes.  Default %d\n\t\t\t\tMbytes\n",
2446d4204758f77acb5a371fa1487a755b76a05d5476plougher				DATA_BUFFER_DEFAULT);
24478bc376ba1f7110fb88989e5134b74aa8412fb00eplougher			ERROR("\t-fr[ag-queue] <size>\tSet fragment queue to "
2448d56f6723626a391b473c2c023b628abcd8ed31e3Phillip Lougher				"<size> Mbytes.  Default\n\t\t\t\t%d Mbytes\n",
2449d4204758f77acb5a371fa1487a755b76a05d5476plougher				FRAGMENT_BUFFER_DEFAULT);
2450c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-r[egex]\t\ttreat extract names as POSIX "
2451c435240f52b78b0ef498118727ba8dad186db26bplougher				"regular expressions\n");
2452c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\trather than use the default shell "
2453c435240f52b78b0ef498118727ba8dad186db26bplougher				"wildcard\n\t\t\t\texpansion (globbing)\n");
2454076b053e2cce5c9172b4f385e866c2e606712a32plougher			ERROR("\nDecompressors available:\n");
2455076b053e2cce5c9172b4f385e866c2e606712a32plougher			display_compressors("", "");
2456443c15812032991c98b33b5424b17bcd55fe3575plougher		}
2457443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2458443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2459443c15812032991c98b33b5424b17bcd55fe3575plougher
246071add234b27054974d5e29f95b3fab3072792a62plougher	for(n = i + 1; n < argc; n++)
2461a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, argv[n], argv[n]);
2462b54566f5c433764830c29c83151691d0034de094plougher
2463443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fd = open(argv[i], O_RDONLY)) == -1) {
2464d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("Could not open %s, because %s\n", argv[i],
2465d4204758f77acb5a371fa1487a755b76a05d5476plougher			strerror(errno));
2466443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2467443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2468443c15812032991c98b33b5424b17bcd55fe3575plougher
246902bc3bcabf2b219f63961f07293b83629948f026plougher	if(read_super(argv[i]) == FALSE)
2470443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2471443c15812032991c98b33b5424b17bcd55fe3575plougher
2472b624936abba03d38b7e9245c647339d8f6f34274plougher	if(stat_sys) {
2473b624936abba03d38b7e9245c647339d8f6f34274plougher		squashfs_stat(argv[i]);
2474b624936abba03d38b7e9245c647339d8f6f34274plougher		exit(0);
2475b624936abba03d38b7e9245c647339d8f6f34274plougher	}
2476b624936abba03d38b7e9245c647339d8f6f34274plougher
2477f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher	if(!comp->supported) {
2478f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher		ERROR("Filesystem uses %s compression, this is "
2479f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher			"unsupported by this version\n", comp->name);
2480f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher		ERROR("Decompressors available:\n");
2481f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher		display_compressors("", "");
2482f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher		exit(1);
2483f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher	}
2484f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher
248527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	block_size = sBlk.s.block_size;
248627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	block_log = sBlk.s.block_log;
2487ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2488009263430d50ee32f3757c3c34d1f06262759f5dPhillip Lougher	/*
24892b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * Sanity check block size and block log.
24902b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 *
24912b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * Check they're within correct limits
24922b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 */
24932b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(block_size > SQUASHFS_FILE_MAX_SIZE ||
24942b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher					block_log > SQUASHFS_FILE_MAX_LOG)
24952b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		EXIT_UNSQUASH("Block size or block_log too large."
24962b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher			"  File system is corrupt.\n");
24972b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
24982b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	/*
24992b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * Check block_size and block_log match
25002b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 */
25012b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(block_size != (1 << block_log))
25022b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		EXIT_UNSQUASH("Block size and block_log do not match."
25032b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher			"  File system is corrupt.\n");
25042b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
25052b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	/*
2506009263430d50ee32f3757c3c34d1f06262759f5dPhillip Lougher	 * convert from queue size in Mbytes to queue size in
25072b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * blocks.
25082b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 *
25092b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * In doing so, check that the user supplied values do not
25102b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * overflow a signed int
2511009263430d50ee32f3757c3c34d1f06262759f5dPhillip Lougher	 */
25122b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(shift_overflow(fragment_buffer_size, 20 - block_log))
25132b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		EXIT_UNSQUASH("Fragment queue size is too large\n");
25142b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	else
25152b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		fragment_buffer_size <<= 20 - block_log;
25162b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
25172b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(shift_overflow(data_buffer_size, 20 - block_log))
25182b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		EXIT_UNSQUASH("Data queue size is too large\n");
25192b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	else
25202b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		data_buffer_size <<= 20 - block_log;
25212b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
25228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	initialise_threads(fragment_buffer_size, data_buffer_size);
25238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
252444a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	fragment_data = malloc(block_size);
252544a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(fragment_data == NULL)
2526443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate fragment_data\n");
2527443c15812032991c98b33b5424b17bcd55fe3575plougher
252844a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	file_data = malloc(block_size);
252944a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(file_data == NULL)
2530443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate file_data");
2531443c15812032991c98b33b5424b17bcd55fe3575plougher
253244a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	data = malloc(block_size);
253344a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(data == NULL)
2534eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		EXIT_UNSQUASH("failed to allocate data\n");
2535443c15812032991c98b33b5424b17bcd55fe3575plougher
253644a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	created_inode = malloc(sBlk.s.inodes * sizeof(char *));
253744a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(created_inode == NULL)
2538443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate created_inode\n");
2539443c15812032991c98b33b5424b17bcd55fe3575plougher
254027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	memset(created_inode, 0, sBlk.s.inodes * sizeof(char *));
2541443c15812032991c98b33b5424b17bcd55fe3575plougher
25421a7e7e871169a6cb6e3470a50b33db83830886e2plougher	if(s_ops.read_uids_guids() == FALSE)
25431a7e7e871169a6cb6e3470a50b33db83830886e2plougher		EXIT_UNSQUASH("failed to uid/gid table\n");
2544ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2545cce13b2f8f73a4224f9dcfe203c992a09f22c6bcplougher	if(s_ops.read_fragment_table() == FALSE)
2546cce13b2f8f73a4224f9dcfe203c992a09f22c6bcplougher		EXIT_UNSQUASH("failed to read fragment table\n");
2547ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
254827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	uncompress_inode_table(sBlk.s.inode_table_start,
254927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.directory_table_start);
2550ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
255127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	uncompress_directory_table(sBlk.s.directory_table_start,
255227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.fragment_table_start);
2553443c15812032991c98b33b5424b17bcd55fe3575plougher
255431638061a6de0cb89093672aa71ddeb42f2eb28aplougher	if(no_xattrs)
255531638061a6de0cb89093672aa71ddeb42f2eb28aplougher		sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK;
255631638061a6de0cb89093672aa71ddeb42f2eb28aplougher
25578935dc25479321709c74c2f8214cf5365669100eplougher	if(read_xattrs_from_disk(fd, &sBlk.s) == 0)
25588935dc25479321709c74c2f8214cf5365669100eplougher		EXIT_UNSQUASH("failed to read the xattr table\n");
25598935dc25479321709c74c2f8214cf5365669100eplougher
2560a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if(path) {
2561a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = init_subdir();
2562a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = add_subdir(paths, path);
2563a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
2564a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
256527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	pre_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode),
256627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths);
2567eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
256827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	memset(created_inode, 0, sBlk.s.inodes * sizeof(char *));
25699b58176e667b67770569c9076a410b27aaa3bcf5plougher	inode_number = 1;
2570eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2571c435240f52b78b0ef498118727ba8dad186db26bplougher	printf("%d inodes (%d blocks) to write\n\n", total_inodes,
2572c435240f52b78b0ef498118727ba8dad186db26bplougher		total_inodes - total_files + total_blocks);
2573eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
25741b42101056befe25b5f19d5b099e806a2ecee9cdplougher	if(progress)
25751b42101056befe25b5f19d5b099e806a2ecee9cdplougher		enable_progress_bar();
25761b42101056befe25b5f19d5b099e806a2ecee9cdplougher
257727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode),
257827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths);
2579443c15812032991c98b33b5424b17bcd55fe3575plougher
25808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_put(to_writer, NULL);
25818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_get(from_writer);
25828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
25835c7885bc293ab675812fd77a05f59c2917e3e8b4plougher	if(progress) {
25841b42101056befe25b5f19d5b099e806a2ecee9cdplougher		disable_progress_bar();
25855c7885bc293ab675812fd77a05f59c2917e3e8b4plougher		progress_bar(sym_count + dev_count + fifo_count + cur_blocks,
25861b42101056befe25b5f19d5b099e806a2ecee9cdplougher			total_inodes - total_files + total_blocks, columns);
25875c7885bc293ab675812fd77a05f59c2917e3e8b4plougher	}
2588eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2589443c15812032991c98b33b5424b17bcd55fe3575plougher	if(!lsonly) {
2590443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("\n");
2591443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d files\n", file_count);
2592443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d directories\n", dir_count);
2593443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d symlinks\n", sym_count);
2594443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d devices\n", dev_count);
2595443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d fifos\n", fifo_count);
2596443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2597eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
25989dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	return 0;
2599443c15812032991c98b33b5424b17bcd55fe3575plougher}
2600