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,
6cc06495ccafaf9bb7f3d078dee22f2e3b1af471cPhillip Lougher * 2012, 2013, 2014
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"
29efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher#include "compressor.h"
302ef25cb004cc6995bd36f781863aa844fe8c358dplougher#include "xattr.h"
31fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher#include "unsquashfs_info.h"
320100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher#include "stdarg.h"
338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
34cdebd2b8ae4b1ac39eefb5f0c556f0d2e3dc3d24plougher#include <sys/sysinfo.h>
352ef25cb004cc6995bd36f781863aa844fe8c358dplougher#include <sys/types.h>
36cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher#include <sys/time.h>
37cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher#include <sys/resource.h>
382b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher#include <limits.h>
39e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher#include <ctype.h>
40cdebd2b8ae4b1ac39eefb5f0c556f0d2e3dc3d24plougher
418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *fragment_cache, *data_cache;
42bee9e37353d957d1c4d8669ca4eba30c2b9df3f5Phillip Lougherstruct queue *to_reader, *to_inflate, *to_writer, *from_writer;
433327bd9640ed579e8022b0e3889f71c342a64193Phillip Lougherpthread_t *thread, *inflator_thread;
448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherpthread_mutex_t	fragment_mutex;
458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* user options that control parallelisation */
478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherint processors = -1;
488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
496490378e5b5e8dc058daf28423a7465699a6ba7bplougherstruct super_block sBlk;
5002bc3bcabf2b219f63961f07293b83629948f026ploughersquashfs_operations s_ops;
51efda88fd6fbb19543a86b5f8d15b437bba8c4674plougherstruct compressor *comp;
5202bc3bcabf2b219f63961f07293b83629948f026plougher
539dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0,
549dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	dev_count = 0, fifo_count = 0;
55443c15812032991c98b33b5424b17bcd55fe3575plougherchar *inode_table = NULL, *directory_table = NULL;
56443c15812032991c98b33b5424b17bcd55fe3575plougherstruct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536];
57443c15812032991c98b33b5424b17bcd55fe3575plougherint fd;
58443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int *uid_table, *guid_table;
59443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int cached_frag = SQUASHFS_INVALID_FRAG;
60443c15812032991c98b33b5424b17bcd55fe3575plougherchar *fragment_data;
61443c15812032991c98b33b5424b17bcd55fe3575plougherchar *file_data;
62443c15812032991c98b33b5424b17bcd55fe3575plougherchar *data;
63443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int block_size;
64ae271cc93e3684d5314bcdc45b631e497ae43166plougherunsigned int block_log;
65d4204758f77acb5a371fa1487a755b76a05d5476plougherint lsonly = FALSE, info = FALSE, force = FALSE, short_ls = TRUE;
66d4204758f77acb5a371fa1487a755b76a05d5476plougherint use_regex = FALSE;
67443c15812032991c98b33b5424b17bcd55fe3575plougherchar **created_inode;
689dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint root_process;
69eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint columns;
70eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint rotate = 0;
711b42101056befe25b5f19d5b099e806a2ecee9cdplougherpthread_mutex_t	screen_mutex;
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;
77498da46ad7e6bd0a1fac0ec81d85ce1ac56bf385Phillip Lougherint user_xattrs = FALSE;
78443c15812032991c98b33b5424b17bcd55fe3575plougher
79476dcb48b24efff22caa970f000e151f1b28918dplougherint lookup_type[] = {
80476dcb48b24efff22caa970f000e151f1b28918dplougher	0,
81476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
82476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFREG,
83476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFLNK,
84476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFBLK,
85476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFCHR,
86476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFIFO,
87476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFSOCK,
88476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
89eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFREG,
90eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFLNK,
91eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFBLK,
92eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFCHR,
93eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFIFO,
94eabe4dbeaec52acc95278663d7a13da7384ef9baplougher	S_IFSOCK
95476dcb48b24efff22caa970f000e151f1b28918dplougher};
96476dcb48b24efff22caa970f000e151f1b28918dplougher
97476dcb48b24efff22caa970f000e151f1b28918dplougherstruct test table[] = {
98476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFSOCK, 0, 's' },
99476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFLNK, 0, 'l' },
100476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFBLK, 0, 'b' },
101476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFDIR, 0, 'd' },
102476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFCHR, 0, 'c' },
103476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFIFO, 0, 'p' },
104476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRUSR, S_IRUSR, 1, 'r' },
105476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWUSR, S_IWUSR, 2, 'w' },
106476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRGRP, S_IRGRP, 4, 'r' },
107476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWGRP, S_IWGRP, 5, 'w' },
108476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IROTH, S_IROTH, 7, 'r' },
109476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWOTH, S_IWOTH, 8, 'w' },
110476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR | S_ISUID, 3, 's' },
111476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_ISUID, 3, 'S' },
112476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR, 3, 'x' },
113476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP | S_ISGID, 6, 's' },
114476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_ISGID, 6, 'S' },
115476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP, 6, 'x' },
116476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH | S_ISVTX, 9, 't' },
117476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_ISVTX, 9, 'T' },
118476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH, 9, 'x' },
1198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	{ 0, 0, 0, 0}
1208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher};
1218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
122eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns);
123eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
124afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher#define MAX_LINE 16384
125afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher
1260100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Loughervoid prep_exit()
1270100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher{
1280100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher}
1290100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
1300100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
131eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid sigwinch_handler()
132eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
133eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct winsize winsize;
134eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
135eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
136c27a3d72b339d80d38623a4ee5a42601338fb4c9plougher		if(isatty(STDOUT_FILENO))
137d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
138d4204758f77acb5a371fa1487a755b76a05d5476plougher				"columns\n");
139eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = 80;
140eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	} else
141eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = winsize.ws_col;
142eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
143eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1451b5f6c5145f284683a2628b73ab5f8a0e37dd7b4ploughervoid sigalrm_handler()
1461b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher{
1471b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	rotate = (rotate + 1) % 4;
1481b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher}
1491b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
1501b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
1512b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougherint add_overflow(int a, int b)
1522b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher{
1532b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	return (INT_MAX - a) < b;
1542b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher}
1552b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1562b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1572b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougherint shift_overflow(int a, int shift)
1582b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher{
1592b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	return (INT_MAX >> shift) < a;
1602b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher}
1612b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1622b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1632b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougherint multiply_overflow(int a, int multiplier)
1642b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher{
1652b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	return (INT_MAX / multiplier) < a;
1662b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher}
1672b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1682b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *queue_init(int size)
1708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct queue *queue = malloc(sizeof(struct queue));
1728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(queue == NULL)
17462b2d7649ad84234afd928a43f9a2c1612eef361plougher		EXIT_UNSQUASH("Out of memory in queue_init\n");
1758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1762b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(add_overflow(size, 1) ||
1772b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher				multiply_overflow(size + 1, sizeof(void *)))
1782b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		EXIT_UNSQUASH("Size too large in queue_init\n");
1792b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
1807b53be8c83b949517c343d9c6d88243578753c3aplougher	queue->data = malloc(sizeof(void *) * (size + 1));
1817b53be8c83b949517c343d9c6d88243578753c3aplougher	if(queue->data == NULL)
1820e0cc6f6dccdc5460c292b0a5accc1184a07f3f5plougher		EXIT_UNSQUASH("Out of memory in queue_init\n");
1838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->size = size + 1;
1858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = queue->writep = 0;
1868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&queue->mutex, NULL);
1878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->empty, NULL);
1888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->full, NULL);
1898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return queue;
1918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
1928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1948888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid queue_put(struct queue *queue, void *data)
1958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
1968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int nextp;
1978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
1998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
2018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->full, &queue->mutex);
2028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->data[queue->writep] = data;
2048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->writep = nextp;
2058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->empty);
2068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
2078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2108888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *queue_get(struct queue *queue)
2118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	void *data;
2138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
2148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(queue->readp == queue->writep)
2168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->empty, &queue->mutex);
2178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data = queue->data[queue->readp];
2198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = (queue->readp + 1) % queue->size;
2208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->full);
2218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
2228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return data;
2248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
227acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Loughervoid dump_queue(struct queue *queue)
228acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher{
229acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher	pthread_mutex_lock(&queue->mutex);
230acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher
231acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher	printf("Max size %d, size %d%s\n", queue->size - 1,
232acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher		queue->readp <= queue->writep ? queue->writep - queue->readp :
233acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher			queue->size - queue->readp + queue->writep,
234acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher		queue->readp == queue->writep ? " (EMPTY)" :
235acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher			((queue->writep + 1) % queue->size) == queue->readp ?
236acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher			" (FULL)" : "");
237acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher
238acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher	pthread_mutex_unlock(&queue->mutex);
239acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher}
240acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher
241acabfdbb5244ddc04c2d372e20b79fccdafb5cbePhillip Lougher
2428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2438888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_hash_table(struct cache *cache, struct cache_entry *entry)
2448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(entry->block);
2468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_next = cache->hash_table[hash];
2488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->hash_table[hash] = entry;
2498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = NULL;
2508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
2518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry;
2528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2568888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_hash_table(struct cache *cache, struct cache_entry *entry)
2578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_prev)
2598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_prev->hash_next = entry->hash_next;
2608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	else
261c435240f52b78b0ef498118727ba8dad186db26bplougher		cache->hash_table[CALCULATE_HASH(entry->block)] =
262c435240f52b78b0ef498118727ba8dad186db26bplougher			entry->hash_next;
2638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
2648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry->hash_prev;
2658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = entry->hash_next = NULL;
2678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2718888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_free_list(struct cache *cache, struct cache_entry *entry)
2728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache->free_list) {
2748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next = cache->free_list;
2758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = cache->free_list->free_prev;
2768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev->free_next = entry;
2778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev = entry;
2788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
2798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = entry;
2808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = entry->free_next = entry;
2818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
2828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
2868888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_free_list(struct cache *cache, struct cache_entry *entry)
2878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
28856b6f5f361fe521ce75a7c189724a84987cd3d13Phillip Lougher	if(entry->free_prev == NULL || entry->free_next == NULL)
2898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* not in free list */
2908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return;
291222e49e257bccb10c0e608f071778f26fce28f01plougher	else if(entry->free_prev == entry && entry->free_next == entry) {
2928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* only this entry in the free list */
2938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = NULL;
2948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
2958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* more than one entry in the free list */
2968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next->free_prev = entry->free_prev;
2978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev->free_next = entry->free_next;
2988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->free_list == entry)
2998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->free_list = entry->free_next;
3008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->free_prev = entry->free_next = NULL;
3038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *cache_init(int buffer_size, int max_buffers)
3078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
3088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache *cache = malloc(sizeof(struct cache));
3098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache == NULL)
311360570574b8f7786728d91d5fe4a0a4aa291fa03plougher		EXIT_UNSQUASH("Out of memory in cache_init\n");
3128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->max_buffers = max_buffers;
3148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->buffer_size = buffer_size;
3158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->count = 0;
3166b336d83d3546674593f7de3be86d174f32fd753Phillip Lougher	cache->used = 0;
3178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->free_list = NULL;
3188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536);
3198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_free = FALSE;
3208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_pending = FALSE;
3218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&cache->mutex, NULL);
3228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_free, NULL);
3238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_pending, NULL);
3248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return cache;
3268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache_entry *cache_get(struct cache *cache, long long block, int size)
3308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
331d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
332d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * Get a block out of the cache.  If the block isn't in the cache
3333327bd9640ed579e8022b0e3889f71c342a64193Phillip Lougher 	 * it is added and queued to the reader() and inflate() threads for
334c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * reading off disk and decompression.  The cache grows until max_blocks
335c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * is reached, once this occurs existing discarded blocks on the free
336c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * list are reused
337d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
3388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(block);
3398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *entry;
3408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&cache->mutex);
3428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
3448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->block == block)
3458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			break;
3468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry) {
348d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
349b55ce2730ff8cda018d8d18e64c9cbda433593afPhillip Lougher 		 * found the block in the cache.  If the block is currently unused
350b55ce2730ff8cda018d8d18e64c9cbda433593afPhillip Lougher		 * remove it from the free list and increment cache used count.
3518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
352b55ce2730ff8cda018d8d18e64c9cbda433593afPhillip Lougher		if(entry->used == 0) {
353b55ce2730ff8cda018d8d18e64c9cbda433593afPhillip Lougher			cache->used ++;
354b55ce2730ff8cda018d8d18e64c9cbda433593afPhillip Lougher			remove_free_list(cache, entry);
355b55ce2730ff8cda018d8d18e64c9cbda433593afPhillip Lougher		}
3568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used ++;
3578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
3588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
359d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
360d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 * not in the cache
361d4204758f77acb5a371fa1487a755b76a05d5476plougher		 *
362d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * first try to allocate new block
363d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
3648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->count < cache->max_buffers) {
3658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = malloc(sizeof(struct cache_entry));
3668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(entry == NULL)
3677227416360c2f249a0783dffef6725ad03b61c99plougher				EXIT_UNSQUASH("Out of memory in cache_get\n");
3688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data = malloc(cache->buffer_size);
3697227416360c2f249a0783dffef6725ad03b61c99plougher			if(entry->data == NULL)
3707227416360c2f249a0783dffef6725ad03b61c99plougher				EXIT_UNSQUASH("Out of memory in cache_get\n");
3718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache = cache;
3728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->free_prev = entry->free_next = NULL;
3738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->count ++;
3748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		} else {
375d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
376d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * try to get from free list
377d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
3788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			while(cache->free_list == NULL) {
3798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				cache->wait_free = TRUE;
380d4204758f77acb5a371fa1487a755b76a05d5476plougher				pthread_cond_wait(&cache->wait_for_free,
381d4204758f77acb5a371fa1487a755b76a05d5476plougher					&cache->mutex);
3828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
3838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = cache->free_list;
3848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_free_list(cache, entry);
3858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_hash_table(cache, entry);
3868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
3878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
388d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
3896b336d83d3546674593f7de3be86d174f32fd753Phillip Lougher		 * Initialise block and insert into the hash table.
3906b336d83d3546674593f7de3be86d174f32fd753Phillip Lougher		 * Increment used which tracks how many buffers in the
3916b336d83d3546674593f7de3be86d174f32fd753Phillip Lougher		 * cache are actively in use (the other blocks, count - used,
3926b336d83d3546674593f7de3be86d174f32fd753Phillip Lougher		 * are in the cache and available for lookup, but can also be
3936b336d83d3546674593f7de3be86d174f32fd753Phillip Lougher		 * re-used).
394d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
3958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->block = block;
3968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->size = size;
3978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used = 1;
3988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->error = FALSE;
3998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->pending = TRUE;
4008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_hash_table(cache, entry);
4016b336d83d3546674593f7de3be86d174f32fd753Phillip Lougher		cache->used ++;
4028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
403d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
404c435240f52b78b0ef498118727ba8dad186db26bplougher		 * queue to read thread to read and ultimately (via the
405c435240f52b78b0ef498118727ba8dad186db26bplougher		 * decompress threads) decompress the buffer
4068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
4078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
4088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_reader, entry);
4098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
4108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return entry;
4128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
4138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4158888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_ready(struct cache_entry *entry, int error)
4168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
417d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
418d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * mark cache entry as being complete, reading and (if necessary)
4198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * decompression has taken place, and the buffer is valid for use.
4208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * If an error occurs reading or decompressing, the buffer also
421d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 * becomes ready but with an error...
422d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
4238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
4248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->pending = FALSE;
4258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->error = error;
4268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
427d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
428c435240f52b78b0ef498118727ba8dad186db26bplougher	 * if the wait_pending flag is set, one or more threads may be waiting
429c435240f52b78b0ef498118727ba8dad186db26bplougher	 * on this buffer
430d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
4318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->cache->wait_pending) {
4328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = FALSE;
4338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_broadcast(&entry->cache->wait_for_pending);
4348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
4358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
4378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
4388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4408888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_wait(struct cache_entry *entry)
4418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
442d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
443d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * wait for this cache entry to become ready, when reading and (if
444d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * necessary) decompression has taken place
445d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
4468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
4478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(entry->pending) {
4498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = TRUE;
450d4204758f77acb5a371fa1487a755b76a05d5476plougher		pthread_cond_wait(&entry->cache->wait_for_pending,
451d4204758f77acb5a371fa1487a755b76a05d5476plougher			&entry->cache->mutex);
4528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
4538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
4558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
4568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4588888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_put(struct cache_entry *entry)
4598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
460d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
461d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * finished with this cache entry, once the usage count reaches zero it
462c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * can be reused and is put onto the free list.  As it remains
463c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * accessible via the hash table it can be found getting a new lease of
464c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * life before it is reused.
465d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
4668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
4678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->used --;
4698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->used == 0) {
4708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_free_list(entry->cache, entry);
4716b336d83d3546674593f7de3be86d174f32fd753Phillip Lougher		entry->cache->used --;
4728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
473d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
474c435240f52b78b0ef498118727ba8dad186db26bplougher		 * if the wait_free flag is set, one or more threads may be
475c435240f52b78b0ef498118727ba8dad186db26bplougher		 * waiting on this buffer
476d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
4778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->cache->wait_free) {
4788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache->wait_free = FALSE;
4798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			pthread_cond_broadcast(&entry->cache->wait_for_free);
4808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
4818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
4828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
4848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
485476dcb48b24efff22caa970f000e151f1b28918dplougher
486476dcb48b24efff22caa970f000e151f1b28918dplougher
487cece843c2aff7b4775b60b04f24822f477b7b488Phillip Loughervoid dump_cache(struct cache *cache)
488cece843c2aff7b4775b60b04f24822f477b7b488Phillip Lougher{
489cece843c2aff7b4775b60b04f24822f477b7b488Phillip Lougher	pthread_mutex_lock(&cache->mutex);
490cece843c2aff7b4775b60b04f24822f477b7b488Phillip Lougher
491cece843c2aff7b4775b60b04f24822f477b7b488Phillip Lougher	printf("Max buffers %d, Current size %d, Used %d,  %s\n",
492cece843c2aff7b4775b60b04f24822f477b7b488Phillip Lougher		cache->max_buffers, cache->count, cache->used,
493cece843c2aff7b4775b60b04f24822f477b7b488Phillip Lougher		cache->free_list ?  "Free buffers" : "No free buffers");
494cece843c2aff7b4775b60b04f24822f477b7b488Phillip Lougher
495cece843c2aff7b4775b60b04f24822f477b7b488Phillip Lougher	pthread_mutex_unlock(&cache->mutex);
496cece843c2aff7b4775b60b04f24822f477b7b488Phillip Lougher}
497cece843c2aff7b4775b60b04f24822f477b7b488Phillip Lougher
498cece843c2aff7b4775b60b04f24822f477b7b488Phillip Lougher
499476dcb48b24efff22caa970f000e151f1b28918dplougherchar *modestr(char *str, int mode)
500476dcb48b24efff22caa970f000e151f1b28918dplougher{
501476dcb48b24efff22caa970f000e151f1b28918dplougher	int i;
502476dcb48b24efff22caa970f000e151f1b28918dplougher
503476dcb48b24efff22caa970f000e151f1b28918dplougher	strcpy(str, "----------");
504476dcb48b24efff22caa970f000e151f1b28918dplougher
505476dcb48b24efff22caa970f000e151f1b28918dplougher	for(i = 0; table[i].mask != 0; i++) {
506476dcb48b24efff22caa970f000e151f1b28918dplougher		if((mode & table[i].mask) == table[i].value)
507476dcb48b24efff22caa970f000e151f1b28918dplougher			str[table[i].position] = table[i].mode;
508476dcb48b24efff22caa970f000e151f1b28918dplougher	}
509476dcb48b24efff22caa970f000e151f1b28918dplougher
510476dcb48b24efff22caa970f000e151f1b28918dplougher	return str;
511476dcb48b24efff22caa970f000e151f1b28918dplougher}
512476dcb48b24efff22caa970f000e151f1b28918dplougher
513476dcb48b24efff22caa970f000e151f1b28918dplougher
5143edfa57b6a463f7d441d995559143f4861d62e98plougher#define TOTALCHARS  25
5156f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint print_filename(char *pathname, struct inode *inode)
516476dcb48b24efff22caa970f000e151f1b28918dplougher{
517afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher	char str[11], dummy[12], dummy2[12]; /* overflow safe */
518afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher	char *userstr, *groupstr;
5196f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int padchars;
520476dcb48b24efff22caa970f000e151f1b28918dplougher	struct passwd *user;
521476dcb48b24efff22caa970f000e151f1b28918dplougher	struct group *group;
52288facddfd83e48a907b82210ddccbb4f84d80aecplougher	struct tm *t;
523476dcb48b24efff22caa970f000e151f1b28918dplougher
524476dcb48b24efff22caa970f000e151f1b28918dplougher	if(short_ls) {
525476dcb48b24efff22caa970f000e151f1b28918dplougher		printf("%s\n", pathname);
526476dcb48b24efff22caa970f000e151f1b28918dplougher		return 1;
527476dcb48b24efff22caa970f000e151f1b28918dplougher	}
528476dcb48b24efff22caa970f000e151f1b28918dplougher
529266b83c3b162a6764407753909712fcaade951f2plougher	user = getpwuid(inode->uid);
530266b83c3b162a6764407753909712fcaade951f2plougher	if(user == NULL) {
531afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		int res = snprintf(dummy, 12, "%d", inode->uid);
532afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		if(res < 0)
533afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			EXIT_UNSQUASH("snprintf failed in print_filename()\n");
534afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		else if(res >= 12)
535afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			/* unsigned int shouldn't ever need more than 11 bytes
536afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			 * (including terminating '\0') to print in base 10 */
537afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			userstr = "*";
538afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		else
539afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			userstr = dummy;
5403edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
5413edfa57b6a463f7d441d995559143f4861d62e98plougher		userstr = user->pw_name;
5423edfa57b6a463f7d441d995559143f4861d62e98plougher
543266b83c3b162a6764407753909712fcaade951f2plougher	group = getgrgid(inode->gid);
544266b83c3b162a6764407753909712fcaade951f2plougher	if(group == NULL) {
545afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		int res = snprintf(dummy2, 12, "%d", inode->gid);
546afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		if(res < 0)
547afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			EXIT_UNSQUASH("snprintf failed in print_filename()\n");
548afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		else if(res >= 12)
549afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			/* unsigned int shouldn't ever need more than 11 bytes
550afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			 * (including terminating '\0') to print in base 10 */
551afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			groupstr = "*";
552afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher		else
553afd5fec5ba90ad8efb344f814128e0d746001ea5Phillip Lougher			groupstr = dummy2;
5543edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
5553edfa57b6a463f7d441d995559143f4861d62e98plougher		groupstr = group->gr_name;
5563edfa57b6a463f7d441d995559143f4861d62e98plougher
5576f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	printf("%s %s/%s ", modestr(str, inode->mode), userstr, groupstr);
5583edfa57b6a463f7d441d995559143f4861d62e98plougher
5596f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(inode->mode & S_IFMT) {
5603edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFREG:
5613edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFDIR:
5623edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFSOCK:
5633edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFIFO:
5643edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFLNK:
565c435240f52b78b0ef498118727ba8dad186db26bplougher			padchars = TOTALCHARS - strlen(userstr) -
566c435240f52b78b0ef498118727ba8dad186db26bplougher				strlen(groupstr);
5673edfa57b6a463f7d441d995559143f4861d62e98plougher
568c435240f52b78b0ef498118727ba8dad186db26bplougher			printf("%*lld ", padchars > 0 ? padchars : 0,
569c435240f52b78b0ef498118727ba8dad186db26bplougher				inode->data);
5703edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
5713edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFCHR:
5723edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFBLK:
573c435240f52b78b0ef498118727ba8dad186db26bplougher			padchars = TOTALCHARS - strlen(userstr) -
574c435240f52b78b0ef498118727ba8dad186db26bplougher				strlen(groupstr) - 7;
5753edfa57b6a463f7d441d995559143f4861d62e98plougher
576d4204758f77acb5a371fa1487a755b76a05d5476plougher			printf("%*s%3d,%3d ", padchars > 0 ? padchars : 0, " ",
577c435240f52b78b0ef498118727ba8dad186db26bplougher				(int) inode->data >> 8, (int) inode->data &
578c435240f52b78b0ef498118727ba8dad186db26bplougher				0xff);
5793edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
5803edfa57b6a463f7d441d995559143f4861d62e98plougher	}
581476dcb48b24efff22caa970f000e151f1b28918dplougher
5826f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	t = localtime(&inode->time);
58388facddfd83e48a907b82210ddccbb4f84d80aecplougher
584d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("%d-%02d-%02d %02d:%02d %s", t->tm_year + 1900, t->tm_mon + 1,
585d4204758f77acb5a371fa1487a755b76a05d5476plougher		t->tm_mday, t->tm_hour, t->tm_min, pathname);
5866f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((inode->mode & S_IFMT) == S_IFLNK)
5876f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		printf(" -> %s", inode->symlink);
5883edfa57b6a463f7d441d995559143f4861d62e98plougher	printf("\n");
5893edfa57b6a463f7d441d995559143f4861d62e98plougher
590476dcb48b24efff22caa970f000e151f1b28918dplougher	return 1;
591476dcb48b24efff22caa970f000e151f1b28918dplougher}
592476dcb48b24efff22caa970f000e151f1b28918dplougher
593443c15812032991c98b33b5424b17bcd55fe3575plougher
594e3206fad5b70e7e0527db2a627ad26616a8a2429ploughervoid add_entry(struct hash_table_entry *hash_table[], long long start,
595e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	int bytes)
596443c15812032991c98b33b5424b17bcd55fe3575plougher{
597443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
598443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
599443c15812032991c98b33b5424b17bcd55fe3575plougher
600cb2cff9a58d8d92fc6edb95049469188ee49c6c9plougher	hash_table_entry = malloc(sizeof(struct hash_table_entry));
601cb2cff9a58d8d92fc6edb95049469188ee49c6c9plougher	if(hash_table_entry == NULL)
6024a39fa82d4614c18d2977be7898d78d20ba01a49plougher		EXIT_UNSQUASH("Out of memory in add_entry\n");
603443c15812032991c98b33b5424b17bcd55fe3575plougher
604443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->start = start;
605443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->bytes = bytes;
606443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->next = hash_table[hash];
607443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table[hash] = hash_table_entry;
608443c15812032991c98b33b5424b17bcd55fe3575plougher}
609443c15812032991c98b33b5424b17bcd55fe3575plougher
610443c15812032991c98b33b5424b17bcd55fe3575plougher
611f404f4914fdb272a70e18664e8963d793cc90f44plougherint lookup_entry(struct hash_table_entry *hash_table[], long long start)
612443c15812032991c98b33b5424b17bcd55fe3575plougher{
613443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
614443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
615443c15812032991c98b33b5424b17bcd55fe3575plougher
6169dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	for(hash_table_entry = hash_table[hash]; hash_table_entry;
6179dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				hash_table_entry = hash_table_entry->next)
6187a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher
619443c15812032991c98b33b5424b17bcd55fe3575plougher		if(hash_table_entry->start == start)
620443c15812032991c98b33b5424b17bcd55fe3575plougher			return hash_table_entry->bytes;
621443c15812032991c98b33b5424b17bcd55fe3575plougher
622443c15812032991c98b33b5424b17bcd55fe3575plougher	return -1;
623443c15812032991c98b33b5424b17bcd55fe3575plougher}
624443c15812032991c98b33b5424b17bcd55fe3575plougher
625443c15812032991c98b33b5424b17bcd55fe3575plougher
6263306cb2b54a60a32664617118336ac141e1471b6plougherint read_fs_bytes(int fd, long long byte, int bytes, void *buff)
627443c15812032991c98b33b5424b17bcd55fe3575plougher{
628443c15812032991c98b33b5424b17bcd55fe3575plougher	off_t off = byte;
629d7f3de3408089ce187d8bc26f6072730c77628daplougher	int res, count;
630443c15812032991c98b33b5424b17bcd55fe3575plougher
631c435240f52b78b0ef498118727ba8dad186db26bplougher	TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte,
632c435240f52b78b0ef498118727ba8dad186db26bplougher		bytes);
633fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
634443c15812032991c98b33b5424b17bcd55fe3575plougher	if(lseek(fd, off, SEEK_SET) == -1) {
6355d415c6659faaa7a69c9baa7175610d889747142plougher		ERROR("Lseek failed because %s\n", strerror(errno));
636443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
637443c15812032991c98b33b5424b17bcd55fe3575plougher	}
638443c15812032991c98b33b5424b17bcd55fe3575plougher
639d7f3de3408089ce187d8bc26f6072730c77628daplougher	for(count = 0; count < bytes; count += res) {
640d7f3de3408089ce187d8bc26f6072730c77628daplougher		res = read(fd, buff + count, bytes - count);
641d7f3de3408089ce187d8bc26f6072730c77628daplougher		if(res < 1) {
642d7f3de3408089ce187d8bc26f6072730c77628daplougher			if(res == 0) {
643e3206fad5b70e7e0527db2a627ad26616a8a2429plougher				ERROR("Read on filesystem failed because "
644e3206fad5b70e7e0527db2a627ad26616a8a2429plougher					"EOF\n");
645d7f3de3408089ce187d8bc26f6072730c77628daplougher				return FALSE;
646d7f3de3408089ce187d8bc26f6072730c77628daplougher			} else if(errno != EINTR) {
647d7f3de3408089ce187d8bc26f6072730c77628daplougher				ERROR("Read on filesystem failed because %s\n",
648d7f3de3408089ce187d8bc26f6072730c77628daplougher						strerror(errno));
649d7f3de3408089ce187d8bc26f6072730c77628daplougher				return FALSE;
650d7f3de3408089ce187d8bc26f6072730c77628daplougher			} else
651d7f3de3408089ce187d8bc26f6072730c77628daplougher				res = 0;
652d7f3de3408089ce187d8bc26f6072730c77628daplougher		}
653443c15812032991c98b33b5424b17bcd55fe3575plougher	}
654443c15812032991c98b33b5424b17bcd55fe3575plougher
655443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
656443c15812032991c98b33b5424b17bcd55fe3575plougher}
657443c15812032991c98b33b5424b17bcd55fe3575plougher
658443c15812032991c98b33b5424b17bcd55fe3575plougher
659cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougherint read_block(int fd, long long start, long long *next, int expected,
660cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher								void *block)
661443c15812032991c98b33b5424b17bcd55fe3575plougher{
662443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned short c_byte;
663cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	int offset = 2, res, compressed;
664cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	int outlen = expected ? expected : SQUASHFS_METADATA_SIZE;
665443c15812032991c98b33b5424b17bcd55fe3575plougher
666443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
667923b301e304637fd5e587eb05a6f44558abae2bdplougher		if(read_fs_bytes(fd, start, 2, &c_byte) == FALSE)
668fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
669923b301e304637fd5e587eb05a6f44558abae2bdplougher		c_byte = (c_byte >> 8) | ((c_byte & 0xff) << 8);
670443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
6713306cb2b54a60a32664617118336ac141e1471b6plougher		if(read_fs_bytes(fd, start, 2, &c_byte) == FALSE)
672fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
673fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
674d4204758f77acb5a371fa1487a755b76a05d5476plougher	TRACE("read_block: block @0x%llx, %d %s bytes\n", start,
675d4204758f77acb5a371fa1487a755b76a05d5476plougher		SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ?
676d4204758f77acb5a371fa1487a755b76a05d5476plougher		"compressed" : "uncompressed");
677443c15812032991c98b33b5424b17bcd55fe3575plougher
67827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(SQUASHFS_CHECK_DATA(sBlk.s.flags))
679443c15812032991c98b33b5424b17bcd55fe3575plougher		offset = 3;
680443c15812032991c98b33b5424b17bcd55fe3575plougher
681cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	compressed = SQUASHFS_COMPRESSED(c_byte);
682cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
683cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher
684cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	/*
685cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	 * The block size should not be larger than
686cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	 * the uncompressed size (or max uncompressed size if
687cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	 * expected is 0)
688cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	 */
689cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	if(c_byte > outlen)
690cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		return 0;
691cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher
692cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	if(compressed) {
693cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		char buffer[c_byte];
694cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		int error;
695cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher
696cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		res = read_fs_bytes(fd, start + offset, c_byte, buffer);
697cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		if(res == FALSE)
698fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
699443c15812032991c98b33b5424b17bcd55fe3575plougher
700b48442b2e37b3cb7efbffb032968f115eec7963cplougher		res = compressor_uncompress(comp, block, buffer, c_byte,
701cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher			outlen, &error);
702efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
703efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		if(res == -1) {
704efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			ERROR("%s uncompress failed with error code %d\n",
705efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher				comp->name, error);
706fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
707443c15812032991c98b33b5424b17bcd55fe3575plougher		}
708443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
709cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		res = read_fs_bytes(fd, start + offset, c_byte, block);
710cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		if(res == FALSE)
711fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
712cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		res = c_byte;
713443c15812032991c98b33b5424b17bcd55fe3575plougher	}
714fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
715cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	if(next)
716cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		*next = start + offset + c_byte;
717cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher
718cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	/*
719cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	 * if expected, then check the (uncompressed) return data
720cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	 * is of the expected size
721cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	 */
722cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	if(expected && expected != res)
723cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		return 0;
724cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher	else
725cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		return res;
726cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher
727fe3ca0609d02d78bcd11637c1220b2ff428f466aplougherfailed:
72868ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher	ERROR("read_block: failed to read block @0x%llx\n", start);
729fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	return FALSE;
730443c15812032991c98b33b5424b17bcd55fe3575plougher}
731443c15812032991c98b33b5424b17bcd55fe3575plougher
732443c15812032991c98b33b5424b17bcd55fe3575plougher
733443c15812032991c98b33b5424b17bcd55fe3575plougherint read_data_block(long long start, unsigned int size, char *block)
734443c15812032991c98b33b5424b17bcd55fe3575plougher{
735efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	int error, res;
736443c15812032991c98b33b5424b17bcd55fe3575plougher	int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
737443c15812032991c98b33b5424b17bcd55fe3575plougher
738d4204758f77acb5a371fa1487a755b76a05d5476plougher	TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start,
739c6ab26edb0c0da6b276281960d9c8748a70886feplougher		c_byte, SQUASHFS_COMPRESSED_BLOCK(size) ? "compressed" :
740c435240f52b78b0ef498118727ba8dad186db26bplougher		"uncompressed");
741fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
742443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED_BLOCK(size)) {
74386561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		if(read_fs_bytes(fd, start, c_byte, data) == FALSE)
74468ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
745443c15812032991c98b33b5424b17bcd55fe3575plougher
746b48442b2e37b3cb7efbffb032968f115eec7963cplougher		res = compressor_uncompress(comp, block, data, c_byte,
747b48442b2e37b3cb7efbffb032968f115eec7963cplougher			block_size, &error);
748efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
749efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		if(res == -1) {
750efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			ERROR("%s uncompress failed with error code %d\n",
751efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher				comp->name, error);
75268ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
753443c15812032991c98b33b5424b17bcd55fe3575plougher		}
754443c15812032991c98b33b5424b17bcd55fe3575plougher
755efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		return res;
756443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
75786561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		if(read_fs_bytes(fd, start, c_byte, block) == FALSE)
75868ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher			goto failed;
759443c15812032991c98b33b5424b17bcd55fe3575plougher
760443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
761443c15812032991c98b33b5424b17bcd55fe3575plougher	}
76268ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher
76368ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougherfailed:
764d4204758f77acb5a371fa1487a755b76a05d5476plougher	ERROR("read_data_block: failed to read block @0x%llx, size %d\n", start,
765c6ab26edb0c0da6b276281960d9c8748a70886feplougher		c_byte);
76668ba26e4a9ee62315d5d2bf5c23bfbc02347b646plougher	return FALSE;
767443c15812032991c98b33b5424b17bcd55fe3575plougher}
768443c15812032991c98b33b5424b17bcd55fe3575plougher
769443c15812032991c98b33b5424b17bcd55fe3575plougher
7701ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougherint read_inode_table(long long start, long long end)
771443c15812032991c98b33b5424b17bcd55fe3575plougher{
772443c15812032991c98b33b5424b17bcd55fe3575plougher	int size = 0, bytes = 0, res;
773443c15812032991c98b33b5424b17bcd55fe3575plougher
7741ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher	TRACE("read_inode_table: start %lld, end %lld\n", start, end);
7751ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher
776443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
777c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher		if(size - bytes < SQUASHFS_METADATA_SIZE) {
778c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher			inode_table = realloc(inode_table, size +=
779c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher				SQUASHFS_METADATA_SIZE);
7801ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher			if(inode_table == NULL) {
7811ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher				ERROR("Out of memory in read_inode_table");
7821ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher				goto failed;
7831ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher			}
784c1a81ec0ca6911533aec74e690f55b7d0a7131a4plougher		}
7851ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher
786443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(inode_table_hash, start, bytes);
7871ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher
788cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		res = read_block(fd, start, &start, 0, inode_table + bytes);
789c435240f52b78b0ef498118727ba8dad186db26bplougher		if(res == 0) {
7901ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher			ERROR("read_inode_table: failed to read block\n");
7911ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher			goto failed;
792443c15812032991c98b33b5424b17bcd55fe3575plougher		}
793443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
794066439a35c69c023ca15156da81987fe5264475fPhillip Lougher
795066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		/*
796066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 * If this is not the last metadata block in the inode table
797066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 * then it should be SQUASHFS_METADATA_SIZE in size.
798066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 * Note, we can't use expected in read_block() above for this
799066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 * because we don't know if this is the last block until
800066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 * after reading.
801066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 */
8021ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher		if(start != end && res != SQUASHFS_METADATA_SIZE) {
8031ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher			ERROR("read_inode_table: metadata block should be %d "
8041ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher				"bytes in length, it is %d bytes\n",
8051ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher				SQUASHFS_METADATA_SIZE, res);
806066439a35c69c023ca15156da81987fe5264475fPhillip Lougher
8071ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher			goto failed;
8081ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher		}
809443c15812032991c98b33b5424b17bcd55fe3575plougher	}
8101ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher
8111ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher	return TRUE;
8121ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher
8131ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougherfailed:
8141ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher	free(inode_table);
8151ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher	return FALSE;
816443c15812032991c98b33b5424b17bcd55fe3575plougher}
817443c15812032991c98b33b5424b17bcd55fe3575plougher
818443c15812032991c98b33b5424b17bcd55fe3575plougher
819d4204758f77acb5a371fa1487a755b76a05d5476plougherint set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time,
820fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher	unsigned int xattr, unsigned int set_mode)
821443c15812032991c98b33b5424b17bcd55fe3575plougher{
8226f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	struct utimbuf times = { time, time };
823443c15812032991c98b33b5424b17bcd55fe3575plougher
8242ef25cb004cc6995bd36f781863aa844fe8c358dplougher	write_xattr(pathname, xattr);
8252ef25cb004cc6995bd36f781863aa844fe8c358dplougher
826443c15812032991c98b33b5424b17bcd55fe3575plougher	if(utime(pathname, &times) == -1) {
827d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("set_attributes: failed to set time on %s, because %s\n",
828d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
829443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
830443c15812032991c98b33b5424b17bcd55fe3575plougher	}
831443c15812032991c98b33b5424b17bcd55fe3575plougher
8329dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if(root_process) {
8336f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(chown(pathname, uid, guid) == -1) {
834c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("set_attributes: failed to change uid and gids "
835c435240f52b78b0ef498118727ba8dad186db26bplougher				"on %s, because %s\n", pathname,
836c435240f52b78b0ef498118727ba8dad186db26bplougher				strerror(errno));
837443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
838443c15812032991c98b33b5424b17bcd55fe3575plougher		}
8399dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	} else
8409dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		mode &= ~07000;
8419dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
8429dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) {
843d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("set_attributes: failed to change mode %s, because %s\n",
844d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
8459dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		return FALSE;
846443c15812032991c98b33b5424b17bcd55fe3575plougher	}
847443c15812032991c98b33b5424b17bcd55fe3575plougher
848443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
849443c15812032991c98b33b5424b17bcd55fe3575plougher}
850443c15812032991c98b33b5424b17bcd55fe3575plougher
851443c15812032991c98b33b5424b17bcd55fe3575plougher
8521c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougherint write_bytes(int fd, char *buff, int bytes)
8531c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher{
8541c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	int res, count;
8551c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
8561c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	for(count = 0; count < bytes; count += res) {
8571c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		res = write(fd, buff + count, bytes - count);
8581c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		if(res == -1) {
8591c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			if(errno != EINTR) {
860c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("Write on output file failed because "
861c435240f52b78b0ef498118727ba8dad186db26bplougher					"%s\n", strerror(errno));
8621c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher				return -1;
8631c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			}
8641c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher			res = 0;
8651c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher		}
8661c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	}
8671c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
8681c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	return 0;
8691c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher}
8701c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
8711c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher
872b9cee889506e674726856035dba52d5e1cceeb99plougherint lseek_broken = FALSE;
873c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougherchar *zero_data = NULL;
874b9cee889506e674726856035dba52d5e1cceeb99plougher
87587f5e0e29e5f56516daaa51b1d36cde3d86a0f1fplougherint write_block(int file_fd, char *buffer, int size, long long hole, int sparse)
876b9cee889506e674726856035dba52d5e1cceeb99plougher{
877b9cee889506e674726856035dba52d5e1cceeb99plougher	off_t off = hole;
878b9cee889506e674726856035dba52d5e1cceeb99plougher
879b9cee889506e674726856035dba52d5e1cceeb99plougher	if(hole) {
880c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if(sparse && lseek_broken == FALSE) {
881c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			 int error = lseek(file_fd, off, SEEK_CUR);
882c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			 if(error == -1)
883c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				/* failed to seek beyond end of file */
884c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				lseek_broken = TRUE;
885c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		}
886c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
887c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if((sparse == FALSE || lseek_broken) && zero_data == NULL) {
888b9cee889506e674726856035dba52d5e1cceeb99plougher			if((zero_data = malloc(block_size)) == NULL)
889c435240f52b78b0ef498118727ba8dad186db26bplougher				EXIT_UNSQUASH("write_block: failed to alloc "
890c435240f52b78b0ef498118727ba8dad186db26bplougher					"zero data block\n");
891b9cee889506e674726856035dba52d5e1cceeb99plougher			memset(zero_data, 0, block_size);
892b9cee889506e674726856035dba52d5e1cceeb99plougher		}
893c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
894c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		if(sparse == FALSE || lseek_broken) {
895b9cee889506e674726856035dba52d5e1cceeb99plougher			int blocks = (hole + block_size -1) / block_size;
896b9cee889506e674726856035dba52d5e1cceeb99plougher			int avail_bytes, i;
897b9cee889506e674726856035dba52d5e1cceeb99plougher			for(i = 0; i < blocks; i++, hole -= avail_bytes) {
898d4204758f77acb5a371fa1487a755b76a05d5476plougher				avail_bytes = hole > block_size ? block_size :
899d4204758f77acb5a371fa1487a755b76a05d5476plougher					hole;
900d4204758f77acb5a371fa1487a755b76a05d5476plougher				if(write_bytes(file_fd, zero_data, avail_bytes)
901d4204758f77acb5a371fa1487a755b76a05d5476plougher						== -1)
902b9cee889506e674726856035dba52d5e1cceeb99plougher					goto failure;
903b9cee889506e674726856035dba52d5e1cceeb99plougher			}
904b9cee889506e674726856035dba52d5e1cceeb99plougher		}
905b9cee889506e674726856035dba52d5e1cceeb99plougher	}
906b9cee889506e674726856035dba52d5e1cceeb99plougher
9071c5d8b0e7c8e68373eeb28311f9f9ccae2d9c617plougher	if(write_bytes(file_fd, buffer, size) == -1)
908b9cee889506e674726856035dba52d5e1cceeb99plougher		goto failure;
909b9cee889506e674726856035dba52d5e1cceeb99plougher
910b9cee889506e674726856035dba52d5e1cceeb99plougher	return TRUE;
911b9cee889506e674726856035dba52d5e1cceeb99plougher
912b9cee889506e674726856035dba52d5e1cceeb99plougherfailure:
913b9cee889506e674726856035dba52d5e1cceeb99plougher	return FALSE;
914b9cee889506e674726856035dba52d5e1cceeb99plougher}
915b9cee889506e674726856035dba52d5e1cceeb99plougher
9168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
917cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougherpthread_mutex_t open_mutex = PTHREAD_MUTEX_INITIALIZER;
918cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougherpthread_cond_t open_empty = PTHREAD_COND_INITIALIZER;
919cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougherint open_unlimited, open_count;
920cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher#define OPEN_FILE_MARGIN 10
921cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
922cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
923cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Loughervoid open_init(int count)
924cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher{
925cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	open_count = count;
926cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	open_unlimited = count == -1;
927cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher}
928cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
929cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
930cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougherint open_wait(char *pathname, int flags, mode_t mode)
931cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher{
932cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	if (!open_unlimited) {
933cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		pthread_mutex_lock(&open_mutex);
934cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		while (open_count == 0)
935cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher			pthread_cond_wait(&open_empty, &open_mutex);
936cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		open_count --;
937cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		pthread_mutex_unlock(&open_mutex);
938cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	}
939cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
940cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	return open(pathname, flags, mode);
941cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher}
942cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
943cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
944cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Loughervoid close_wake(int fd)
945cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher{
946cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	close(fd);
947cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
948cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	if (!open_unlimited) {
949cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		pthread_mutex_lock(&open_mutex);
950cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		open_count ++;
951cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		pthread_cond_signal(&open_empty);
952cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		pthread_mutex_unlock(&open_mutex);
953cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	}
954cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher}
955cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
956cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
9572c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Loughervoid queue_file(char *pathname, int file_fd, struct inode *inode)
9582c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher{
9592c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	struct squashfs_file *file = malloc(sizeof(struct squashfs_file));
9602c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	if(file == NULL)
9612c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		EXIT_UNSQUASH("queue_file: unable to malloc file\n");
9622c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
9632c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->fd = file_fd;
9642c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->file_size = inode->data;
9652c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->mode = inode->mode;
9662c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->gid = inode->gid;
9672c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->uid = inode->uid;
9682c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->time = inode->time;
9692c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->pathname = strdup(pathname);
9702c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->blocks = inode->blocks + (inode->frag_bytes > 0);
9712c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->sparse = inode->sparse;
9722c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->xattr = inode->xattr;
9732c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	queue_put(to_writer, file);
9742c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher}
9752c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
9762c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
9772c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Loughervoid queue_dir(char *pathname, struct dir *dir)
9782c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher{
9792c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	struct squashfs_file *file = malloc(sizeof(struct squashfs_file));
9802c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	if(file == NULL)
9812c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		EXIT_UNSQUASH("queue_dir: unable to malloc file\n");
9822c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
9832c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->fd = -1;
9842c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->mode = dir->mode;
9852c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->gid = dir->guid;
9862c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->uid = dir->uid;
9872c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->time = dir->mtime;
9882c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->pathname = strdup(pathname);
9892c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	file->xattr = dir->xattr;
9902c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	queue_put(to_writer, file);
9912c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher}
9922c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
9932c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
99479df93becb68081effabebba3006c794be308598plougherint write_file(struct inode *inode, char *pathname)
995443c15812032991c98b33b5424b17bcd55fe3575plougher{
9968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	unsigned int file_fd, i;
997f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher	unsigned int *block_list;
99879df93becb68081effabebba3006c794be308598plougher	int file_end = inode->data / block_size;
99979df93becb68081effabebba3006c794be308598plougher	long long start = inode->start;
1000443c15812032991c98b33b5424b17bcd55fe3575plougher
100179df93becb68081effabebba3006c794be308598plougher	TRACE("write_file: regular file, blocks %d\n", inode->blocks);
1002443c15812032991c98b33b5424b17bcd55fe3575plougher
1003cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	file_fd = open_wait(pathname, O_CREAT | O_WRONLY |
1004cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		(force ? O_TRUNC : 0), (mode_t) inode->mode & 0777);
1005d4204758f77acb5a371fa1487a755b76a05d5476plougher	if(file_fd == -1) {
1006d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("write_file: failed to create file %s, because %s\n",
1007d4204758f77acb5a371fa1487a755b76a05d5476plougher			pathname, strerror(errno));
1008443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
1009443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1010443c15812032991c98b33b5424b17bcd55fe3575plougher
10116037584bc3e861ff932f5244105959c56c8560e3plougher	block_list = malloc(inode->blocks * sizeof(unsigned int));
10126037584bc3e861ff932f5244105959c56c8560e3plougher	if(block_list == NULL)
10138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("write_file: unable to malloc block list\n");
1014443c15812032991c98b33b5424b17bcd55fe3575plougher
101579df93becb68081effabebba3006c794be308598plougher	s_ops.read_block_list(block_list, inode->block_ptr, inode->blocks);
1016443c15812032991c98b33b5424b17bcd55fe3575plougher
1017d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
1018d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * the writer thread is queued a squashfs_file structure describing the
1019009263430d50ee32f3757c3c34d1f06262759f5dPhillip Lougher 	 * file.  If the file has one or more blocks or a fragment they are
1020c435240f52b78b0ef498118727ba8dad186db26bplougher 	 * queued separately (references to blocks in the cache).
1021d4204758f77acb5a371fa1487a755b76a05d5476plougher 	 */
10222c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	queue_file(pathname, file_fd, inode);
1023443c15812032991c98b33b5424b17bcd55fe3575plougher
102479df93becb68081effabebba3006c794be308598plougher	for(i = 0; i < inode->blocks; i++) {
10258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
10268372232d2460411adaa2299c32a0a88665e44902plougher		struct file_entry *block = malloc(sizeof(struct file_entry));
10278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
10288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
10298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
10308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->offset = 0;
1031d4204758f77acb5a371fa1487a755b76a05d5476plougher		block->size = i == file_end ? inode->data & (block_size - 1) :
1032d4204758f77acb5a371fa1487a755b76a05d5476plougher			block_size;
1033009263430d50ee32f3757c3c34d1f06262759f5dPhillip Lougher		if(block_list[i] == 0) /* sparse block */
10348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			block->buffer = NULL;
10358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else {
1036d4204758f77acb5a371fa1487a755b76a05d5476plougher			block->buffer = cache_get(data_cache, start,
1037d4204758f77acb5a371fa1487a755b76a05d5476plougher				block_list[i]);
10388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			start += c_byte;
1039443c15812032991c98b33b5424b17bcd55fe3575plougher		}
10408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
1041443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1042443c15812032991c98b33b5424b17bcd55fe3575plougher
104379df93becb68081effabebba3006c794be308598plougher	if(inode->frag_bytes) {
10448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int size;
10458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		long long start;
10468372232d2460411adaa2299c32a0a88665e44902plougher		struct file_entry *block = malloc(sizeof(struct file_entry));
10478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
10488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
10498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
105079df93becb68081effabebba3006c794be308598plougher		s_ops.read_fragment(inode->fragment, &start, &size);
10518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->buffer = cache_get(fragment_cache, start, size);
105279df93becb68081effabebba3006c794be308598plougher		block->offset = inode->offset;
105379df93becb68081effabebba3006c794be308598plougher		block->size = inode->frag_bytes;
10548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
1055b9cee889506e674726856035dba52d5e1cceeb99plougher	}
1056b9cee889506e674726856035dba52d5e1cceeb99plougher
1057b9cee889506e674726856035dba52d5e1cceeb99plougher	free(block_list);
1058443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1059443c15812032991c98b33b5424b17bcd55fe3575plougher}
1060476dcb48b24efff22caa970f000e151f1b28918dplougher
1061476dcb48b24efff22caa970f000e151f1b28918dplougher
10626f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint create_inode(char *pathname, struct inode *i)
1063443c15812032991c98b33b5424b17bcd55fe3575plougher{
10646f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	TRACE("create_inode: pathname %s\n", pathname);
1065443c15812032991c98b33b5424b17bcd55fe3575plougher
10666f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if(created_inode[i->inode_number - 1]) {
1067443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("create_inode: hard link\n");
10686013a30bd39550decc2546a47e5168e57bfcfde8plougher		if(force)
10696013a30bd39550decc2546a47e5168e57bfcfde8plougher			unlink(pathname);
10706013a30bd39550decc2546a47e5168e57bfcfde8plougher
10716f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(link(created_inode[i->inode_number - 1], pathname) == -1) {
1072c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("create_inode: failed to create hardlink, "
1073c435240f52b78b0ef498118727ba8dad186db26bplougher				"because %s\n", strerror(errno));
1074443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
1075443c15812032991c98b33b5424b17bcd55fe3575plougher		}
1076443c15812032991c98b33b5424b17bcd55fe3575plougher
1077443c15812032991c98b33b5424b17bcd55fe3575plougher		return TRUE;
1078443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1079443c15812032991c98b33b5424b17bcd55fe3575plougher
10806f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(i->type) {
10816f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_FILE_TYPE:
10826f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_LREG_TYPE:
1083c435240f52b78b0ef498118727ba8dad186db26bplougher			TRACE("create_inode: regular file, file_size %lld, "
1084c435240f52b78b0ef498118727ba8dad186db26bplougher				"blocks %d\n", i->data, i->blocks);
1085443c15812032991c98b33b5424b17bcd55fe3575plougher
108679df93becb68081effabebba3006c794be308598plougher			if(write_file(i, pathname))
1087443c15812032991c98b33b5424b17bcd55fe3575plougher				file_count ++;
1088443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
10896f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_SYMLINK_TYPE:
109099ec5405b480bf852a0d9eed20693b750ed68943plougher		case SQUASHFS_LSYMLINK_TYPE:
1091d4204758f77acb5a371fa1487a755b76a05d5476plougher			TRACE("create_inode: symlink, symlink_size %lld\n",
1092d4204758f77acb5a371fa1487a755b76a05d5476plougher				i->data);
1093443c15812032991c98b33b5424b17bcd55fe3575plougher
1094a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
1095a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
1096a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
10976f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(symlink(i->symlink, pathname) == -1) {
1098c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("create_inode: failed to create symlink "
1099c435240f52b78b0ef498118727ba8dad186db26bplougher					"%s, because %s\n", pathname,
1100c435240f52b78b0ef498118727ba8dad186db26bplougher					strerror(errno));
1101443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
1102443c15812032991c98b33b5424b17bcd55fe3575plougher			}
1103443c15812032991c98b33b5424b17bcd55fe3575plougher
11042ef25cb004cc6995bd36f781863aa844fe8c358dplougher			write_xattr(pathname, i->xattr);
11052ef25cb004cc6995bd36f781863aa844fe8c358dplougher
11069dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
11076f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(lchown(pathname, i->uid, i->gid) == -1)
1108c435240f52b78b0ef498118727ba8dad186db26bplougher					ERROR("create_inode: failed to change "
1109c435240f52b78b0ef498118727ba8dad186db26bplougher						"uid and gids on %s, because "
1110c435240f52b78b0ef498118727ba8dad186db26bplougher						"%s\n", pathname,
1111c435240f52b78b0ef498118727ba8dad186db26bplougher						strerror(errno));
1112443c15812032991c98b33b5424b17bcd55fe3575plougher			}
1113443c15812032991c98b33b5424b17bcd55fe3575plougher
1114443c15812032991c98b33b5424b17bcd55fe3575plougher			sym_count ++;
1115443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1116443c15812032991c98b33b5424b17bcd55fe3575plougher 		case SQUASHFS_BLKDEV_TYPE:
111799ec5405b480bf852a0d9eed20693b750ed68943plougher	 	case SQUASHFS_CHRDEV_TYPE:
111899ec5405b480bf852a0d9eed20693b750ed68943plougher 		case SQUASHFS_LBLKDEV_TYPE:
111999ec5405b480bf852a0d9eed20693b750ed68943plougher	 	case SQUASHFS_LCHRDEV_TYPE: {
11206f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			int chrdev = i->type == SQUASHFS_CHRDEV_TYPE;
1121545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			TRACE("create_inode: dev, rdev 0x%llx\n", i->data);
1122443c15812032991c98b33b5424b17bcd55fe3575plougher
11239dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
1124a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				if(force)
1125a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher					unlink(pathname);
1126a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
11276f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(mknod(pathname, chrdev ? S_IFCHR : S_IFBLK,
1128d4204758f77acb5a371fa1487a755b76a05d5476plougher						makedev((i->data >> 8) & 0xff,
1129d4204758f77acb5a371fa1487a755b76a05d5476plougher						i->data & 0xff)) == -1) {
1130c435240f52b78b0ef498118727ba8dad186db26bplougher					ERROR("create_inode: failed to create "
1131c435240f52b78b0ef498118727ba8dad186db26bplougher						"%s device %s, because %s\n",
1132d4204758f77acb5a371fa1487a755b76a05d5476plougher						chrdev ? "character" : "block",
1133d4204758f77acb5a371fa1487a755b76a05d5476plougher						pathname, strerror(errno));
1134443c15812032991c98b33b5424b17bcd55fe3575plougher					break;
1135443c15812032991c98b33b5424b17bcd55fe3575plougher				}
1136c435240f52b78b0ef498118727ba8dad186db26bplougher				set_attributes(pathname, i->mode, i->uid,
1137fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher					i->gid, i->time, i->xattr, TRUE);
1138443c15812032991c98b33b5424b17bcd55fe3575plougher				dev_count ++;
1139443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
1140c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("create_inode: could not create %s "
1141c435240f52b78b0ef498118727ba8dad186db26bplougher					"device %s, because you're not "
1142c435240f52b78b0ef498118727ba8dad186db26bplougher					"superuser!\n", chrdev ? "character" :
1143c435240f52b78b0ef498118727ba8dad186db26bplougher					"block", pathname);
1144443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
11456f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		}
1146443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_FIFO_TYPE:
114799ec5405b480bf852a0d9eed20693b750ed68943plougher		case SQUASHFS_LFIFO_TYPE:
1148443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: fifo\n");
1149443c15812032991c98b33b5424b17bcd55fe3575plougher
1150a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
1151a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
1152a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
1153443c15812032991c98b33b5424b17bcd55fe3575plougher			if(mknod(pathname, S_IFIFO, 0) == -1) {
1154d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("create_inode: failed to create fifo %s, "
1155d4204758f77acb5a371fa1487a755b76a05d5476plougher					"because %s\n", pathname,
1156d4204758f77acb5a371fa1487a755b76a05d5476plougher					strerror(errno));
1157443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
1158443c15812032991c98b33b5424b17bcd55fe3575plougher			}
1159c435240f52b78b0ef498118727ba8dad186db26bplougher			set_attributes(pathname, i->mode, i->uid, i->gid,
1160fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher				i->time, i->xattr, TRUE);
1161443c15812032991c98b33b5424b17bcd55fe3575plougher			fifo_count ++;
1162443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1163443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_SOCKET_TYPE:
116499ec5405b480bf852a0d9eed20693b750ed68943plougher		case SQUASHFS_LSOCKET_TYPE:
1165443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: socket\n");
1166443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("create_inode: socket %s ignored\n", pathname);
1167443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1168443c15812032991c98b33b5424b17bcd55fe3575plougher		default:
1169d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("Unknown inode type %d in create_inode_table!\n",
1170d4204758f77acb5a371fa1487a755b76a05d5476plougher				i->type);
1171443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
1172443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1173fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
11746f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	created_inode[i->inode_number - 1] = strdup(pathname);
1175443c15812032991c98b33b5424b17bcd55fe3575plougher
1176443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1177443c15812032991c98b33b5424b17bcd55fe3575plougher}
1178443c15812032991c98b33b5424b17bcd55fe3575plougher
1179443c15812032991c98b33b5424b17bcd55fe3575plougher
1180e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougherint read_directory_table(long long start, long long end)
1181443c15812032991c98b33b5424b17bcd55fe3575plougher{
1182443c15812032991c98b33b5424b17bcd55fe3575plougher	int bytes = 0, size = 0, res;
1183443c15812032991c98b33b5424b17bcd55fe3575plougher
1184e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher	TRACE("read_directory_table: start %lld, end %lld\n", start, end);
118541da3230b2ac91a73f9190676f66b3d80b21c270plougher
1186443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
118707d4d0dcafeb198a568f859b88034637e6e7a8e7plougher		if(size - bytes < SQUASHFS_METADATA_SIZE) {
118807d4d0dcafeb198a568f859b88034637e6e7a8e7plougher			directory_table = realloc(directory_table, size +=
118907d4d0dcafeb198a568f859b88034637e6e7a8e7plougher				SQUASHFS_METADATA_SIZE);
1190e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher			if(directory_table == NULL) {
1191e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher				ERROR("Out of memory in "
1192e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher						"read_directory_table\n");
1193e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher				goto failed;
1194e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher			}
119507d4d0dcafeb198a568f859b88034637e6e7a8e7plougher		}
1196e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher
1197443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(directory_table_hash, start, bytes);
1198e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher
1199cf5c8b43f14bad020372fe55fb237eb2ae2b28d4Phillip Lougher		res = read_block(fd, start, &start, 0, directory_table + bytes);
1200e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher		if(res == 0) {
1201e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher			ERROR("read_directory_table: failed to read block\n");
1202e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher			goto failed;
1203e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher		}
1204e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher
1205443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
1206066439a35c69c023ca15156da81987fe5264475fPhillip Lougher
1207066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		/*
1208066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 * If this is not the last metadata block in the directory table
1209066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 * then it should be SQUASHFS_METADATA_SIZE in size.
1210066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 * Note, we can't use expected in read_block() above for this
1211066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 * because we don't know if this is the last block until
1212066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 * after reading.
1213066439a35c69c023ca15156da81987fe5264475fPhillip Lougher		 */
1214e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher		if(start != end && res != SQUASHFS_METADATA_SIZE) {
121591f125a8dec54a0201423182ec523e975f93053bPhillip Lougher			ERROR("read_directory_table: metadata block "
1216e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher				"should be %d bytes in length, it is %d "
1217066439a35c69c023ca15156da81987fe5264475fPhillip Lougher				"bytes\n", SQUASHFS_METADATA_SIZE, res);
1218e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher			goto failed;
1219e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher		}
1220443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1221e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher
1222e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher	return TRUE;
1223e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher
1224e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougherfailed:
1225e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher	free(directory_table);
1226e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher	return FALSE;
1227443c15812032991c98b33b5424b17bcd55fe3575plougher}
1228443c15812032991c98b33b5424b17bcd55fe3575plougher
1229443c15812032991c98b33b5424b17bcd55fe3575plougher
12309dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block,
12319dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherunsigned int *offset, unsigned int *type)
1232443c15812032991c98b33b5424b17bcd55fe3575plougher{
1233443c15812032991c98b33b5424b17bcd55fe3575plougher	if(dir->cur_entry == dir->dir_count)
1234443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
1235443c15812032991c98b33b5424b17bcd55fe3575plougher
1236443c15812032991c98b33b5424b17bcd55fe3575plougher	*name = dir->dirs[dir->cur_entry].name;
1237443c15812032991c98b33b5424b17bcd55fe3575plougher	*start_block = dir->dirs[dir->cur_entry].start_block;
1238443c15812032991c98b33b5424b17bcd55fe3575plougher	*offset = dir->dirs[dir->cur_entry].offset;
1239443c15812032991c98b33b5424b17bcd55fe3575plougher	*type = dir->dirs[dir->cur_entry].type;
1240443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->cur_entry ++;
1241443c15812032991c98b33b5424b17bcd55fe3575plougher
1242443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1243443c15812032991c98b33b5424b17bcd55fe3575plougher}
1244443c15812032991c98b33b5424b17bcd55fe3575plougher
1245443c15812032991c98b33b5424b17bcd55fe3575plougher
1246443c15812032991c98b33b5424b17bcd55fe3575ploughervoid squashfs_closedir(struct dir *dir)
1247443c15812032991c98b33b5424b17bcd55fe3575plougher{
1248443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir->dirs);
1249443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir);
1250443c15812032991c98b33b5424b17bcd55fe3575plougher}
1251443c15812032991c98b33b5424b17bcd55fe3575plougher
1252443c15812032991c98b33b5424b17bcd55fe3575plougher
125304281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougherchar *get_component(char *target, char **targname)
1254b54566f5c433764830c29c83151691d0034de094plougher{
125504281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher	char *start;
125604281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher
1257b54566f5c433764830c29c83151691d0034de094plougher	while(*target == '/')
12583cef656655723444fb1e2de1a001e6c2a54cf81erlougher		target ++;
1259b54566f5c433764830c29c83151691d0034de094plougher
126004281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher	start = target;
12617f3c1887319ca4acff0787ed821628eb27c29f14Phillip Lougher	while(*target != '/' && *target != '\0')
126204281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher		target ++;
1263b54566f5c433764830c29c83151691d0034de094plougher
126404281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher	*targname = strndup(start, target - start);
1265b54566f5c433764830c29c83151691d0034de094plougher
12667f3c1887319ca4acff0787ed821628eb27c29f14Phillip Lougher	while(*target == '/')
12677f3c1887319ca4acff0787ed821628eb27c29f14Phillip Lougher		target ++;
12687f3c1887319ca4acff0787ed821628eb27c29f14Phillip Lougher
1269b54566f5c433764830c29c83151691d0034de094plougher	return target;
1270b54566f5c433764830c29c83151691d0034de094plougher}
1271b54566f5c433764830c29c83151691d0034de094plougher
1272b54566f5c433764830c29c83151691d0034de094plougher
12736ee88c6b5da9f7b3ea88ab7481db126efa01c8f4ploughervoid free_path(struct pathname *paths)
12746ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher{
12756ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	int i;
12766ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
12776ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	for(i = 0; i < paths->names; i++) {
12786ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths)
12796ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
12806ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		free(paths->name[i].name);
12816ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].preg) {
12826ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			regfree(paths->name[i].preg);
12836ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free(paths->name[i].preg);
12846ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		}
12856ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	}
12866ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
12876ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	free(paths);
12886ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher}
12896ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
12906ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
12914dba330d7b952f2f044d38e342e2ae3ea78910d6plougherstruct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
1292b54566f5c433764830c29c83151691d0034de094plougher{
129304281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher	char *targname;
12944dba330d7b952f2f044d38e342e2ae3ea78910d6plougher	int i, error;
129571add234b27054974d5e29f95b3fab3072792a62plougher
1296b7bb000643cd21c615a0366a7365441aa9c433f2plougher	TRACE("add_path: adding \"%s\" extract file\n", target);
1297b7bb000643cd21c615a0366a7365441aa9c433f2plougher
129804281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher	target = get_component(target, &targname);
129971add234b27054974d5e29f95b3fab3072792a62plougher
130071add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
13019dd4507fac1c96098eda8abe699a813a59451633plougher		paths = malloc(sizeof(struct pathname));
13029dd4507fac1c96098eda8abe699a813a59451633plougher		if(paths == NULL)
13034dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			EXIT_UNSQUASH("failed to allocate paths\n");
13044dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
130571add234b27054974d5e29f95b3fab3072792a62plougher		paths->names = 0;
130671add234b27054974d5e29f95b3fab3072792a62plougher		paths->name = NULL;
130771add234b27054974d5e29f95b3fab3072792a62plougher	}
130871add234b27054974d5e29f95b3fab3072792a62plougher
130971add234b27054974d5e29f95b3fab3072792a62plougher	for(i = 0; i < paths->names; i++)
131071add234b27054974d5e29f95b3fab3072792a62plougher		if(strcmp(paths->name[i].name, targname) == 0)
131171add234b27054974d5e29f95b3fab3072792a62plougher			break;
131271add234b27054974d5e29f95b3fab3072792a62plougher
13136ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	if(i == paths->names) {
1314d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1315d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * allocate new name entry
1316d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
131771add234b27054974d5e29f95b3fab3072792a62plougher		paths->names ++;
1318d4204758f77acb5a371fa1487a755b76a05d5476plougher		paths->name = realloc(paths->name, (i + 1) *
1319d4204758f77acb5a371fa1487a755b76a05d5476plougher			sizeof(struct path_entry));
1320fd628227871aecb36bb2b4f9c7f664f731510cdeplougher		if(paths->name == NULL)
1321fd628227871aecb36bb2b4f9c7f664f731510cdeplougher			EXIT_UNSQUASH("Out of memory in add_path\n");
132204281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher		paths->name[i].name = targname;
13236ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		paths->name[i].paths = NULL;
13244dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		if(use_regex) {
13254dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = malloc(sizeof(regex_t));
13261f3cc42a2f77966d321a38d1709eba26f71104bdplougher			if(paths->name[i].preg == NULL)
13271f3cc42a2f77966d321a38d1709eba26f71104bdplougher				EXIT_UNSQUASH("Out of memory in add_path\n");
1328d4204758f77acb5a371fa1487a755b76a05d5476plougher			error = regcomp(paths->name[i].preg, targname,
1329d4204758f77acb5a371fa1487a755b76a05d5476plougher				REG_EXTENDED|REG_NOSUB);
1330545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			if(error) {
133162859d215e7f828ace8501f5863f0c3d8b48ebf3Phillip Lougher				char str[1024]; /* overflow safe */
13324dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
13334dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				regerror(error, paths->name[i].preg, str, 1024);
1334d4204758f77acb5a371fa1487a755b76a05d5476plougher				EXIT_UNSQUASH("invalid regex %s in export %s, "
1335c435240f52b78b0ef498118727ba8dad186db26bplougher					"because %s\n", targname, alltarget,
1336c435240f52b78b0ef498118727ba8dad186db26bplougher					str);
13374dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			}
13384dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		} else
13394dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = NULL;
13406ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
13416ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(target[0] == '\0')
1342d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1343d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * at leaf pathname component
1344d4204758f77acb5a371fa1487a755b76a05d5476plougher			*/
134571add234b27054974d5e29f95b3fab3072792a62plougher			paths->name[i].paths = NULL;
134671add234b27054974d5e29f95b3fab3072792a62plougher		else
1347d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1348d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * recurse adding child components
1349d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
13504dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].paths = add_path(NULL, target, alltarget);
13516ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	} else {
1352d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1353d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * existing matching entry
1354d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
135504281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher		free(targname);
135604281b2f978bb7b30aa1394129ea99d2d9c47d26Phillip Lougher
13576ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths == NULL) {
1358d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1359c435240f52b78b0ef498118727ba8dad186db26bplougher			 * No sub-directory which means this is the leaf
1360c435240f52b78b0ef498118727ba8dad186db26bplougher			 * component of a pre-existing extract which subsumes
1361c435240f52b78b0ef498118727ba8dad186db26bplougher			 * the extract currently being added, in which case stop
1362c435240f52b78b0ef498118727ba8dad186db26bplougher			 * adding components
1363d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
13646ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else if(target[0] == '\0') {
1365d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1366d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * at leaf pathname component and child components exist
1367c435240f52b78b0ef498118727ba8dad186db26bplougher			 * from more specific extracts, delete as they're
1368c435240f52b78b0ef498118727ba8dad186db26bplougher			 * subsumed by this extract
1369d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
13706ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
13716ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			paths->name[i].paths = NULL;
13726ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else
1373d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1374d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * recurse adding child components
1375d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
13766ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			add_path(paths->name[i].paths, target, alltarget);
137771add234b27054974d5e29f95b3fab3072792a62plougher	}
137871add234b27054974d5e29f95b3fab3072792a62plougher
137971add234b27054974d5e29f95b3fab3072792a62plougher	return paths;
138071add234b27054974d5e29f95b3fab3072792a62plougher}
13816ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
13826ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
1383a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *init_subdir()
138471add234b27054974d5e29f95b3fab3072792a62plougher{
13858372232d2460411adaa2299c32a0a88665e44902plougher	struct pathnames *new = malloc(sizeof(struct pathnames));
1386c5671cbe8dffaff7062ceb7b75f8d96c657a67b7plougher	if(new == NULL)
1387c5671cbe8dffaff7062ceb7b75f8d96c657a67b7plougher		EXIT_UNSQUASH("Out of memory in init_subdir\n");
1388a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	new->count = 0;
1389a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return new;
1390a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1391a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1392a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1393a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
1394a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
13953488d3bb3b89c394534ad2be909b661771a9581bplougher	if(paths->count % PATHS_ALLOC_SIZE == 0) {
1396d4204758f77acb5a371fa1487a755b76a05d5476plougher		paths = realloc(paths, sizeof(struct pathnames *) +
13973488d3bb3b89c394534ad2be909b661771a9581bplougher			(paths->count + PATHS_ALLOC_SIZE) *
13983488d3bb3b89c394534ad2be909b661771a9581bplougher			sizeof(struct pathname *));
13993488d3bb3b89c394534ad2be909b661771a9581bplougher		if(paths == NULL)
14003488d3bb3b89c394534ad2be909b661771a9581bplougher			EXIT_UNSQUASH("Out of memory in add_subdir\n");
14013488d3bb3b89c394534ad2be909b661771a9581bplougher	}
1402a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1403a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	paths->path[paths->count++] = path;
1404a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return paths;
1405a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1406a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1407a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1408a706f1b6bb48f288ecaf74e218ce20504bda52c6ploughervoid free_subdir(struct pathnames *paths)
1409a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1410a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free(paths);
1411a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1412a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1413a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1414a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherint matches(struct pathnames *paths, char *name, struct pathnames **new)
1415a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1416a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	int i, n;
141771add234b27054974d5e29f95b3fab3072792a62plougher
141871add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
141971add234b27054974d5e29f95b3fab3072792a62plougher		*new = NULL;
1420b54566f5c433764830c29c83151691d0034de094plougher		return TRUE;
142171add234b27054974d5e29f95b3fab3072792a62plougher	}
142271add234b27054974d5e29f95b3fab3072792a62plougher
1423a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = init_subdir();
1424a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1425a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	for(n = 0; n < paths->count; n++) {
1426a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		struct pathname *path = paths->path[n];
1427a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		for(i = 0; i < path->names; i++) {
1428a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			int match = use_regex ?
1429c435240f52b78b0ef498118727ba8dad186db26bplougher				regexec(path->name[i].preg, name, (size_t) 0,
1430c435240f52b78b0ef498118727ba8dad186db26bplougher				NULL, 0) == 0 : fnmatch(path->name[i].name,
1431c435240f52b78b0ef498118727ba8dad186db26bplougher				name, FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) ==
1432c435240f52b78b0ef498118727ba8dad186db26bplougher				0;
1433a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match && path->name[i].paths == NULL)
1434d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
1435d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * match on a leaf component, any subdirectories
1436c435240f52b78b0ef498118727ba8dad186db26bplougher				 * will implicitly match, therefore return an
1437c435240f52b78b0ef498118727ba8dad186db26bplougher				 * empty new search set
1438d4204758f77acb5a371fa1487a755b76a05d5476plougher				 */
1439a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				goto empty_set;
1440a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1441a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match)
1442d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
1443d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * match on a non-leaf component, add any
1444c435240f52b78b0ef498118727ba8dad186db26bplougher				 * subdirectories to the new set of
1445c435240f52b78b0ef498118727ba8dad186db26bplougher				 * subdirectories to scan for this name
1446d4204758f77acb5a371fa1487a755b76a05d5476plougher				 */
1447a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				*new = add_subdir(*new, path->name[i].paths);
1448a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		}
1449a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1450b54566f5c433764830c29c83151691d0034de094plougher
1451a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if((*new)->count == 0) {
1452d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
1453d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * no matching names found, delete empty search set, and return
1454d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * FALSE
1455d4204758f77acb5a371fa1487a755b76a05d5476plougher		 */
1456a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(*new);
1457a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		*new = NULL;
1458a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		return FALSE;
1459a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1460a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1461d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
14620a0d045642e8e413f90b770539193d3fd1522786plougher	 * one or more matches with sub-directories found (no leaf matches),
14630a0d045642e8e413f90b770539193d3fd1522786plougher	 * return new search set and return TRUE
14640a0d045642e8e413f90b770539193d3fd1522786plougher	 */
1465a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
1466a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1467a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherempty_set:
1468d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
1469d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * found matching leaf exclude, return empty search set and return TRUE
1470d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
1471a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free_subdir(*new);
1472a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = NULL;
1473a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
1474b54566f5c433764830c29c83151691d0034de094plougher}
1475b54566f5c433764830c29c83151691d0034de094plougher
1476b54566f5c433764830c29c83151691d0034de094plougher
1477b807ab3497c01a49fed6f9daafce3bfc599a9421ploughervoid pre_scan(char *parent_name, unsigned int start_block, unsigned int offset,
1478d4204758f77acb5a371fa1487a755b76a05d5476plougher	struct pathnames *paths)
1479eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
1480eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	unsigned int type;
1481454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher	char *name;
1482eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct pathnames *new;
1483eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
1484eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1485eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1486cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher	if(dir == NULL)
1487cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher		return;
1488cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher
1489eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
1490eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		struct inode *i;
1491454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher		char *pathname;
1492454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher		int res;
1493eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1494d4204758f77acb5a371fa1487a755b76a05d5476plougher		TRACE("pre_scan: name %s, start_block %d, offset %d, type %d\n",
1495d4204758f77acb5a371fa1487a755b76a05d5476plougher			name, start_block, offset, type);
1496eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1497eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(!matches(paths, name, &new))
1498eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			continue;
1499eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1500454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher		res = asprintf(&pathname, "%s/%s", parent_name, name);
1501454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher		if(res == -1)
1502454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher			EXIT_UNSQUASH("asprintf failed in dir_scan\n");
1503eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1504eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(type == SQUASHFS_DIR_TYPE)
1505eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			pre_scan(parent_name, start_block, offset, new);
1506eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		else if(new == NULL) {
1507d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(type == SQUASHFS_FILE_TYPE ||
1508d4204758f77acb5a371fa1487a755b76a05d5476plougher					type == SQUASHFS_LREG_TYPE) {
1509312e50b7b8c9dd39577657bd3d79fcedf6e91a1bplougher				i = s_ops.read_inode(start_block, offset);
1510eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				if(created_inode[i->inode_number - 1] == NULL) {
1511d4204758f77acb5a371fa1487a755b76a05d5476plougher					created_inode[i->inode_number - 1] =
1512d4204758f77acb5a371fa1487a755b76a05d5476plougher						(char *) i;
1513d4204758f77acb5a371fa1487a755b76a05d5476plougher					total_blocks += (i->data +
1514d4204758f77acb5a371fa1487a755b76a05d5476plougher						(block_size - 1)) >> block_log;
1515eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
1516eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				total_files ++;
1517eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			}
1518eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			total_inodes ++;
1519eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		}
1520eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1521eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		free_subdir(new);
1522454c96fede0c4c424308744cbbf861df17b28f73Phillip Lougher		free(pathname);
1523eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
1524eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1525eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	squashfs_closedir(dir);
1526eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
1527eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1528eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
1529a2cff53655359b044ea88baa76cb16d1c8f44d2aploughervoid dir_scan(char *parent_name, unsigned int start_block, unsigned int offset,
1530d4204758f77acb5a371fa1487a755b76a05d5476plougher	struct pathnames *paths)
1531443c15812032991c98b33b5424b17bcd55fe3575plougher{
1532443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int type;
1533d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher	char *name;
1534a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *new;
1535eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
1536eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
1537443c15812032991c98b33b5424b17bcd55fe3575plougher
1538cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher	if(dir == NULL) {
1539cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher		ERROR("dir_scan: failed to read directory %s, skipping\n",
1540cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher			parent_name);
1541cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher		return;
1542cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher	}
1543cc7cea5b0d004fbaaf5e1060e6ed0fa9367e7ef0Phillip Lougher
1544eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(lsonly || info)
1545eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		print_filename(parent_name, i);
1546eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
15472c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher	if(!lsonly) {
15482c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		/*
15492c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		 * Make directory with default User rwx permissions rather than
15502c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		 * the permissions from the filesystem, as these may not have
15512c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		 * write/execute permission.  These are fixed up later in
15522c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		 * set_attributes().
15532c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		 */
15542c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		int res = mkdir(parent_name, S_IRUSR|S_IWUSR|S_IXUSR);
15552c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		if(res == -1) {
15562c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			/*
15572c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 * Skip directory if mkdir fails, unless we're
15582c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 * forcing and the error is -EEXIST
15592c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 */
15602c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			if(!force || errno != EEXIST) {
15612c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher				ERROR("dir_scan: failed to make directory %s, "
15622c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher					"because %s\n", parent_name,
15632c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher					strerror(errno));
15642c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher				squashfs_closedir(dir);
15652c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher				return;
15662c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			}
15672c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher
15682c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			/*
15692c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 * Try to change permissions of existing directory so
15702c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 * that we can write to it
15712c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			 */
15722c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			res = chmod(parent_name, S_IRUSR|S_IWUSR|S_IXUSR);
15732c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			if (res == -1)
15742c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher				ERROR("dir_scan: failed to change permissions "
15752c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher					"for directory %s, because %s\n",
15762c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher					parent_name, strerror(errno));
15772c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		}
157885917a285edbd4bb78f1b245f66c634d1e0d4029plougher	}
1579443c15812032991c98b33b5424b17bcd55fe3575plougher
1580443c15812032991c98b33b5424b17bcd55fe3575plougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
1581d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher		char *pathname;
1582d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher		int res;
1583d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher
1584d4204758f77acb5a371fa1487a755b76a05d5476plougher		TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n",
1585d4204758f77acb5a371fa1487a755b76a05d5476plougher			name, start_block, offset, type);
1586b54566f5c433764830c29c83151691d0034de094plougher
158771add234b27054974d5e29f95b3fab3072792a62plougher
158871add234b27054974d5e29f95b3fab3072792a62plougher		if(!matches(paths, name, &new))
1589b54566f5c433764830c29c83151691d0034de094plougher			continue;
1590b54566f5c433764830c29c83151691d0034de094plougher
1591d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher		res = asprintf(&pathname, "%s/%s", parent_name, name);
1592d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher		if(res == -1)
1593d27d51b4bc39e050392303009e08273d9f38bdccPhillip Lougher			EXIT_UNSQUASH("asprintf failed in dir_scan\n");
1594fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
1595fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher		if(type == SQUASHFS_DIR_TYPE) {
159671add234b27054974d5e29f95b3fab3072792a62plougher			dir_scan(pathname, start_block, offset, new);
1597fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher			free(pathname);
1598fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher		} else if(new == NULL) {
1599fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher			update_info(pathname);
1600fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher
1601312e50b7b8c9dd39577657bd3d79fcedf6e91a1bplougher			i = s_ops.read_inode(start_block, offset);
16026f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
16036f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(lsonly || info)
16046f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				print_filename(pathname, i);
16056f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
1606559bfb898c92e302b18b975927163eb9e49bfbd2Phillip Lougher			if(!lsonly)
16076f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				create_inode(pathname, i);
1608427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher
1609d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(i->type == SQUASHFS_SYMLINK_TYPE ||
1610d4204758f77acb5a371fa1487a755b76a05d5476plougher					i->type == SQUASHFS_LSYMLINK_TYPE)
1611427e2790c9ae74e2ff2c25e80a469cee0bbcae44plougher				free(i->symlink);
1612fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher		} else
1613fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher			free(pathname);
1614a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1615a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(new);
1616443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1617443c15812032991c98b33b5424b17bcd55fe3575plougher
1618074d3f1129eae914655f6637773488052bf22327rlougher	if(!lsonly)
16192c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		queue_dir(parent_name, dir);
1620443c15812032991c98b33b5424b17bcd55fe3575plougher
1621443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_closedir(dir);
1622443c15812032991c98b33b5424b17bcd55fe3575plougher	dir_count ++;
1623443c15812032991c98b33b5424b17bcd55fe3575plougher}
1624443c15812032991c98b33b5424b17bcd55fe3575plougher
1625443c15812032991c98b33b5424b17bcd55fe3575plougher
1626b624936abba03d38b7e9245c647339d8f6f34274ploughervoid squashfs_stat(char *source)
1627b624936abba03d38b7e9245c647339d8f6f34274plougher{
162827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	time_t mkfs_time = (time_t) sBlk.s.mkfs_time;
1629b624936abba03d38b7e9245c647339d8f6f34274plougher	char *mkfs_str = ctime(&mkfs_time);
1630b624936abba03d38b7e9245c647339d8f6f34274plougher
1631b624936abba03d38b7e9245c647339d8f6f34274plougher#if __BYTE_ORDER == __BIG_ENDIAN
1632d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n",
163327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.s_major == 4 ? "" : swap ? "little endian " :
163427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		"big endian ", sBlk.s.s_major, sBlk.s.s_minor, source);
1635b624936abba03d38b7e9245c647339d8f6f34274plougher#else
1636d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n",
163727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.s_major == 4 ? "" : swap ? "big endian " :
163827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		"little endian ", sBlk.s.s_major, sBlk.s.s_minor, source);
1639b624936abba03d38b7e9245c647339d8f6f34274plougher#endif
1640c766500607f1ea7494b8360409be3d8ea66f9761plougher
1641d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Creation or last append time %s", mkfs_str ? mkfs_str :
1642d4204758f77acb5a371fa1487a755b76a05d5476plougher		"failed to get time\n");
1643e5e5a7502f722fae4f057f49932fe4de2501f6e8plougher	printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n",
1644e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		sBlk.s.bytes_used / 1024.0, sBlk.s.bytes_used /
1645e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		(1024.0 * 1024.0));
1646c766500607f1ea7494b8360409be3d8ea66f9761plougher
16473fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher	if(sBlk.s.s_major == 4) {
1648e5e5a7502f722fae4f057f49932fe4de2501f6e8plougher		printf("Compression %s\n", comp->name);
1649c766500607f1ea7494b8360409be3d8ea66f9761plougher
16503fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher		if(SQUASHFS_COMP_OPTS(sBlk.s.flags)) {
1651b1b4fe22b339f73360c4e94e75ca46975c54bc06Phillip Lougher			char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned));
16523fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher			int bytes;
16533fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher
16543fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher			bytes = read_block(fd, sizeof(sBlk.s), NULL, 0, buffer);
16553fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher			if(bytes == 0) {
16563fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher				ERROR("Failed to read compressor options\n");
16573fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher				return;
16583fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher			}
16593fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher
16603fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher			compressor_display_options(comp, buffer, bytes);
16613fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher		}
16623fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher	}
16633fcced11c3e4b49b2b687010304b5156935a3b2cPhillip Lougher
166427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	printf("Block size %d\n", sBlk.s.block_size);
1665d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Filesystem is %sexportable via NFS\n",
166627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_EXPORTABLE(sBlk.s.flags) ? "" : "not ");
1667d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Inodes are %scompressed\n",
166827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_UNCOMPRESSED_INODES(sBlk.s.flags) ? "un" : "");
1669d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("Data is %scompressed\n",
167027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_UNCOMPRESSED_DATA(sBlk.s.flags) ? "un" : "");
1671c766500607f1ea7494b8360409be3d8ea66f9761plougher
16727ca09d1320cdc30a068f179b93ca5c141b55c395plougher	if(sBlk.s.s_major > 1) {
16737ca09d1320cdc30a068f179b93ca5c141b55c395plougher		if(SQUASHFS_NO_FRAGMENTS(sBlk.s.flags))
16747ca09d1320cdc30a068f179b93ca5c141b55c395plougher			printf("Fragments are not stored\n");
16757ca09d1320cdc30a068f179b93ca5c141b55c395plougher		else {
16767ca09d1320cdc30a068f179b93ca5c141b55c395plougher			printf("Fragments are %scompressed\n",
16777ca09d1320cdc30a068f179b93ca5c141b55c395plougher				SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.s.flags) ?
16787ca09d1320cdc30a068f179b93ca5c141b55c395plougher				"un" : "");
16799077fad8779e259fa03326b567644374e98ff171Phillip Lougher			printf("Always-use-fragments option is %sspecified\n",
16807ca09d1320cdc30a068f179b93ca5c141b55c395plougher				SQUASHFS_ALWAYS_FRAGMENTS(sBlk.s.flags) ? "" :
16817ca09d1320cdc30a068f179b93ca5c141b55c395plougher				"not ");
16827ca09d1320cdc30a068f179b93ca5c141b55c395plougher		}
16837ca09d1320cdc30a068f179b93ca5c141b55c395plougher	}
16847ca09d1320cdc30a068f179b93ca5c141b55c395plougher
1685de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher	if(sBlk.s.s_major == 4) {
1686de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher		if(SQUASHFS_NO_XATTRS(sBlk.s.flags))
1687de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher			printf("Xattrs are not stored\n");
1688de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher		else
1689de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher			printf("Xattrs are %scompressed\n",
1690de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher				SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.s.flags) ?
1691de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher				"un" : "");
1692de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher	}
1693de61cdcdf3e3edb6eb1c579ec9968c22f664c9f8plougher
1694ba95dd35ef0e9f618d926ddc1a595076adc23818plougher	if(sBlk.s.s_major < 4)
1695ba95dd35ef0e9f618d926ddc1a595076adc23818plougher			printf("Check data is %spresent in the filesystem\n",
1696ba95dd35ef0e9f618d926ddc1a595076adc23818plougher				SQUASHFS_CHECK_DATA(sBlk.s.flags) ? "" :
1697ba95dd35ef0e9f618d926ddc1a595076adc23818plougher				"not ");
1698c766500607f1ea7494b8360409be3d8ea66f9761plougher
169927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major > 1)
1700d4204758f77acb5a371fa1487a755b76a05d5476plougher		printf("Duplicates are %sremoved\n",
170127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			SQUASHFS_DUPLICATES(sBlk.s.flags) ? "" : "not ");
17020337de3977eec74e6a3d28e0d0863299246de8b7plougher	else
17030337de3977eec74e6a3d28e0d0863299246de8b7plougher		printf("Duplicates are removed\n");
1704c766500607f1ea7494b8360409be3d8ea66f9761plougher
170527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major > 1)
170627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		printf("Number of fragments %d\n", sBlk.s.fragments);
1707c766500607f1ea7494b8360409be3d8ea66f9761plougher
170827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	printf("Number of inodes %d\n", sBlk.s.inodes);
1709c766500607f1ea7494b8360409be3d8ea66f9761plougher
171027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major == 4)
171127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		printf("Number of ids %d\n", sBlk.s.no_ids);
17120f74340e3b68533339adc60f418ddf59fa188f61plougher	else {
17130f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of uids %d\n", sBlk.no_uids);
17140f74340e3b68533339adc60f418ddf59fa188f61plougher		printf("Number of gids %d\n", sBlk.no_guids);
17150f74340e3b68533339adc60f418ddf59fa188f61plougher	}
1716b624936abba03d38b7e9245c647339d8f6f34274plougher
171727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	TRACE("sBlk.s.inode_table_start 0x%llx\n", sBlk.s.inode_table_start);
171827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	TRACE("sBlk.s.directory_table_start 0x%llx\n",
171927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.directory_table_start);
1720c766500607f1ea7494b8360409be3d8ea66f9761plougher
17210ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher	if(sBlk.s.s_major > 1)
17220ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher		TRACE("sBlk.s.fragment_table_start 0x%llx\n\n",
17230ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher			sBlk.s.fragment_table_start);
17240ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher
17250ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher	if(sBlk.s.s_major > 2)
17260ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher		TRACE("sBlk.s.lookup_table_start 0x%llx\n\n",
17270ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher			sBlk.s.lookup_table_start);
17280ca44ca7b28597911258e0c27bd82feef73f2256Phillip Lougher
1729053da34003852e494400c1ade35b526e1821b576plougher	if(sBlk.s.s_major == 4) {
173027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		TRACE("sBlk.s.id_table_start 0x%llx\n", sBlk.s.id_table_start);
1731053da34003852e494400c1ade35b526e1821b576plougher		TRACE("sBlk.s.xattr_id_table_start 0x%llx\n",
1732053da34003852e494400c1ade35b526e1821b576plougher			sBlk.s.xattr_id_table_start);
1733053da34003852e494400c1ade35b526e1821b576plougher	} else {
17340f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.uid_start 0x%llx\n", sBlk.uid_start);
17350f74340e3b68533339adc60f418ddf59fa188f61plougher		TRACE("sBlk.guid_start 0x%llx\n", sBlk.guid_start);
17360f74340e3b68533339adc60f418ddf59fa188f61plougher	}
1737b624936abba03d38b7e9245c647339d8f6f34274plougher}
1738b624936abba03d38b7e9245c647339d8f6f34274plougher
1739b624936abba03d38b7e9245c647339d8f6f34274plougher
174059b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougherint check_compression(struct compressor *comp)
174159b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher{
174259b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	int res, bytes = 0;
174359b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned));
174459b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher
174559b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	if(!comp->supported) {
174659b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher		ERROR("Filesystem uses %s compression, this is "
174759b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher			"unsupported by this version\n", comp->name);
174859b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher		ERROR("Decompressors available:\n");
174959b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher		display_compressors("", "");
175059b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher		return 0;
175159b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	}
175259b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher
175359b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	/*
175459b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	 * Read compression options from disk if present, and pass to
175559b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	 * the compressor to ensure we know how to decompress a filesystem
175659b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	 * compressed with these compression options.
175759b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	 *
175859b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	 * Note, even if there is no compression options we still call the
175959b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	 * compressor because some compression options may be mandatory
176059b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	 * for some compressors.
176159b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	 */
176259b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	if(SQUASHFS_COMP_OPTS(sBlk.s.flags)) {
176359b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher		bytes = read_block(fd, sizeof(sBlk.s), NULL, 0, buffer);
176459b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher		if(bytes == 0) {
176559b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher			ERROR("Failed to read compressor options\n");
176659b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher			return 0;
176759b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher		}
176859b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	}
176959b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher
1770b642c41261e510bc2b314008d8b01b9902554e58Phillip Lougher	res = compressor_check_options(comp, sBlk.s.block_size, buffer, bytes);
177159b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher
177259b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	return res != -1;
177359b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher}
177459b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher
177559b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher
177602bc3bcabf2b219f63961f07293b83629948f026plougherint read_super(char *source)
1777443c15812032991c98b33b5424b17bcd55fe3575plougher{
17786490378e5b5e8dc058daf28423a7465699a6ba7bplougher	squashfs_super_block_3 sBlk_3;
177964e83fda63a1b8408ffbfa466e6c67b0de7a8c99plougher	struct squashfs_super_block sBlk_4;
17806490378e5b5e8dc058daf28423a7465699a6ba7bplougher
17816490378e5b5e8dc058daf28423a7465699a6ba7bplougher	/*
17826490378e5b5e8dc058daf28423a7465699a6ba7bplougher	 * Try to read a Squashfs 4 superblock
17836490378e5b5e8dc058daf28423a7465699a6ba7bplougher	 */
178464e83fda63a1b8408ffbfa466e6c67b0de7a8c99plougher	read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
17853306cb2b54a60a32664617118336ac141e1471b6plougher		&sBlk_4);
178654660e177ba40ab08ee2f3304b9f030eb5675677plougher	swap = sBlk_4.s_magic != SQUASHFS_MAGIC;
17876490378e5b5e8dc058daf28423a7465699a6ba7bplougher	SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4);
17886490378e5b5e8dc058daf28423a7465699a6ba7bplougher
1789d4204758f77acb5a371fa1487a755b76a05d5476plougher	if(sBlk_4.s_magic == SQUASHFS_MAGIC && sBlk_4.s_major == 4 &&
1790d4204758f77acb5a371fa1487a755b76a05d5476plougher			sBlk_4.s_minor == 0) {
17916490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.squashfs_opendir = squashfs_opendir_4;
17926490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_fragment = read_fragment_4;
17936490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_fragment_table = read_fragment_table_4;
17946490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_block_list = read_block_list_2;
17956490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_inode = read_inode_4;
17966490378e5b5e8dc058daf28423a7465699a6ba7bplougher		s_ops.read_uids_guids = read_uids_guids_4;
17976490378e5b5e8dc058daf28423a7465699a6ba7bplougher		memcpy(&sBlk, &sBlk_4, sizeof(sBlk_4));
1798efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
1799efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		/*
1800efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		 * Check the compression type
1801efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		 */
180227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		comp = lookup_compressor_id(sBlk.s.compression);
18036490378e5b5e8dc058daf28423a7465699a6ba7bplougher		return TRUE;
18046490378e5b5e8dc058daf28423a7465699a6ba7bplougher	}
18056490378e5b5e8dc058daf28423a7465699a6ba7bplougher
18066490378e5b5e8dc058daf28423a7465699a6ba7bplougher	/*
18076490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 * Not a Squashfs 4 superblock, try to read a squashfs 3 superblock
18086490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 * (compatible with 1 and 2 filesystems)
18096490378e5b5e8dc058daf28423a7465699a6ba7bplougher 	 */
181086561909d9ca51a4e4ce4efcfea30b41d1d08275plougher	read_fs_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block_3),
18113306cb2b54a60a32664617118336ac141e1471b6plougher		&sBlk_3);
1812443c15812032991c98b33b5424b17bcd55fe3575plougher
1813d4204758f77acb5a371fa1487a755b76a05d5476plougher	/*
1814d4204758f77acb5a371fa1487a755b76a05d5476plougher	 * Check it is a SQUASHFS superblock
1815d4204758f77acb5a371fa1487a755b76a05d5476plougher	 */
1816443c15812032991c98b33b5424b17bcd55fe3575plougher	swap = 0;
181721ee4773956342a8a7d0f14e430ae77ffbd10601plougher	if(sBlk_3.s_magic != SQUASHFS_MAGIC) {
181821ee4773956342a8a7d0f14e430ae77ffbd10601plougher		if(sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP) {
18197a5df5d70c02bdb5175a5b9301c2c9597a6a4937plougher			squashfs_super_block_3 sblk;
1820c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("Reading a different endian SQUASHFS filesystem "
1821c435240f52b78b0ef498118727ba8dad186db26bplougher				"on %s\n", source);
18226490378e5b5e8dc058daf28423a7465699a6ba7bplougher			SQUASHFS_SWAP_SUPER_BLOCK_3(&sblk, &sBlk_3);
18236490378e5b5e8dc058daf28423a7465699a6ba7bplougher			memcpy(&sBlk_3, &sblk, sizeof(squashfs_super_block_3));
1824443c15812032991c98b33b5424b17bcd55fe3575plougher			swap = 1;
1825443c15812032991c98b33b5424b17bcd55fe3575plougher		} else  {
1826c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("Can't find a SQUASHFS superblock on %s\n",
1827c435240f52b78b0ef498118727ba8dad186db26bplougher				source);
1828443c15812032991c98b33b5424b17bcd55fe3575plougher			goto failed_mount;
1829443c15812032991c98b33b5424b17bcd55fe3575plougher		}
1830443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1831443c15812032991c98b33b5424b17bcd55fe3575plougher
183227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.s_magic = sBlk_3.s_magic;
183327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.inodes = sBlk_3.inodes;
183427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.mkfs_time = sBlk_3.mkfs_time;
183527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.block_size = sBlk_3.block_size;
183627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.fragments = sBlk_3.fragments;
183727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.block_log = sBlk_3.block_log;
183827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.flags = sBlk_3.flags;
183927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.s_major = sBlk_3.s_major;
184027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.s_minor = sBlk_3.s_minor;
184127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.root_inode = sBlk_3.root_inode;
184227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.bytes_used = sBlk_3.bytes_used;
184327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.inode_table_start = sBlk_3.inode_table_start;
184427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.directory_table_start = sBlk_3.directory_table_start;
184527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.fragment_table_start = sBlk_3.fragment_table_start;
184627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.lookup_table_start = sBlk_3.lookup_table_start;
18476490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.no_uids = sBlk_3.no_uids;
18486490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.no_guids = sBlk_3.no_guids;
18496490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.uid_start = sBlk_3.uid_start;
18506490378e5b5e8dc058daf28423a7465699a6ba7bplougher	sBlk.guid_start = sBlk_3.guid_start;
185127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK;
18526490378e5b5e8dc058daf28423a7465699a6ba7bplougher
1853443c15812032991c98b33b5424b17bcd55fe3575plougher	/* Check the MAJOR & MINOR versions */
185427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	if(sBlk.s.s_major == 1 || sBlk.s.s_major == 2) {
185527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.bytes_used = sBlk_3.bytes_used_2;
18566490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.uid_start = sBlk_3.uid_start_2;
18576490378e5b5e8dc058daf28423a7465699a6ba7bplougher		sBlk.guid_start = sBlk_3.guid_start_2;
185827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.inode_table_start = sBlk_3.inode_table_start_2;
185927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		sBlk.s.directory_table_start = sBlk_3.directory_table_start_2;
186002bc3bcabf2b219f63961f07293b83629948f026plougher
186127c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		if(sBlk.s.s_major == 1) {
186227c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.block_size = sBlk_3.block_size_1;
186327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.fragment_table_start = sBlk.uid_start;
1864ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.squashfs_opendir = squashfs_opendir_1;
1865ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_1;
1866ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_block_list = read_block_list_1;
18676f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_1;
186879e700efc62527661ce140bd1013a2b60577917eplougher			s_ops.read_uids_guids = read_uids_guids_1;
1869ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		} else {
187027c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.fragment_table_start =
1871c435240f52b78b0ef498118727ba8dad186db26bplougher				sBlk_3.fragment_table_start_2;
1872ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.squashfs_opendir = squashfs_opendir_1;
1873ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment = read_fragment_2;
1874ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_2;
1875ed5124f016834932db2c63d60d259d846171c216plougher			s_ops.read_block_list = read_block_list_2;
18766f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_2;
187779e700efc62527661ce140bd1013a2b60577917eplougher			s_ops.read_uids_guids = read_uids_guids_1;
1878ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		}
187927c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	} else if(sBlk.s.s_major == 3) {
1880ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.squashfs_opendir = squashfs_opendir_3;
1881ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_fragment = read_fragment_3;
1882ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_fragment_table = read_fragment_table_3;
1883ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_block_list = read_block_list_2;
1884ed5124f016834932db2c63d60d259d846171c216plougher		s_ops.read_inode = read_inode_3;
188579e700efc62527661ce140bd1013a2b60577917eplougher		s_ops.read_uids_guids = read_uids_guids_1;
188602bc3bcabf2b219f63961f07293b83629948f026plougher	} else {
188727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		ERROR("Filesystem on %s is (%d:%d), ", source, sBlk.s.s_major,
188827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher			sBlk.s.s_minor);
18894c99cb7f458d8e1c598f1c80793daf3696c9b528plougher		ERROR("which is a later filesystem version than I support!\n");
1890443c15812032991c98b33b5424b17bcd55fe3575plougher		goto failed_mount;
1891443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1892443c15812032991c98b33b5424b17bcd55fe3575plougher
1893efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	/*
189499c8abf4de4297b3159355a0cefe9ad6f5182827plougher	 * 1.x, 2.x and 3.x filesystems use gzip compression.
1895efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	 */
1896efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher	comp = lookup_compressor("gzip");
1897443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1898443c15812032991c98b33b5424b17bcd55fe3575plougher
1899443c15812032991c98b33b5424b17bcd55fe3575plougherfailed_mount:
1900443c15812032991c98b33b5424b17bcd55fe3575plougher	return FALSE;
1901443c15812032991c98b33b5424b17bcd55fe3575plougher}
1902443c15812032991c98b33b5424b17bcd55fe3575plougher
1903443c15812032991c98b33b5424b17bcd55fe3575plougher
1904a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathname *process_extract_files(struct pathname *path, char *filename)
190571add234b27054974d5e29f95b3fab3072792a62plougher{
190671add234b27054974d5e29f95b3fab3072792a62plougher	FILE *fd;
1907afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher	char buffer[MAX_LINE + 1]; /* overflow safe */
1908e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher	char *name;
190971add234b27054974d5e29f95b3fab3072792a62plougher
191063e21ee4b795bb900f82c18e7b5c6f7369907360plougher	fd = fopen(filename, "r");
191163e21ee4b795bb900f82c18e7b5c6f7369907360plougher	if(fd == NULL)
1912e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		EXIT_UNSQUASH("Failed to open extract file \"%s\" because %s\n",
1913e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			filename, strerror(errno));
1914e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1915afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher	while(fgets(name = buffer, MAX_LINE + 1, fd) != NULL) {
1916e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		int len = strlen(name);
1917e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1918afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher		if(len == MAX_LINE && name[len - 1] != '\n')
1919e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			/* line too large */
1920e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			EXIT_UNSQUASH("Line too long when reading "
1921afbbfbf11bc846056666d073c94a9c8e84fcb1caPhillip Lougher				"extract file \"%s\", larger than %d "
192283847c1beb852a7b3f5906a0f4c90be659e46794Phillip Lougher				"bytes\n", filename, MAX_LINE);
1923e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1924e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		/*
1925e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		 * Remove '\n' terminator if it exists (the last line
1926e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		 * in the file may not be '\n' terminated)
1927e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		 */
1928e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		if(len && name[len - 1] == '\n')
1929e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			name[len - 1] = '\0';
1930e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1931e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		/* Skip any leading whitespace */
1932e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		while(isspace(*name))
1933e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			name ++;
1934e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1935e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		/* if comment line, skip */
1936e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		if(*name == '#')
1937e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			continue;
1938e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1939e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		/* check for initial backslash, to accommodate
1940e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		 * filenames with leading space or leading # character
1941e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		 */
1942e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		if(*name == '\\')
1943e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			name ++;
1944e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1945e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		/* if line is now empty after skipping characters, skip it */
1946e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		if(*name == '\0')
1947e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			continue;
194871add234b27054974d5e29f95b3fab3072792a62plougher
1949a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, name, name);
1950e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher	}
1951e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher
1952e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher	if(ferror(fd))
1953e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher		EXIT_UNSQUASH("Reading extract file \"%s\" failed because %s\n",
1954e4d5a8ee19193b451884e96b6405b6390e5b7c5ePhillip Lougher			filename, strerror(errno));
195571add234b27054974d5e29f95b3fab3072792a62plougher
195671add234b27054974d5e29f95b3fab3072792a62plougher	fclose(fd);
1957a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return path;
195871add234b27054974d5e29f95b3fab3072792a62plougher}
195971add234b27054974d5e29f95b3fab3072792a62plougher
196071add234b27054974d5e29f95b3fab3072792a62plougher
1961d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
1962d4204758f77acb5a371fa1487a755b76a05d5476plougher * reader thread.  This thread processes read requests queued by the
1963d4204758f77acb5a371fa1487a755b76a05d5476plougher * cache_get() routine.
1964d4204758f77acb5a371fa1487a755b76a05d5476plougher */
19658888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *reader(void *arg)
19668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
19678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
19688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct cache_entry *entry = queue_get(to_reader);
196986561909d9ca51a4e4ce4efcfea30b41d1d08275plougher		int res = read_fs_bytes(fd, entry->block,
19708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size),
19718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data);
19728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
19738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(res && SQUASHFS_COMPRESSED_BLOCK(entry->size))
1974d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
19753327bd9640ed579e8022b0e3889f71c342a64193Phillip Lougher			 * queue successfully read block to the inflate
1976c435240f52b78b0ef498118727ba8dad186db26bplougher			 * thread(s) for further processing
1977d4204758f77acb5a371fa1487a755b76a05d5476plougher 			 */
1978bee9e37353d957d1c4d8669ca4eba30c2b9df3f5Phillip Lougher			queue_put(to_inflate, entry);
19798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else
1980d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
1981d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * block has either been successfully read and is
1982d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * uncompressed, or an error has occurred, clear pending
1983c435240f52b78b0ef498118727ba8dad186db26bplougher			 * flag, set error appropriately, and wake up any
1984c435240f52b78b0ef498118727ba8dad186db26bplougher			 * threads waiting on this buffer
1985d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
19868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_ready(entry, !res);
19878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
19888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
19898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
19908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1991d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
1992d4204758f77acb5a371fa1487a755b76a05d5476plougher * writer thread.  This processes file write requests queued by the
1993d4204758f77acb5a371fa1487a755b76a05d5476plougher * write_file() routine.
1994d4204758f77acb5a371fa1487a755b76a05d5476plougher */
19958888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *writer(void *arg)
19968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
19978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int i;
19988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
19998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
20008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct squashfs_file *file = queue_get(to_writer);
20018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int file_fd;
200287f5e0e29e5f56516daaa51b1d36cde3d86a0f1fplougher		long long hole = 0;
200327636cb2cec37a68313f9eb825c0548245eecad0plougher		int failed = FALSE;
2004c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher		int error;
20058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
20068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(file == NULL) {
20078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			queue_put(from_writer, NULL);
20088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			continue;
20092c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher		} else if(file->fd == -1) {
20102c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			/* write attributes for directory file->pathname */
20112c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			set_attributes(file->pathname, file->mode, file->uid,
20122c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher				file->gid, file->time, file->xattr, TRUE);
20132c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			free(file->pathname);
20142c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			free(file);
20152c5e1385ccd9ee8e7d274331cc8a646948874538Phillip Lougher			continue;
20168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
20178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
20188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		TRACE("writer: regular file, blocks %d\n", file->blocks);
20198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
20208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		file_fd = file->fd;
20218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2022eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		for(i = 0; i < file->blocks; i++, cur_blocks ++) {
20238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			struct file_entry *block = queue_get(to_writer);
20248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
20258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(block->buffer == 0) { /* sparse file */
20268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole += block->size;
20278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				free(block);
20288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				continue;
20298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
20308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
20318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_wait(block->buffer);
203227636cb2cec37a68313f9eb825c0548245eecad0plougher
203327636cb2cec37a68313f9eb825c0548245eecad0plougher			if(block->buffer->error)
203427636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
203527636cb2cec37a68313f9eb825c0548245eecad0plougher
2036c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			if(failed)
2037c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				continue;
2038c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
2039c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			error = write_block(file_fd, block->buffer->data +
2040c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				block->offset, block->size, hole, file->sparse);
2041c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
2042c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher			if(error == FALSE) {
2043d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("writer: failed to write data block %d\n",
2044d4204758f77acb5a371fa1487a755b76a05d5476plougher					i);
204527636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
20468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
2047c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher
20488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			hole = 0;
20498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_put(block->buffer);
20508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			free(block);
20518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
20528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
205327636cb2cec37a68313f9eb825c0548245eecad0plougher		if(hole && failed == FALSE) {
2054d4204758f77acb5a371fa1487a755b76a05d5476plougher			/*
2055d4204758f77acb5a371fa1487a755b76a05d5476plougher			 * corner case for hole extending to end of file
2056d4204758f77acb5a371fa1487a755b76a05d5476plougher			 */
2057d4204758f77acb5a371fa1487a755b76a05d5476plougher			if(file->sparse == FALSE ||
2058d4204758f77acb5a371fa1487a755b76a05d5476plougher					lseek(file_fd, hole, SEEK_CUR) == -1) {
2059d4204758f77acb5a371fa1487a755b76a05d5476plougher				/*
2060d4204758f77acb5a371fa1487a755b76a05d5476plougher				 * for files which we don't want to write
2061c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * sparsely, or for broken lseeks which cannot
2062c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * seek beyond end of file, write_block will do
2063c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 * the right thing
2064c6e684fd0562ef5339ea2c0b3ce09aa6149708cdplougher				 */
20658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole --;
2066d4204758f77acb5a371fa1487a755b76a05d5476plougher				if(write_block(file_fd, "\0", 1, hole,
2067d4204758f77acb5a371fa1487a755b76a05d5476plougher						file->sparse) == FALSE) {
2068d4204758f77acb5a371fa1487a755b76a05d5476plougher					ERROR("writer: failed to write sparse "
2069d4204758f77acb5a371fa1487a755b76a05d5476plougher						"data block\n");
207027636cb2cec37a68313f9eb825c0548245eecad0plougher					failed = TRUE;
20718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				}
20728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			} else if(ftruncate(file_fd, file->file_size) == -1) {
2073d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("writer: failed to write sparse data "
2074d4204758f77acb5a371fa1487a755b76a05d5476plougher					"block\n");
207527636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
20768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
20778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
20788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2079cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		close_wake(file_fd);
208027636cb2cec37a68313f9eb825c0548245eecad0plougher		if(failed == FALSE)
2081d4204758f77acb5a371fa1487a755b76a05d5476plougher			set_attributes(file->pathname, file->mode, file->uid,
2082fdbbd7d7e595a227e0c259fa4afc872098c9e471plougher				file->gid, file->time, file->xattr, force);
208327636cb2cec37a68313f9eb825c0548245eecad0plougher		else {
208427636cb2cec37a68313f9eb825c0548245eecad0plougher			ERROR("Failed to write %s, skipping\n", file->pathname);
208527636cb2cec37a68313f9eb825c0548245eecad0plougher			unlink(file->pathname);
208627636cb2cec37a68313f9eb825c0548245eecad0plougher		}
208779df93becb68081effabebba3006c794be308598plougher		free(file->pathname);
20888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		free(file);
208927636cb2cec37a68313f9eb825c0548245eecad0plougher
20908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
20918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
20928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
20938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2094d4204758f77acb5a371fa1487a755b76a05d5476plougher/*
2095d4204758f77acb5a371fa1487a755b76a05d5476plougher * decompress thread.  This decompresses buffers queued by the read thread
2096d4204758f77acb5a371fa1487a755b76a05d5476plougher */
20973327bd9640ed579e8022b0e3889f71c342a64193Phillip Loughervoid *inflator(void *arg)
20988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
20998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	char tmp[block_size];
21008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
21018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
2102bee9e37353d957d1c4d8669ca4eba30c2b9df3f5Phillip Lougher		struct cache_entry *entry = queue_get(to_inflate);
2103efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		int error, res;
2104efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
2105b48442b2e37b3cb7efbffb032968f115eec7963cplougher		res = compressor_uncompress(comp, tmp, entry->data,
2106efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size), block_size,
2107efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			&error);
2108efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher
2109efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		if(res == -1)
2110efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			ERROR("%s uncompress failed with error code %d\n",
2111efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher				comp->name, error);
2112efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		else
2113efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher			memcpy(entry->data, tmp, res);
21148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2115d4204758f77acb5a371fa1487a755b76a05d5476plougher		/*
2116d4204758f77acb5a371fa1487a755b76a05d5476plougher		 * block has been either successfully decompressed, or an error
21178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * occurred, clear pending flag, set error appropriately and
2118d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 * wake up any threads waiting on this block
2119d4204758f77acb5a371fa1487a755b76a05d5476plougher 		 */
2120efda88fd6fbb19543a86b5f8d15b437bba8c4674plougher		cache_block_ready(entry, res == -1);
21218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
21228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
21238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
21248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2125eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid *progress_thread(void *arg)
2126eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
21279fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher	struct timespec requested_time, remaining;
21281b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct itimerval itimerval;
21291b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct winsize winsize;
21301b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
21311b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
213201b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher		if(isatty(STDOUT_FILENO))
213301b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher			ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
213401b4328a47a3c1ecd9ccc3ff6cde37ea973bb3c6plougher				"columns\n");
21351b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = 80;
21361b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	} else
21371b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = winsize.ws_col;
21381b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGWINCH, sigwinch_handler);
21391b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGALRM, sigalrm_handler);
21401b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
21411b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_sec = 0;
21421b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_usec = 250000;
21431b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_sec = 0;
21441b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_usec = 250000;
21451b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	setitimer(ITIMER_REAL, &itimerval, NULL);
2146eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
21479fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher	requested_time.tv_sec = 0;
21489fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher	requested_time.tv_nsec = 250000000;
2149eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2150eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(1) {
21519fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher		int res = nanosleep(&requested_time, &remaining);
21529fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher
21539fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher		if(res == -1 && errno != EINTR)
21549fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher			EXIT_UNSQUASH("nanosleep failed in progress thread\n");
21559fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher
21569fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher		if(progress_enabled) {
21579fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher			pthread_mutex_lock(&screen_mutex);
21581b42101056befe25b5f19d5b099e806a2ecee9cdplougher			progress_bar(sym_count + dev_count +
2159d4204758f77acb5a371fa1487a755b76a05d5476plougher				fifo_count + cur_blocks, total_inodes -
2160d4204758f77acb5a371fa1487a755b76a05d5476plougher				total_files + total_blocks, columns);
21619fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher			pthread_mutex_unlock(&screen_mutex);
21629fdf6bba5e8babda13fe13a08e3fe555bd41bfbdPhillip Lougher		}
2163eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
2164eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
2165eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2166eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
21678888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid initialise_threads(int fragment_buffer_size, int data_buffer_size)
21688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2169cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	struct rlimit rlim;
2170cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	int i, max_files, res;
21718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigset_t sigmask, old_mask;
21728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2173fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher	/* block SIGQUIT and SIGHUP, these are handled by the info thread */
21748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigemptyset(&sigmask);
21758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigaddset(&sigmask, SIGQUIT);
2176fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher	sigaddset(&sigmask, SIGHUP);
2177e0a306c5aca0aa2ca4d07593afaef79e360213a2Phillip Lougher	if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1)
21783642cef78fdbb9c4dc90cc6463443a6d005cfab2Phillip Lougher		EXIT_UNSQUASH("Failed to set signal mask in initialise_threads"
2179fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher			"\n");
2180fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher
2181fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher	/*
2182e0a306c5aca0aa2ca4d07593afaef79e360213a2Phillip Lougher	 * temporarily block these signals so the created sub-threads will
2183fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher	 * ignore them, ensuring the main thread handles them
2184fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher	 */
2185fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher	sigemptyset(&sigmask);
2186fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher	sigaddset(&sigmask, SIGINT);
2187fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher	sigaddset(&sigmask, SIGTERM);
2188e0a306c5aca0aa2ca4d07593afaef79e360213a2Phillip Lougher	if(pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
21893642cef78fdbb9c4dc90cc6463443a6d005cfab2Phillip Lougher		EXIT_UNSQUASH("Failed to set signal mask in initialise_threads"
2190c435240f52b78b0ef498118727ba8dad186db26bplougher			"\n");
21918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
21928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(processors == -1) {
21938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifndef linux
21948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int mib[2];
21958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		size_t len = sizeof(processors);
21968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
21978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[0] = CTL_HW;
21988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifdef HW_AVAILCPU
21998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_AVAILCPU;
22008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
22018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_NCPU;
22028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
22038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
22048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
2205d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("Failed to get number of available processors.  "
2206d4204758f77acb5a371fa1487a755b76a05d5476plougher				"Defaulting to 1\n");
22078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors = 1;
22088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
22098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
22109cc26b77a61fefdeb45f5c487c2bfdefd394b66fplougher		processors = sysconf(_SC_NPROCESSORS_ONLN);
22118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
22128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
22138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
221470f4aa66fa20ac3f86605e1330ccf241440e2cc3Phillip Lougher	if(add_overflow(processors, 3) ||
221570f4aa66fa20ac3f86605e1330ccf241440e2cc3Phillip Lougher			multiply_overflow(processors + 3, sizeof(pthread_t)))
221670f4aa66fa20ac3f86605e1330ccf241440e2cc3Phillip Lougher		EXIT_UNSQUASH("Processors too large\n");
221770f4aa66fa20ac3f86605e1330ccf241440e2cc3Phillip Lougher
22186697cff2155192a3e0c182a3cef046ebf215ac32plougher	thread = malloc((3 + processors) * sizeof(pthread_t));
22196697cff2155192a3e0c182a3cef046ebf215ac32plougher	if(thread == NULL)
22208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
22213327bd9640ed579e8022b0e3889f71c342a64193Phillip Lougher	inflator_thread = &thread[3];
22228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2223cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	/*
2224bee9e37353d957d1c4d8669ca4eba30c2b9df3f5Phillip Lougher	 * dimensioning the to_reader and to_inflate queues.  The size of
2225cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * these queues is directly related to the amount of block
2226cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * read-ahead possible.  To_reader queues block read requests to
2227bee9e37353d957d1c4d8669ca4eba30c2b9df3f5Phillip Lougher	 * the reader thread and to_inflate queues block decompression
22283327bd9640ed579e8022b0e3889f71c342a64193Phillip Lougher	 * requests to the inflate thread(s) (once the block has been read by
2229cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * the reader thread).  The amount of read-ahead is determined by
2230cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * the combined size of the data_block and fragment caches which
2231cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * determine the total number of blocks which can be "in flight"
2232cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * at any one time (either being read or being decompressed)
2233cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 *
2234cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * The maximum file open limit, however, affects the read-ahead
2235cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * possible, in that for normal sizes of the fragment and data block
2236cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * caches, where the incoming files have few data blocks or one fragment
2237cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * only, the file open limit is likely to be reached before the
2238cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * caches are full.  This means the worst case sizing of the combined
2239cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * sizes of the caches is unlikely to ever be necessary.  However, is is
2240cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * obvious read-ahead up to the data block cache size is always possible
2241cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * irrespective of the file open limit, because a single file could
2242cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * contain that number of blocks.
2243cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 *
2244cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * Choosing the size as "file open limit + data block cache size" seems
2245cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * to be a reasonable estimate.  We can reasonably assume the maximum
2246cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * likely read-ahead possible is data block cache size + one fragment
2247cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * per open file.
2248cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 *
2249cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * dimensioning the to_writer queue.  The size of this queue is
2250cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * directly related to the amount of block read-ahead possible.
2251bee9e37353d957d1c4d8669ca4eba30c2b9df3f5Phillip Lougher	 * However, unlike the to_reader and to_inflate queues, this is
2252cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * complicated by the fact the to_writer queue not only contains
2253cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * entries for fragments and data_blocks but it also contains
2254cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * file entries, one per open file in the read-ahead.
2255cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 *
2256cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * Choosing the size as "2 * (file open limit) +
2257cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * data block cache size" seems to be a reasonable estimate.
2258cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * We can reasonably assume the maximum likely read-ahead possible
2259cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * is data block cache size + one fragment per open file, and then
2260cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * we will have a file_entry for each open file.
2261cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 */
2262cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	res = getrlimit(RLIMIT_NOFILE, &rlim);
2263cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	if (res == -1) {
2264cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		ERROR("failed to get open file limit!  Defaulting to 1\n");
2265cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		rlim.rlim_cur = 1;
2266cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	}
2267cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
2268cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	if (rlim.rlim_cur != RLIM_INFINITY) {
2269cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		/*
2270cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		 * leave OPEN_FILE_MARGIN free (rlim_cur includes fds used by
2271cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		 * stdin, stdout, stderr and filesystem fd
2272cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		 */
2273cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		if (rlim.rlim_cur <= OPEN_FILE_MARGIN)
2274cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher			/* no margin, use minimum possible */
2275cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher			max_files = 1;
2276cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		else
2277cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher			max_files = rlim.rlim_cur - OPEN_FILE_MARGIN;
2278cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	} else
2279cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		max_files = -1;
2280cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
2281cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	/* set amount of available files for use by open_wait and close_wake */
2282cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	open_init(max_files);
2283cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
2284cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	/*
2285bee9e37353d957d1c4d8669ca4eba30c2b9df3f5Phillip Lougher	 * allocate to_reader, to_inflate and to_writer queues.  Set based on
2286cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * open file limit and cache size, unless open file limit is unlimited,
2287cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 * in which case set purely based on cache limits
22882b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 *
22892b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * In doing so, check that the user supplied values do not overflow
22902b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * a signed int
2291cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	 */
2292cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	if (max_files != -1) {
22932b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		if(add_overflow(data_buffer_size, max_files) ||
22942b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher				add_overflow(data_buffer_size, max_files * 2))
22952b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher			EXIT_UNSQUASH("Data queue size is too large\n");
22962b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
2297cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		to_reader = queue_init(max_files + data_buffer_size);
2298bee9e37353d957d1c4d8669ca4eba30c2b9df3f5Phillip Lougher		to_inflate = queue_init(max_files + data_buffer_size);
2299cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		to_writer = queue_init(max_files * 2 + data_buffer_size);
2300cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	} else {
23012b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		int all_buffers_size;
23022b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
23032b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		if(add_overflow(fragment_buffer_size, data_buffer_size))
23042b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher			EXIT_UNSQUASH("Data and fragment queues combined are"
23052b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher							" too large\n");
23062b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
23072b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		all_buffers_size = fragment_buffer_size + data_buffer_size;
23082b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
23092b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		if(add_overflow(all_buffers_size, all_buffers_size))
23102b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher			EXIT_UNSQUASH("Data and fragment queues combined are"
23112b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher							" too large\n");
2312cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
2313cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		to_reader = queue_init(all_buffers_size);
2314bee9e37353d957d1c4d8669ca4eba30c2b9df3f5Phillip Lougher		to_inflate = queue_init(all_buffers_size);
2315cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher		to_writer = queue_init(all_buffers_size * 2);
2316cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher	}
2317cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
23188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	from_writer = queue_init(1);
2319cb32e1c6050eba57d59bef5a35a75ffc19d3c699Phillip Lougher
23208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	fragment_cache = cache_init(block_size, fragment_buffer_size);
23218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data_cache = cache_init(block_size, data_buffer_size);
23228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[0], NULL, reader, NULL);
23238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[1], NULL, writer, NULL);
2324eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_create(&thread[2], NULL, progress_thread, NULL);
2325fec0a36c9b8a2c91c2930ea57b304299490ccedfPhillip Lougher	init_info();
23268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&fragment_mutex, NULL);
23278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(i = 0; i < processors; i++) {
23293327bd9640ed579e8022b0e3889f71c342a64193Phillip Lougher		if(pthread_create(&inflator_thread[i], NULL, inflator, NULL) !=
2330c435240f52b78b0ef498118727ba8dad186db26bplougher				 0)
23318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("Failed to create thread\n");
23328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
23338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	printf("Parallel unsquashfs: Using %d processor%s\n", processors,
23358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors == 1 ? "" : "s");
23368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2337e0a306c5aca0aa2ca4d07593afaef79e360213a2Phillip Lougher	if(pthread_sigmask(SIG_SETMASK, &old_mask, NULL) == -1)
23383642cef78fdbb9c4dc90cc6463443a6d005cfab2Phillip Lougher		EXIT_UNSQUASH("Failed to set signal mask in initialise_threads"
2339c435240f52b78b0ef498118727ba8dad186db26bplougher			"\n");
23408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
23418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23431b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid enable_progress_bar()
23441b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
23451b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
2346ff53fc094fa4760f2e4d602fd14ad6aa7a97cbe9Phillip Lougher	progress_enabled = progress;
23471b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
23481b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
23491b42101056befe25b5f19d5b099e806a2ecee9cdplougher
23501b42101056befe25b5f19d5b099e806a2ecee9cdplougher
23511b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid disable_progress_bar()
23521b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
23531b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
2354ff53fc094fa4760f2e4d602fd14ad6aa7a97cbe9Phillip Lougher	if(progress_enabled) {
2355ff53fc094fa4760f2e4d602fd14ad6aa7a97cbe9Phillip Lougher		progress_bar(sym_count + dev_count + fifo_count + cur_blocks,
2356ff53fc094fa4760f2e4d602fd14ad6aa7a97cbe9Phillip Lougher			total_inodes - total_files + total_blocks, columns);
2357ff53fc094fa4760f2e4d602fd14ad6aa7a97cbe9Phillip Lougher		printf("\n");
2358ff53fc094fa4760f2e4d602fd14ad6aa7a97cbe9Phillip Lougher	}
23591b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_enabled = FALSE;
23601b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
23611b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
23621b42101056befe25b5f19d5b099e806a2ecee9cdplougher
23631b42101056befe25b5f19d5b099e806a2ecee9cdplougher
23640100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Loughervoid progressbar_error(char *fmt, ...)
23650100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher{
23660100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	va_list ap;
23670100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
23680100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	pthread_mutex_lock(&screen_mutex);
23690100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
23700100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	if(progress_enabled)
23710100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher		fprintf(stderr, "\n");
23720100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
23730100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	va_start(ap, fmt);
23740100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	vfprintf(stderr, fmt, ap);
23750100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	va_end(ap);
23760100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
23770100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	pthread_mutex_unlock(&screen_mutex);
23780100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher}
23790100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
23800100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
23810100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Loughervoid progressbar_info(char *fmt, ...)
23820100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher{
23830100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	va_list ap;
23840100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
23850100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	pthread_mutex_lock(&screen_mutex);
23860100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
23870100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	if(progress_enabled)
23880100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher		printf("\n");
23890100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
23900100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	va_start(ap, fmt);
23910100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	vprintf(fmt, ap);
23920100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	va_end(ap);
23930100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
23940100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher	pthread_mutex_unlock(&screen_mutex);
23950100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher}
23960100fed4ec712daba9a0009c47f6e8390da5bd93Phillip Lougher
2397eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns)
2398eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
2399eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	char rotate_list[] = { '|', '/', '-', '\\' };
2400b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	int max_digits, used, hashes, spaces;
2401dce832998340bea4236fddb5ba1525121044ce18plougher	static int tty = -1;
2402eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2403b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	if(max == 0)
2404b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher		return;
2405b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher
2406b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	max_digits = floor(log10(max)) + 1;
2407b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	used = max_digits * 2 + 11;
2408b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	hashes = (current * (columns - used)) / max;
2409b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher	spaces = columns - used - hashes;
2410b5a32017ae5c8f1b4d00b296e8f6fef140e8dd99plougher
2411eaf639366792995c36ae7295bddf534f6f416643plougher	if((current > max) || (columns - used < 0))
2412eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		return;
2413eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2414dce832998340bea4236fddb5ba1525121044ce18plougher	if(tty == -1)
2415dce832998340bea4236fddb5ba1525121044ce18plougher		tty = isatty(STDOUT_FILENO);
2416dce832998340bea4236fddb5ba1525121044ce18plougher	if(!tty) {
2417dce832998340bea4236fddb5ba1525121044ce18plougher		static long long previous = -1;
2418dce832998340bea4236fddb5ba1525121044ce18plougher
24190a0d045642e8e413f90b770539193d3fd1522786plougher		/*
24200a0d045642e8e413f90b770539193d3fd1522786plougher		 * Updating much more frequently than this results in huge
24210a0d045642e8e413f90b770539193d3fd1522786plougher		 * log files.
24220a0d045642e8e413f90b770539193d3fd1522786plougher		 */
2423dce832998340bea4236fddb5ba1525121044ce18plougher		if((current % 100) != 0 && current != max)
2424dce832998340bea4236fddb5ba1525121044ce18plougher			return;
2425dce832998340bea4236fddb5ba1525121044ce18plougher		/* Don't update just to rotate the spinner. */
2426dce832998340bea4236fddb5ba1525121044ce18plougher		if(current == previous)
2427dce832998340bea4236fddb5ba1525121044ce18plougher			return;
2428dce832998340bea4236fddb5ba1525121044ce18plougher		previous = current;
2429dce832998340bea4236fddb5ba1525121044ce18plougher	}
2430dce832998340bea4236fddb5ba1525121044ce18plougher
2431eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("\r[");
2432eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2433eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while (hashes --)
2434eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar('=');
2435eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2436eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	putchar(rotate_list[rotate]);
2437eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2438eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(spaces --)
2439eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar(' ');
2440eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2441eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("] %*lld/%*lld", max_digits, current, max_digits, max);
2442eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf(" %3lld%%", current * 100 / max);
2443eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	fflush(stdout);
2444eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
2445eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2446eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
24472b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougherint parse_number(char *arg, int *res)
24482b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher{
24492b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	char *b;
24502b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	long number = strtol(arg, &b, 10);
24512b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
24522b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	/* check for trailing junk after number */
24532b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(*b != '\0')
24542b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		return 0;
24552b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
24567f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	/*
24577f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 * check for strtol underflow or overflow in conversion.
24587f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 * Note: strtol can validly return LONG_MIN and LONG_MAX
24597f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 * if the user entered these values, but, additional code
24607f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 * to distinguish this scenario is unnecessary, because for
24617f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 * our purposes LONG_MIN and LONG_MAX are too large anyway
24627f1f61927a265b3c32f73afec110807b43dc1193Phillip Lougher	 */
24632b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(number == LONG_MIN || number == LONG_MAX)
24642b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		return 0;
24652b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
24662b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	/* reject negative numbers as invalid */
24672b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(number < 0)
24682b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		return 0;
24692b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
24702b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	/* check if long result will overflow signed int */
24712b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(number > INT_MAX)
24722b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		return 0;
24732b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
24742b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	*res = number;
24752b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	return 1;
24762b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher}
24772b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
24782b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
2479443c15812032991c98b33b5424b17bcd55fe3575plougher#define VERSION() \
2480af304198183f3651ffbab317906dac1024ab61a5Phillip Lougher	printf("unsquashfs version 4.3 (2014/05/12)\n");\
2481cc06495ccafaf9bb7f3d078dee22f2e3b1af471cPhillip Lougher	printf("copyright (C) 2014 Phillip Lougher "\
248283d42a3fc898962aa1f1e8387f2ccb1114e0d294Phillip Lougher		"<phillip@squashfs.org.uk>\n\n");\
2483e3206fad5b70e7e0527db2a627ad26616a8a2429plougher    	printf("This program is free software; you can redistribute it and/or"\
2484d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
2485e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("modify it under the terms of the GNU General Public License"\
2486d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
2487e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("as published by the Free Software Foundation; either version "\
2488e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		"2,\n");\
2489e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("or (at your option) any later version.\n\n");\
2490e3206fad5b70e7e0527db2a627ad26616a8a2429plougher	printf("This program is distributed in the hope that it will be "\
2491e3206fad5b70e7e0527db2a627ad26616a8a2429plougher		"useful,\n");\
2492d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of"\
2493d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
2494d4204758f77acb5a371fa1487a755b76a05d5476plougher	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the"\
2495d4204758f77acb5a371fa1487a755b76a05d5476plougher		"\n");\
2496443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("GNU General Public License for more details.\n");
2497443c15812032991c98b33b5424b17bcd55fe3575plougherint main(int argc, char *argv[])
2498443c15812032991c98b33b5424b17bcd55fe3575plougher{
2499443c15812032991c98b33b5424b17bcd55fe3575plougher	char *dest = "squashfs-root";
2500b624936abba03d38b7e9245c647339d8f6f34274plougher	int i, stat_sys = FALSE, version = FALSE;
2501545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	int n;
2502a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *paths = NULL;
2503a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathname *path = NULL;
2504e1542da6a3f99db8dc60b5cad891547e047861b7Phillip Lougher	long long directory_table_end;
2505ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int fragment_buffer_size = FRAGMENT_BUFFER_DEFAULT;
2506ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int data_buffer_size = DATA_BUFFER_DEFAULT;
2507443c15812032991c98b33b5424b17bcd55fe3575plougher
25081b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_init(&screen_mutex, NULL);
2509545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	root_process = geteuid() == 0;
2510545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	if(root_process)
25119dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		umask(0);
25129dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
2513443c15812032991c98b33b5424b17bcd55fe3575plougher	for(i = 1; i < argc; i++) {
2514443c15812032991c98b33b5424b17bcd55fe3575plougher		if(*argv[i] != '-')
2515443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
2516d4204758f77acb5a371fa1487a755b76a05d5476plougher		if(strcmp(argv[i], "-version") == 0 ||
2517d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-v") == 0) {
2518443c15812032991c98b33b5424b17bcd55fe3575plougher			VERSION();
2519443c15812032991c98b33b5424b17bcd55fe3575plougher			version = TRUE;
2520d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-info") == 0 ||
2521d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-i") == 0)
2522443c15812032991c98b33b5424b17bcd55fe3575plougher			info = TRUE;
2523c435240f52b78b0ef498118727ba8dad186db26bplougher		else if(strcmp(argv[i], "-ls") == 0 ||
2524c435240f52b78b0ef498118727ba8dad186db26bplougher				strcmp(argv[i], "-l") == 0)
2525443c15812032991c98b33b5424b17bcd55fe3575plougher			lsonly = TRUE;
2526d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-no-progress") == 0 ||
2527d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-n") == 0)
2528296d7d8a68e33341d68f4354b5e1fe2f3aa275a6plougher			progress = FALSE;
252931638061a6de0cb89093672aa71ddeb42f2eb28aplougher		else if(strcmp(argv[i], "-no-xattrs") == 0 ||
253031638061a6de0cb89093672aa71ddeb42f2eb28aplougher				strcmp(argv[i], "-no") == 0)
253131638061a6de0cb89093672aa71ddeb42f2eb28aplougher			no_xattrs = TRUE;
2532df9d38a515489c2c573754ad81abd230dfd8b1f0plougher		else if(strcmp(argv[i], "-xattrs") == 0 ||
2533df9d38a515489c2c573754ad81abd230dfd8b1f0plougher				strcmp(argv[i], "-x") == 0)
2534df9d38a515489c2c573754ad81abd230dfd8b1f0plougher			no_xattrs = FALSE;
2535498da46ad7e6bd0a1fac0ec81d85ce1ac56bf385Phillip Lougher		else if(strcmp(argv[i], "-user-xattrs") == 0 ||
2536498da46ad7e6bd0a1fac0ec81d85ce1ac56bf385Phillip Lougher				strcmp(argv[i], "-u") == 0) {
2537498da46ad7e6bd0a1fac0ec81d85ce1ac56bf385Phillip Lougher			user_xattrs = TRUE;
2538498da46ad7e6bd0a1fac0ec81d85ce1ac56bf385Phillip Lougher			no_xattrs = FALSE;
2539498da46ad7e6bd0a1fac0ec81d85ce1ac56bf385Phillip Lougher		} else if(strcmp(argv[i], "-dest") == 0 ||
2540d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-d") == 0) {
254171add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
2542d4204758f77acb5a371fa1487a755b76a05d5476plougher				fprintf(stderr, "%s: -dest missing filename\n",
2543d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
254471add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
254571add234b27054974d5e29f95b3fab3072792a62plougher			}
2546443c15812032991c98b33b5424b17bcd55fe3575plougher			dest = argv[i];
2547d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-processors") == 0 ||
2548d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-p") == 0) {
2549c435240f52b78b0ef498118727ba8dad186db26bplougher			if((++i == argc) ||
25502c7ffbdfb7ef17a2032864e074a43d00631eeb8ePhillip Lougher					!parse_number(argv[i],
25512c7ffbdfb7ef17a2032864e074a43d00631eeb8ePhillip Lougher						&processors)) {
2552d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -processors missing or invalid "
2553d4204758f77acb5a371fa1487a755b76a05d5476plougher					"processor number\n", argv[0]);
25540cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
25550cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
25560cf5c297bec42c7c220d2825f12f9499f2293279plougher			if(processors < 1) {
2557d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -processors should be 1 or larger\n",
2558d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
25590cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
25600cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
2561d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-data-queue") == 0 ||
2562d4204758f77acb5a371fa1487a755b76a05d5476plougher					 strcmp(argv[i], "-da") == 0) {
2563c435240f52b78b0ef498118727ba8dad186db26bplougher			if((++i == argc) ||
25642b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher					!parse_number(argv[i],
25652b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher						&data_buffer_size)) {
2566c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("%s: -data-queue missing or invalid "
2567c435240f52b78b0ef498118727ba8dad186db26bplougher					"queue size\n", argv[0]);
2568ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2569ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2570ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(data_buffer_size < 1) {
2571d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -data-queue should be 1 Mbyte or "
2572d4204758f77acb5a371fa1487a755b76a05d5476plougher					"larger\n", argv[0]);
2573ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2574ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2575d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-frag-queue") == 0 ||
2576d4204758f77acb5a371fa1487a755b76a05d5476plougher					strcmp(argv[i], "-fr") == 0) {
2577c435240f52b78b0ef498118727ba8dad186db26bplougher			if((++i == argc) ||
25782b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher					!parse_number(argv[i],
25792b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher						&fragment_buffer_size)) {
2580c435240f52b78b0ef498118727ba8dad186db26bplougher				ERROR("%s: -frag-queue missing or invalid "
2581c435240f52b78b0ef498118727ba8dad186db26bplougher					"queue size\n", argv[0]);
2582ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2583ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2584ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(fragment_buffer_size < 1) {
2585d4204758f77acb5a371fa1487a755b76a05d5476plougher				ERROR("%s: -frag-queue should be 1 Mbyte or "
2586d4204758f77acb5a371fa1487a755b76a05d5476plougher					"larger\n", argv[0]);
2587ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2588ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2589d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-force") == 0 ||
2590d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-f") == 0)
2591a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			force = TRUE;
2592d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-stat") == 0 ||
2593d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-s") == 0)
2594b624936abba03d38b7e9245c647339d8f6f34274plougher			stat_sys = TRUE;
2595d4204758f77acb5a371fa1487a755b76a05d5476plougher		else if(strcmp(argv[i], "-lls") == 0 ||
2596d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-ll") == 0) {
25979baf35a00f38816d2054deb70184943d0686d03eplougher			lsonly = TRUE;
25989baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
2599d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-linfo") == 0 ||
2600d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-li") == 0) {
26019baf35a00f38816d2054deb70184943d0686d03eplougher			info = TRUE;
26029baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
2603d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-ef") == 0 ||
2604d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-e") == 0) {
260571add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
2606d4204758f77acb5a371fa1487a755b76a05d5476plougher				fprintf(stderr, "%s: -ef missing filename\n",
2607d4204758f77acb5a371fa1487a755b76a05d5476plougher					argv[0]);
260871add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
260971add234b27054974d5e29f95b3fab3072792a62plougher			}
2610a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			path = process_extract_files(path, argv[i]);
2611d4204758f77acb5a371fa1487a755b76a05d5476plougher		} else if(strcmp(argv[i], "-regex") == 0 ||
2612d4204758f77acb5a371fa1487a755b76a05d5476plougher				strcmp(argv[i], "-r") == 0)
26134dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			use_regex = TRUE;
26144dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		else
2615b624936abba03d38b7e9245c647339d8f6f34274plougher			goto options;
2616443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2617443c15812032991c98b33b5424b17bcd55fe3575plougher
2618feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher	if(lsonly || info)
2619feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher		progress = FALSE;
2620feb4051fd2a6f1f5cc65df4c0e8b117800c016c9plougher
2621bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher#ifdef SQUASHFS_TRACE
2622ce2c9c3d3741fb0285f20c6da2d0c73efd3bfa35Phillip Lougher	/*
2623ce2c9c3d3741fb0285f20c6da2d0c73efd3bfa35Phillip Lougher	 * Disable progress bar if full debug tracing is enabled.
2624ce2c9c3d3741fb0285f20c6da2d0c73efd3bfa35Phillip Lougher	 * The progress bar in this case just gets in the way of the
2625ce2c9c3d3741fb0285f20c6da2d0c73efd3bfa35Phillip Lougher	 * debug trace output
2626ce2c9c3d3741fb0285f20c6da2d0c73efd3bfa35Phillip Lougher	 */
2627bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher	progress = FALSE;
2628bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher#endif
2629bfa6e0b4ecb0e0cf3d451d1a094bc88c88593f76plougher
2630443c15812032991c98b33b5424b17bcd55fe3575plougher	if(i == argc) {
2631443c15812032991c98b33b5424b17bcd55fe3575plougher		if(!version) {
2632443c15812032991c98b33b5424b17bcd55fe3575plougheroptions:
2633d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("SYNTAX: %s [options] filesystem [directories or "
2634d4204758f77acb5a371fa1487a755b76a05d5476plougher				"files to extract]\n", argv[0]);
2635d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-v[ersion]\t\tprint version, licence and "
2636d4204758f77acb5a371fa1487a755b76a05d5476plougher				"copyright information\n");
2637d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-d[est] <pathname>\tunsquash to <pathname>, "
2638d4204758f77acb5a371fa1487a755b76a05d5476plougher				"default \"squashfs-root\"\n");
2639c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-n[o-progress]\t\tdon't display the progress "
2640c435240f52b78b0ef498118727ba8dad186db26bplougher				"bar\n");
2641df9d38a515489c2c573754ad81abd230dfd8b1f0plougher			ERROR("\t-no[-xattrs]\t\tdon't extract xattrs in file system"
2642df9d38a515489c2c573754ad81abd230dfd8b1f0plougher				NOXOPT_STR"\n");
2643df9d38a515489c2c573754ad81abd230dfd8b1f0plougher			ERROR("\t-x[attrs]\t\textract xattrs in file system"
2644df9d38a515489c2c573754ad81abd230dfd8b1f0plougher				XOPT_STR "\n");
2645498da46ad7e6bd0a1fac0ec81d85ce1ac56bf385Phillip Lougher			ERROR("\t-u[ser-xattrs]\t\tonly extract user xattrs in "
2646498da46ad7e6bd0a1fac0ec81d85ce1ac56bf385Phillip Lougher				"file system.\n\t\t\t\tEnables extracting "
2647498da46ad7e6bd0a1fac0ec81d85ce1ac56bf385Phillip Lougher				"xattrs\n");
2648c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-p[rocessors] <number>\tuse <number> "
2649c435240f52b78b0ef498118727ba8dad186db26bplougher				"processors.  By default will use\n");
2650c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\tnumber of processors available\n");
2651c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-i[nfo]\t\t\tprint files as they are "
2652c435240f52b78b0ef498118727ba8dad186db26bplougher				"unsquashed\n");
2653c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-li[nfo]\t\tprint files as they are "
2654c435240f52b78b0ef498118727ba8dad186db26bplougher				"unsquashed with file\n");
2655c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\tattributes (like ls -l output)\n");
2656d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-l[s]\t\t\tlist filesystem, but don't unsquash"
2657d4204758f77acb5a371fa1487a755b76a05d5476plougher				"\n");
2658c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-ll[s]\t\t\tlist filesystem with file "
2659c435240f52b78b0ef498118727ba8dad186db26bplougher				"attributes (like\n");
2660c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\tls -l output), but don't unsquash\n");
2661c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-f[orce]\t\tif file already exists then "
2662c435240f52b78b0ef498118727ba8dad186db26bplougher				"overwrite\n");
2663d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-s[tat]\t\t\tdisplay filesystem superblock "
2664d4204758f77acb5a371fa1487a755b76a05d5476plougher				"information\n");
2665d4204758f77acb5a371fa1487a755b76a05d5476plougher			ERROR("\t-e[f] <extract file>\tlist of directories or "
2666d4204758f77acb5a371fa1487a755b76a05d5476plougher				"files to extract.\n\t\t\t\tOne per line\n");
2667c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-da[ta-queue] <size>\tSet data queue to "
2668c435240f52b78b0ef498118727ba8dad186db26bplougher				"<size> Mbytes.  Default %d\n\t\t\t\tMbytes\n",
2669d4204758f77acb5a371fa1487a755b76a05d5476plougher				DATA_BUFFER_DEFAULT);
26708bc376ba1f7110fb88989e5134b74aa8412fb00eplougher			ERROR("\t-fr[ag-queue] <size>\tSet fragment queue to "
2671d56f6723626a391b473c2c023b628abcd8ed31e3Phillip Lougher				"<size> Mbytes.  Default\n\t\t\t\t%d Mbytes\n",
2672d4204758f77acb5a371fa1487a755b76a05d5476plougher				FRAGMENT_BUFFER_DEFAULT);
2673c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t-r[egex]\t\ttreat extract names as POSIX "
2674c435240f52b78b0ef498118727ba8dad186db26bplougher				"regular expressions\n");
2675c435240f52b78b0ef498118727ba8dad186db26bplougher			ERROR("\t\t\t\trather than use the default shell "
2676c435240f52b78b0ef498118727ba8dad186db26bplougher				"wildcard\n\t\t\t\texpansion (globbing)\n");
2677076b053e2cce5c9172b4f385e866c2e606712a32plougher			ERROR("\nDecompressors available:\n");
2678076b053e2cce5c9172b4f385e866c2e606712a32plougher			display_compressors("", "");
2679443c15812032991c98b33b5424b17bcd55fe3575plougher		}
2680443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2681443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2682443c15812032991c98b33b5424b17bcd55fe3575plougher
268371add234b27054974d5e29f95b3fab3072792a62plougher	for(n = i + 1; n < argc; n++)
2684a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, argv[n], argv[n]);
2685b54566f5c433764830c29c83151691d0034de094plougher
2686443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fd = open(argv[i], O_RDONLY)) == -1) {
2687d4204758f77acb5a371fa1487a755b76a05d5476plougher		ERROR("Could not open %s, because %s\n", argv[i],
2688d4204758f77acb5a371fa1487a755b76a05d5476plougher			strerror(errno));
2689443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2690443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2691443c15812032991c98b33b5424b17bcd55fe3575plougher
269202bc3bcabf2b219f63961f07293b83629948f026plougher	if(read_super(argv[i]) == FALSE)
2693443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2694443c15812032991c98b33b5424b17bcd55fe3575plougher
2695b624936abba03d38b7e9245c647339d8f6f34274plougher	if(stat_sys) {
2696b624936abba03d38b7e9245c647339d8f6f34274plougher		squashfs_stat(argv[i]);
2697b624936abba03d38b7e9245c647339d8f6f34274plougher		exit(0);
2698b624936abba03d38b7e9245c647339d8f6f34274plougher	}
2699b624936abba03d38b7e9245c647339d8f6f34274plougher
270059b85a3abcbada8e2fdbfafb4c3dd2b91141d78fPhillip Lougher	if(!check_compression(comp))
2701f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher		exit(1);
2702f025ee7d93e3ce56f1fdbd0661a89172500ba168plougher
270327c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	block_size = sBlk.s.block_size;
270427c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	block_log = sBlk.s.block_log;
2705ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2706009263430d50ee32f3757c3c34d1f06262759f5dPhillip Lougher	/*
27072b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * Sanity check block size and block log.
27082b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 *
27092b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * Check they're within correct limits
27102b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 */
27112b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(block_size > SQUASHFS_FILE_MAX_SIZE ||
27122b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher					block_log > SQUASHFS_FILE_MAX_LOG)
27132b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		EXIT_UNSQUASH("Block size or block_log too large."
27142b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher			"  File system is corrupt.\n");
27152b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
27162b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	/*
27172b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * Check block_size and block_log match
27182b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 */
27192b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(block_size != (1 << block_log))
27202b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		EXIT_UNSQUASH("Block size and block_log do not match."
27212b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher			"  File system is corrupt.\n");
27222b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
27232b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	/*
2724009263430d50ee32f3757c3c34d1f06262759f5dPhillip Lougher	 * convert from queue size in Mbytes to queue size in
27252b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * blocks.
27262b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 *
27272b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * In doing so, check that the user supplied values do not
27282b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	 * overflow a signed int
2729009263430d50ee32f3757c3c34d1f06262759f5dPhillip Lougher	 */
27302b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(shift_overflow(fragment_buffer_size, 20 - block_log))
27312b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		EXIT_UNSQUASH("Fragment queue size is too large\n");
27322b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	else
27332b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		fragment_buffer_size <<= 20 - block_log;
27342b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
27352b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	if(shift_overflow(data_buffer_size, 20 - block_log))
27362b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		EXIT_UNSQUASH("Data queue size is too large\n");
27372b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher	else
27382b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher		data_buffer_size <<= 20 - block_log;
27392b1aa06131c7d8d4361d79172afb9594e66a7280Phillip Lougher
27408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	initialise_threads(fragment_buffer_size, data_buffer_size);
27418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
274244a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	fragment_data = malloc(block_size);
274344a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(fragment_data == NULL)
2744443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate fragment_data\n");
2745443c15812032991c98b33b5424b17bcd55fe3575plougher
274644a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	file_data = malloc(block_size);
274744a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(file_data == NULL)
2748443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate file_data");
2749443c15812032991c98b33b5424b17bcd55fe3575plougher
275044a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	data = malloc(block_size);
275144a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(data == NULL)
2752eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		EXIT_UNSQUASH("failed to allocate data\n");
2753443c15812032991c98b33b5424b17bcd55fe3575plougher
275444a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	created_inode = malloc(sBlk.s.inodes * sizeof(char *));
275544a6967088416c9bd6ee7165bde59c9ba5ccb704plougher	if(created_inode == NULL)
2756443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate created_inode\n");
2757443c15812032991c98b33b5424b17bcd55fe3575plougher
275827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	memset(created_inode, 0, sBlk.s.inodes * sizeof(char *));
2759443c15812032991c98b33b5424b17bcd55fe3575plougher
27601a7e7e871169a6cb6e3470a50b33db83830886e2plougher	if(s_ops.read_uids_guids() == FALSE)
27611a7e7e871169a6cb6e3470a50b33db83830886e2plougher		EXIT_UNSQUASH("failed to uid/gid table\n");
2762ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2763e1542da6a3f99db8dc60b5cad891547e047861b7Phillip Lougher	if(s_ops.read_fragment_table(&directory_table_end) == FALSE)
2764cce13b2f8f73a4224f9dcfe203c992a09f22c6bcplougher		EXIT_UNSQUASH("failed to read fragment table\n");
2765ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
27661ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher	if(read_inode_table(sBlk.s.inode_table_start,
27671ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher				sBlk.s.directory_table_start) == FALSE)
27681ed1b1bfa19e9edd0e59da61d9f4c99021fb0b67Phillip Lougher		EXIT_UNSQUASH("failed to read inode table\n");
2769ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2770e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher	if(read_directory_table(sBlk.s.directory_table_start,
2771e1542da6a3f99db8dc60b5cad891547e047861b7Phillip Lougher				directory_table_end) == FALSE)
2772e89dabed981f39b54ca5046cfc2290dbe48961b5Phillip Lougher		EXIT_UNSQUASH("failed to read directory table\n");
2773443c15812032991c98b33b5424b17bcd55fe3575plougher
277431638061a6de0cb89093672aa71ddeb42f2eb28aplougher	if(no_xattrs)
277531638061a6de0cb89093672aa71ddeb42f2eb28aplougher		sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK;
277631638061a6de0cb89093672aa71ddeb42f2eb28aplougher
27778935dc25479321709c74c2f8214cf5365669100eplougher	if(read_xattrs_from_disk(fd, &sBlk.s) == 0)
27788935dc25479321709c74c2f8214cf5365669100eplougher		EXIT_UNSQUASH("failed to read the xattr table\n");
27798935dc25479321709c74c2f8214cf5365669100eplougher
2780a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if(path) {
2781a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = init_subdir();
2782a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = add_subdir(paths, path);
2783a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
2784a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
278527c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	pre_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode),
278627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths);
2787eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
278827c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	memset(created_inode, 0, sBlk.s.inodes * sizeof(char *));
27899b58176e667b67770569c9076a410b27aaa3bcf5plougher	inode_number = 1;
2790eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2791c435240f52b78b0ef498118727ba8dad186db26bplougher	printf("%d inodes (%d blocks) to write\n\n", total_inodes,
2792c435240f52b78b0ef498118727ba8dad186db26bplougher		total_inodes - total_files + total_blocks);
2793eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2794ff53fc094fa4760f2e4d602fd14ad6aa7a97cbe9Phillip Lougher	enable_progress_bar();
27951b42101056befe25b5f19d5b099e806a2ecee9cdplougher
279627c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher	dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode),
279727c4b6f7f6a33bf7711c0ee8cd563e4604dc5861plougher		SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths);
2798443c15812032991c98b33b5424b17bcd55fe3575plougher
27998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_put(to_writer, NULL);
28008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_get(from_writer);
28018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2802ff53fc094fa4760f2e4d602fd14ad6aa7a97cbe9Phillip Lougher	disable_progress_bar();
2803eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2804443c15812032991c98b33b5424b17bcd55fe3575plougher	if(!lsonly) {
2805443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("\n");
2806443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d files\n", file_count);
2807443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d directories\n", dir_count);
2808443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d symlinks\n", sym_count);
2809443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d devices\n", dev_count);
2810443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d fifos\n", fifo_count);
2811443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2812eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
28139dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	return 0;
2814443c15812032991c98b33b5424b17bcd55fe3575plougher}
2815