unsquashfs.c revision 1b42101056befe25b5f19d5b099e806a2ecee9cd
1443c15812032991c98b33b5424b17bcd55fe3575plougher/*
2443c15812032991c98b33b5424b17bcd55fe3575plougher * Unsquash a squashfs filesystem.  This is a highly compressed read only filesystem.
3443c15812032991c98b33b5424b17bcd55fe3575plougher *
48888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
579df93becb68081effabebba3006c794be308598plougher * Phillip Lougher <phillip@lougher.demon.co.uk>
6443c15812032991c98b33b5424b17bcd55fe3575plougher *
7443c15812032991c98b33b5424b17bcd55fe3575plougher * This program is free software; you can redistribute it and/or
8443c15812032991c98b33b5424b17bcd55fe3575plougher * modify it under the terms of the GNU General Public License
9443c15812032991c98b33b5424b17bcd55fe3575plougher * as published by the Free Software Foundation; either version 2,
10443c15812032991c98b33b5424b17bcd55fe3575plougher * or (at your option) any later version.
11443c15812032991c98b33b5424b17bcd55fe3575plougher *
12443c15812032991c98b33b5424b17bcd55fe3575plougher * This program is distributed in the hope that it will be useful,
13443c15812032991c98b33b5424b17bcd55fe3575plougher * but WITHOUT ANY WARRANTY; without even the implied warranty of
14443c15812032991c98b33b5424b17bcd55fe3575plougher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15443c15812032991c98b33b5424b17bcd55fe3575plougher * GNU General Public License for more details.
16443c15812032991c98b33b5424b17bcd55fe3575plougher *
17443c15812032991c98b33b5424b17bcd55fe3575plougher * You should have received a copy of the GNU General Public License
18443c15812032991c98b33b5424b17bcd55fe3575plougher * along with this program; if not, write to the Free Software
19443c15812032991c98b33b5424b17bcd55fe3575plougher * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20443c15812032991c98b33b5424b17bcd55fe3575plougher *
21443c15812032991c98b33b5424b17bcd55fe3575plougher * unsquash.c
22443c15812032991c98b33b5424b17bcd55fe3575plougher */
23443c15812032991c98b33b5424b17bcd55fe3575plougher
24ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher#define CONFIG_SQUASHFS_1_0_COMPATIBILITY
2502bc3bcabf2b219f63961f07293b83629948f026plougher#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
2602bc3bcabf2b219f63961f07293b83629948f026plougher
27443c15812032991c98b33b5424b17bcd55fe3575plougher#define TRUE 1
28443c15812032991c98b33b5424b17bcd55fe3575plougher#define FALSE 0
29443c15812032991c98b33b5424b17bcd55fe3575plougher#include <stdio.h>
30443c15812032991c98b33b5424b17bcd55fe3575plougher#include <sys/types.h>
31daa5fa85f54a8deaaaa294797fcc6be9ab7a597bplougher#include <unistd.h>
328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#include <stdlib.h>
33443c15812032991c98b33b5424b17bcd55fe3575plougher#include <sys/stat.h>
34443c15812032991c98b33b5424b17bcd55fe3575plougher#include <fcntl.h>
35443c15812032991c98b33b5424b17bcd55fe3575plougher#include <errno.h>
36443c15812032991c98b33b5424b17bcd55fe3575plougher#include <string.h>
37443c15812032991c98b33b5424b17bcd55fe3575plougher#include <zlib.h>
38443c15812032991c98b33b5424b17bcd55fe3575plougher#include <sys/mman.h>
39443c15812032991c98b33b5424b17bcd55fe3575plougher#include <utime.h>
40476dcb48b24efff22caa970f000e151f1b28918dplougher#include <pwd.h>
41476dcb48b24efff22caa970f000e151f1b28918dplougher#include <grp.h>
4288facddfd83e48a907b82210ddccbb4f84d80aecplougher#include <time.h>
434dba330d7b952f2f044d38e342e2ae3ea78910d6plougher#include <regex.h>
444dba330d7b952f2f044d38e342e2ae3ea78910d6plougher#include <fnmatch.h>
458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#include <signal.h>
468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#include <pthread.h>
47eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher#include <math.h>
48eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher#include <sys/ioctl.h>
49eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher#include <sys/time.h>
50443c15812032991c98b33b5424b17bcd55fe3575plougher
51443c15812032991c98b33b5424b17bcd55fe3575plougher#ifndef linux
52443c15812032991c98b33b5424b17bcd55fe3575plougher#define __BYTE_ORDER BYTE_ORDER
53443c15812032991c98b33b5424b17bcd55fe3575plougher#define __BIG_ENDIAN BIG_ENDIAN
54443c15812032991c98b33b5424b17bcd55fe3575plougher#define __LITTLE_ENDIAN LITTLE_ENDIAN
55443c15812032991c98b33b5424b17bcd55fe3575plougher#else
56443c15812032991c98b33b5424b17bcd55fe3575plougher#include <endian.h>
57443c15812032991c98b33b5424b17bcd55fe3575plougher#endif
58443c15812032991c98b33b5424b17bcd55fe3575plougher
598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#include "squashfs_fs.h"
60443c15812032991c98b33b5424b17bcd55fe3575plougher#include "read_fs.h"
61443c15812032991c98b33b5424b17bcd55fe3575plougher#include "global.h"
62443c15812032991c98b33b5424b17bcd55fe3575plougher
631b42101056befe25b5f19d5b099e806a2ecee9cdplougher#define PRINTF(s, args...)		do { \
641b42101056befe25b5f19d5b099e806a2ecee9cdplougher						pthread_mutex_lock(&screen_mutex); \
651b42101056befe25b5f19d5b099e806a2ecee9cdplougher						printf(s, ## args); \
661b42101056befe25b5f19d5b099e806a2ecee9cdplougher						pthread_mutex_unlock(&screen_mutex);\
671b42101056befe25b5f19d5b099e806a2ecee9cdplougher					} while(0)
681b42101056befe25b5f19d5b099e806a2ecee9cdplougher
69443c15812032991c98b33b5424b17bcd55fe3575plougher#ifdef SQUASHFS_TRACE
70443c15812032991c98b33b5424b17bcd55fe3575plougher#define TRACE(s, args...)		do { \
711b42101056befe25b5f19d5b099e806a2ecee9cdplougher						pthread_mutex_lock(&screen_mutex); \
724dba330d7b952f2f044d38e342e2ae3ea78910d6plougher						printf("unsquashfs: "s, ## args); \
731b42101056befe25b5f19d5b099e806a2ecee9cdplougher						pthread_mutex_unlock(&screen_mutex);\
74443c15812032991c98b33b5424b17bcd55fe3575plougher					} while(0)
75443c15812032991c98b33b5424b17bcd55fe3575plougher#else
76443c15812032991c98b33b5424b17bcd55fe3575plougher#define TRACE(s, args...)
77443c15812032991c98b33b5424b17bcd55fe3575plougher#endif
78443c15812032991c98b33b5424b17bcd55fe3575plougher
79443c15812032991c98b33b5424b17bcd55fe3575plougher#define ERROR(s, args...)		do { \
801b42101056befe25b5f19d5b099e806a2ecee9cdplougher						pthread_mutex_lock(&screen_mutex); \
81443c15812032991c98b33b5424b17bcd55fe3575plougher						fprintf(stderr, s, ## args); \
821b42101056befe25b5f19d5b099e806a2ecee9cdplougher						pthread_mutex_unlock(&screen_mutex);\
83443c15812032991c98b33b5424b17bcd55fe3575plougher					} while(0)
84443c15812032991c98b33b5424b17bcd55fe3575plougher
85443c15812032991c98b33b5424b17bcd55fe3575plougher#define EXIT_UNSQUASH(s, args...)	do { \
861b42101056befe25b5f19d5b099e806a2ecee9cdplougher						pthread_mutex_lock(&screen_mutex); \
87443c15812032991c98b33b5424b17bcd55fe3575plougher						fprintf(stderr, "FATAL ERROR aborting: "s, ## args); \
881b42101056befe25b5f19d5b099e806a2ecee9cdplougher						pthread_mutex_unlock(&screen_mutex);\
894dba330d7b952f2f044d38e342e2ae3ea78910d6plougher						exit(1); \
90443c15812032991c98b33b5424b17bcd55fe3575plougher					} while(0)
91443c15812032991c98b33b5424b17bcd55fe3575plougher
928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#define CALCULATE_HASH(start)	(start & 0xffff)
938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
94443c15812032991c98b33b5424b17bcd55fe3575plougherstruct hash_table_entry {
95443c15812032991c98b33b5424b17bcd55fe3575plougher	int	start;
96443c15812032991c98b33b5424b17bcd55fe3575plougher	int	bytes;
97443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *next;
98443c15812032991c98b33b5424b17bcd55fe3575plougher};
99443c15812032991c98b33b5424b17bcd55fe3575plougher
1006f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherstruct inode {
1016f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int blocks;
1026f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	char *block_ptr;
10347fc2f0b451e12cddb0cc482019e6abe5bd59d46plougher	long long data;
1046f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int fragment;
1056f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int frag_bytes;
1066f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	gid_t gid;
1076f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int inode_number;
1086f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int mode;
1096f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int offset;
1106f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	long long start;
1116f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	char symlink[65536];
1126f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	time_t time;
1136f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int type;
1146f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	uid_t uid;
1156f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher};
116eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
117eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughertypedef struct squashfs_operations {
118eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *(*squashfs_opendir)(unsigned int block_start, unsigned int offset, struct inode **i);
119eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	void (*read_fragment)(unsigned int fragment, long long *start_block, int *size);
120eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	void (*read_fragment_table)();
121eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	void (*read_block_list)(unsigned int *block_list, char *block_ptr, int blocks);
122eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *(*read_inode)(unsigned int start_block, unsigned int offset);
123eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher} squashfs_operations;
1246f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
125476dcb48b24efff22caa970f000e151f1b28918dplougherstruct test {
126476dcb48b24efff22caa970f000e151f1b28918dplougher	int mask;
127476dcb48b24efff22caa970f000e151f1b28918dplougher	int value;
128476dcb48b24efff22caa970f000e151f1b28918dplougher	int position;
129476dcb48b24efff22caa970f000e151f1b28918dplougher	char mode;
130476dcb48b24efff22caa970f000e151f1b28918dplougher};
131476dcb48b24efff22caa970f000e151f1b28918dplougher
1328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Cache status struct.  Caches are used to keep
1348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher  track of memory buffers passed between different threads */
1358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache {
1368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int	max_buffers;
1378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int	count;
1388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int	buffer_size;
1398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int	wait_free;
1408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int	wait_pending;
1418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_t	mutex;
1428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_t wait_for_free;
1438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_t wait_for_pending;
1448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *free_list;
1458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *hash_table[65536];
1468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher};
1478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* struct describing a cache entry passed between threads */
1498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache_entry {
1508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache *cache;
1518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	long long block;
1528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int	size;
1538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int	used;
1548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int error;
1558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int	pending;
1568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *hash_next;
1578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *hash_prev;
1588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *free_next;
1598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *free_prev;
1608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	char *data;
1618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher};
1628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* struct describing queues used to pass data between threads */
1648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue {
1658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int	size;
1668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int	readp;
1678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int	writep;
1688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_t	mutex;
1698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_t empty;
1708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_t full;
1718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	void **data;
1728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher};
1738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *fragment_cache, *data_cache;
1758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *to_reader, *to_deflate, *to_writer, *from_writer;
1768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherpthread_t *thread, *deflator_thread;
1778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherpthread_mutex_t	fragment_mutex;
1788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
1798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* user options that control parallelisation */
1808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherint processors = -1;
1818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* default size of fragment buffer in Mbytes */
1828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#define FRAGMENT_BUFFER_DEFAULT 256
1838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* default size of data buffer in Mbytes */
1848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#define DATA_BUFFER_DEFAULT 256
1858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
18602bc3bcabf2b219f63961f07293b83629948f026ploughersquashfs_super_block sBlk;
18702bc3bcabf2b219f63961f07293b83629948f026ploughersquashfs_operations s_ops;
18802bc3bcabf2b219f63961f07293b83629948f026plougher
1899dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0,
1909dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	dev_count = 0, fifo_count = 0;
191443c15812032991c98b33b5424b17bcd55fe3575plougherchar *inode_table = NULL, *directory_table = NULL;
192443c15812032991c98b33b5424b17bcd55fe3575plougherstruct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536];
193443c15812032991c98b33b5424b17bcd55fe3575plougherint fd;
194443c15812032991c98b33b5424b17bcd55fe3575ploughersquashfs_fragment_entry *fragment_table;
19502bc3bcabf2b219f63961f07293b83629948f026ploughersquashfs_fragment_entry_2 *fragment_table_2;
196443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int *uid_table, *guid_table;
197443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int cached_frag = SQUASHFS_INVALID_FRAG;
198443c15812032991c98b33b5424b17bcd55fe3575plougherchar *fragment_data;
199443c15812032991c98b33b5424b17bcd55fe3575plougherchar *file_data;
200443c15812032991c98b33b5424b17bcd55fe3575plougherchar *data;
201443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int block_size;
202ae271cc93e3684d5314bcdc45b631e497ae43166plougherunsigned int block_log;
2034dba330d7b952f2f044d38e342e2ae3ea78910d6plougherint lsonly = FALSE, info = FALSE, force = FALSE, short_ls = TRUE, use_regex = FALSE;
204443c15812032991c98b33b5424b17bcd55fe3575plougherchar **created_inode;
2059dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint root_process;
206eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint columns;
207eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint rotate = 0;
2081b42101056befe25b5f19d5b099e806a2ecee9cdplougherpthread_mutex_t	screen_mutex;
209eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherpthread_cond_t progress_wait;
2101b42101056befe25b5f19d5b099e806a2ecee9cdplougherint progress = TRUE, progress_enabled = FALSE;
211eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int total_blocks = 0, total_files = 0, total_inodes = 0;
212eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherunsigned int cur_blocks = 0;
213443c15812032991c98b33b5424b17bcd55fe3575plougher
214476dcb48b24efff22caa970f000e151f1b28918dplougherint lookup_type[] = {
215476dcb48b24efff22caa970f000e151f1b28918dplougher	0,
216476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
217476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFREG,
218476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFLNK,
219476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFBLK,
220476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFCHR,
221476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFIFO,
222476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFSOCK,
223476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFDIR,
224476dcb48b24efff22caa970f000e151f1b28918dplougher	S_IFREG
225476dcb48b24efff22caa970f000e151f1b28918dplougher};
226476dcb48b24efff22caa970f000e151f1b28918dplougher
227476dcb48b24efff22caa970f000e151f1b28918dplougherstruct test table[] = {
228476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFSOCK, 0, 's' },
229476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFLNK, 0, 'l' },
230476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFBLK, 0, 'b' },
231476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFDIR, 0, 'd' },
232476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFCHR, 0, 'c' },
233476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IFMT, S_IFIFO, 0, 'p' },
234476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRUSR, S_IRUSR, 1, 'r' },
235476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWUSR, S_IWUSR, 2, 'w' },
236476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IRGRP, S_IRGRP, 4, 'r' },
237476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWGRP, S_IWGRP, 5, 'w' },
238476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IROTH, S_IROTH, 7, 'r' },
239476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IWOTH, S_IWOTH, 8, 'w' },
240476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR | S_ISUID, 3, 's' },
241476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_ISUID, 3, 'S' },
242476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXUSR | S_ISUID, S_IXUSR, 3, 'x' },
243476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP | S_ISGID, 6, 's' },
244476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_ISGID, 6, 'S' },
245476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXGRP | S_ISGID, S_IXGRP, 6, 'x' },
246476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH | S_ISVTX, 9, 't' },
247476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_ISVTX, 9, 'T' },
248476dcb48b24efff22caa970f000e151f1b28918dplougher	{ S_IXOTH | S_ISVTX, S_IXOTH, 9, 'x' },
2498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	{ 0, 0, 0, 0}
2508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher};
2518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
252eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns);
253eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar();
254eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
255eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid sigwinch_handler()
256eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
257eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct winsize winsize;
258eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
259eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
2601b42101056befe25b5f19d5b099e806a2ecee9cdplougher		ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 columns\n");
261eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = 80;
262eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	} else
263eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		columns = winsize.ws_col;
264eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
265eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2671b5f6c5145f284683a2628b73ab5f8a0e37dd7b4ploughervoid sigalrm_handler()
2681b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher{
2691b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	rotate = (rotate + 1) % 4;
2701b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher}
2711b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
2721b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
2738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct queue *queue_init(int size)
2748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct queue *queue = malloc(sizeof(struct queue));
2768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(queue == NULL)
2788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return NULL;
2798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if((queue->data = malloc(sizeof(void *) * (size + 1))) == NULL) {
2818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		free(queue);
2828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return NULL;
2838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
2848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->size = size + 1;
2868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = queue->writep = 0;
2878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&queue->mutex, NULL);
2888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->empty, NULL);
2898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&queue->full, NULL);
2908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return queue;
2928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
2938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2958888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid queue_put(struct queue *queue, void *data)
2968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
2978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int nextp;
2988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
3008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
3028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->full, &queue->mutex);
3038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->data[queue->writep] = data;
3058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->writep = nextp;
3068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->empty);
3078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
3088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3118888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *queue_get(struct queue *queue)
3128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
3138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	void *data;
3148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&queue->mutex);
3158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(queue->readp == queue->writep)
3178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&queue->empty, &queue->mutex);
3188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data = queue->data[queue->readp];
3208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue->readp = (queue->readp + 1) % queue->size;
3218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_signal(&queue->full);
3228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&queue->mutex);
3238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return data;
3258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
3298888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_hash_table(struct cache *cache, struct cache_entry *entry)
3308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
3318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(entry->block);
3328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_next = cache->hash_table[hash];
3348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->hash_table[hash] = entry;
3358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = NULL;
3368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
3378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry;
3388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
3428888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_hash_table(struct cache *cache, struct cache_entry *entry)
3438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
3448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_prev)
3458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_prev->hash_next = entry->hash_next;
3468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	else
3478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->hash_table[CALCULATE_HASH(entry->block)] = entry->hash_next;
3488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->hash_next)
3498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->hash_next->hash_prev = entry->hash_prev;
3508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->hash_prev = entry->hash_next = NULL;
3528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
3568888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid insert_free_list(struct cache *cache, struct cache_entry *entry)
3578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
3588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache->free_list) {
3598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next = cache->free_list;
3608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = cache->free_list->free_prev;
3618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev->free_next = entry;
3628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list->free_prev = entry;
3638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
3648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = entry;
3658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev = entry->free_next = entry;
3668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* Called with the cache mutex held */
3718888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid remove_free_list(struct cache *cache, struct cache_entry *entry)
3728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
3738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->free_prev == NULL && entry->free_next == NULL)
3748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* not in free list */
3758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return;
376222e49e257bccb10c0e608f071778f26fce28f01plougher	else if(entry->free_prev == entry && entry->free_next == entry) {
3778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* only this entry in the free list */
3788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache->free_list = NULL;
3798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
3808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* more than one entry in the free list */
3818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_next->free_prev = entry->free_prev;
3828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->free_prev->free_next = entry->free_next;
3838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->free_list == entry)
3848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->free_list = entry->free_next;
3858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
3868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->free_prev = entry->free_next = NULL;
3888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
3898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache *cache_init(int buffer_size, int max_buffers)
3928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
3938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache *cache = malloc(sizeof(struct cache));
3948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(cache == NULL)
3968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		return NULL;
3978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
3988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->max_buffers = max_buffers;
3998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->buffer_size = buffer_size;
4008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->count = 0;
4018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->free_list = NULL;
4028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536);
4038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_free = FALSE;
4048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	cache->wait_pending = FALSE;
4058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&cache->mutex, NULL);
4068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_free, NULL);
4078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_cond_init(&cache->wait_for_pending, NULL);
4088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return cache;
4108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
4118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct cache_entry *cache_get(struct cache *cache, long long block, int size)
4148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
4158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* Get a block out of the cache.  If the block isn't in the cache
4168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * it is added and queued to the reader() and deflate() threads for reading
4178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * off disk and decompression.  The cache grows until max_blocks is reached,
4188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * once this occurs existing discarded blocks on the free list are reused */
4198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int hash = CALCULATE_HASH(block);
4208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *entry;
4218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&cache->mutex);
4238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
4258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->block == block)
4268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			break;
4278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry) {
4298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* found the block in the cache, increment used count and
4308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * if necessary remove from free list so it won't disappear
4318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
4328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used ++;
4338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		remove_free_list(cache, entry);
4348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
4358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	} else {
4368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* not in the cache */
4378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* first try to allocate new block */
4398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(cache->count < cache->max_buffers) {
4408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = malloc(sizeof(struct cache_entry));
4418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(entry == NULL)
4428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				goto failed;
4438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data = malloc(cache->buffer_size);
4448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(entry->data == NULL) {
4458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				free(entry);
4468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				goto failed;
4478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
4488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache = cache;
4498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->free_prev = entry->free_next = NULL;
4508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache->count ++;
4518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		} else {
4528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			/* try to get from free list */
4538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			while(cache->free_list == NULL) {
4548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				cache->wait_free = TRUE;
4558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
4568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
4578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry = cache->free_list;
4588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_free_list(cache, entry);
4598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			remove_hash_table(cache, entry);
4608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
4618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* initialise block and insert into the hash table */
4638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->block = block;
4648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->size = size;
4658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->used = 1;
4668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->error = FALSE;
4678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->pending = TRUE;
4688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_hash_table(cache, entry);
4698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* queue to read thread to read and ultimately (via the decompress
4718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * threads) decompress the buffer
4728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 */
4738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_mutex_unlock(&cache->mutex);
4748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_reader, entry);
4758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
4768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return entry;
4788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherfailed:
4808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&cache->mutex);
4818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	return NULL;
4828888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
4838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4858888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_ready(struct cache_entry *entry, int error)
4868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
4878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* mark cache entry as being complete, reading and (if necessary)
4888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * decompression has taken place, and the buffer is valid for use.
4898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * If an error occurs reading or decompressing, the buffer also
4908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * becomes ready but with an error... */
4918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
4928888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->pending = FALSE;
4938888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->error = error;
4948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
4958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* if the wait_pending flag is set, one or more threads may be waiting on
4968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * this buffer */
4978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->cache->wait_pending) {
4988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = FALSE;
4998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_broadcast(&entry->cache->wait_for_pending);
5008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
5018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
5028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
5038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
5048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
5058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
5068888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_wait(struct cache_entry *entry)
5078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
5088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* wait for this cache entry to become ready, when reading and (if necessary)
5098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * decompression has taken place */
5108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
5118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
5128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(entry->pending) {
5138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		entry->cache->wait_pending = TRUE;
5148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		pthread_cond_wait(&entry->cache->wait_for_pending, &entry->cache->mutex);
5158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
5168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
5178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
5188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
5198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
5208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
5218888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid cache_block_put(struct cache_entry *entry)
5228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
5238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* finished with this cache entry, once the usage count reaches zero it
5248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * can be reused and is put onto the free list.  As it remains accessible
5258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * via the hash table it can be found getting a new lease of life before it
5268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * is reused. */
5278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_lock(&entry->cache->mutex);
5288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
5298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	entry->used --;
5308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(entry->used == 0) {
5318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		insert_free_list(entry->cache, entry);
5328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
5338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* if the wait_free flag is set, one or more threads may be waiting on
5348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 	 * this buffer */
5358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(entry->cache->wait_free) {
5368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->cache->wait_free = FALSE;
5378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			pthread_cond_broadcast(&entry->cache->wait_for_free);
5388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
5398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
5408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
5418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_unlock(&entry->cache->mutex);
5428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
543476dcb48b24efff22caa970f000e151f1b28918dplougher
544476dcb48b24efff22caa970f000e151f1b28918dplougher
545476dcb48b24efff22caa970f000e151f1b28918dplougherchar *modestr(char *str, int mode)
546476dcb48b24efff22caa970f000e151f1b28918dplougher{
547476dcb48b24efff22caa970f000e151f1b28918dplougher	int i;
548476dcb48b24efff22caa970f000e151f1b28918dplougher
549476dcb48b24efff22caa970f000e151f1b28918dplougher	strcpy(str, "----------");
550476dcb48b24efff22caa970f000e151f1b28918dplougher
551476dcb48b24efff22caa970f000e151f1b28918dplougher	for(i = 0; table[i].mask != 0; i++) {
552476dcb48b24efff22caa970f000e151f1b28918dplougher		if((mode & table[i].mask) == table[i].value)
553476dcb48b24efff22caa970f000e151f1b28918dplougher			str[table[i].position] = table[i].mode;
554476dcb48b24efff22caa970f000e151f1b28918dplougher	}
555476dcb48b24efff22caa970f000e151f1b28918dplougher
556476dcb48b24efff22caa970f000e151f1b28918dplougher	return str;
557476dcb48b24efff22caa970f000e151f1b28918dplougher}
558476dcb48b24efff22caa970f000e151f1b28918dplougher
559476dcb48b24efff22caa970f000e151f1b28918dplougher
5603edfa57b6a463f7d441d995559143f4861d62e98plougher#define TOTALCHARS  25
5616f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint print_filename(char *pathname, struct inode *inode)
562476dcb48b24efff22caa970f000e151f1b28918dplougher{
5636f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	char str[11], dummy[100], dummy2[100], *userstr, *groupstr;
5646f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int padchars;
565476dcb48b24efff22caa970f000e151f1b28918dplougher	struct passwd *user;
566476dcb48b24efff22caa970f000e151f1b28918dplougher	struct group *group;
56788facddfd83e48a907b82210ddccbb4f84d80aecplougher	struct tm *t;
568476dcb48b24efff22caa970f000e151f1b28918dplougher
569476dcb48b24efff22caa970f000e151f1b28918dplougher	if(short_ls) {
570476dcb48b24efff22caa970f000e151f1b28918dplougher		printf("%s\n", pathname);
571476dcb48b24efff22caa970f000e151f1b28918dplougher		return 1;
572476dcb48b24efff22caa970f000e151f1b28918dplougher	}
573476dcb48b24efff22caa970f000e151f1b28918dplougher
5746f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((user = getpwuid(inode->uid)) == NULL) {
5756f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		sprintf(dummy, "%d", inode->uid);
5763edfa57b6a463f7d441d995559143f4861d62e98plougher		userstr = dummy;
5773edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
5783edfa57b6a463f7d441d995559143f4861d62e98plougher		userstr = user->pw_name;
5793edfa57b6a463f7d441d995559143f4861d62e98plougher
5806f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((group = getgrgid(inode->gid)) == NULL) {
5816f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		sprintf(dummy2, "%d", inode->gid);
5823edfa57b6a463f7d441d995559143f4861d62e98plougher		groupstr = dummy2;
5833edfa57b6a463f7d441d995559143f4861d62e98plougher	} else
5843edfa57b6a463f7d441d995559143f4861d62e98plougher		groupstr = group->gr_name;
5853edfa57b6a463f7d441d995559143f4861d62e98plougher
5866f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	printf("%s %s/%s ", modestr(str, inode->mode), userstr, groupstr);
5873edfa57b6a463f7d441d995559143f4861d62e98plougher
5886f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(inode->mode & S_IFMT) {
5893edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFREG:
5903edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFDIR:
5913edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFSOCK:
5923edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFIFO:
5933edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFLNK:
5943edfa57b6a463f7d441d995559143f4861d62e98plougher			padchars = TOTALCHARS - strlen(userstr) - strlen(groupstr);
5953edfa57b6a463f7d441d995559143f4861d62e98plougher
596caf2f0f593c7f14a4e7e151eeeed773c72578f69plougher			printf("%*lld ", padchars > 0 ? padchars : 0, inode->data);
5973edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
5983edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFCHR:
5993edfa57b6a463f7d441d995559143f4861d62e98plougher		case S_IFBLK:
6003edfa57b6a463f7d441d995559143f4861d62e98plougher			padchars = TOTALCHARS - strlen(userstr) - strlen(groupstr) - 7;
6013edfa57b6a463f7d441d995559143f4861d62e98plougher
60247fc2f0b451e12cddb0cc482019e6abe5bd59d46plougher			printf("%*s%3d,%3d ", padchars > 0 ? padchars : 0, " ", (int) inode->data >> 8, (int) inode->data & 0xff);
6033edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
6043edfa57b6a463f7d441d995559143f4861d62e98plougher	}
605476dcb48b24efff22caa970f000e151f1b28918dplougher
6066f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	t = localtime(&inode->time);
60788facddfd83e48a907b82210ddccbb4f84d80aecplougher
60888facddfd83e48a907b82210ddccbb4f84d80aecplougher	printf("%d-%02d-%02d %02d:%02d %s", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, pathname);
6096f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if((inode->mode & S_IFMT) == S_IFLNK)
6106f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		printf(" -> %s", inode->symlink);
6113edfa57b6a463f7d441d995559143f4861d62e98plougher	printf("\n");
6123edfa57b6a463f7d441d995559143f4861d62e98plougher
613476dcb48b24efff22caa970f000e151f1b28918dplougher	return 1;
614476dcb48b24efff22caa970f000e151f1b28918dplougher}
615476dcb48b24efff22caa970f000e151f1b28918dplougher
616443c15812032991c98b33b5424b17bcd55fe3575plougher
617443c15812032991c98b33b5424b17bcd55fe3575plougherint add_entry(struct hash_table_entry *hash_table[], int start, int bytes)
618443c15812032991c98b33b5424b17bcd55fe3575plougher{
619443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
620443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
621443c15812032991c98b33b5424b17bcd55fe3575plougher
622443c15812032991c98b33b5424b17bcd55fe3575plougher	if((hash_table_entry = malloc(sizeof(struct hash_table_entry))) == NULL) {
623443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("add_hash: out of memory in malloc\n");
624443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
625443c15812032991c98b33b5424b17bcd55fe3575plougher	}
626443c15812032991c98b33b5424b17bcd55fe3575plougher
627443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->start = start;
628443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->bytes = bytes;
629443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->next = hash_table[hash];
630443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table[hash] = hash_table_entry;
631443c15812032991c98b33b5424b17bcd55fe3575plougher
632443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
633443c15812032991c98b33b5424b17bcd55fe3575plougher}
634443c15812032991c98b33b5424b17bcd55fe3575plougher
635443c15812032991c98b33b5424b17bcd55fe3575plougher
636443c15812032991c98b33b5424b17bcd55fe3575plougherint lookup_entry(struct hash_table_entry *hash_table[], int start)
637443c15812032991c98b33b5424b17bcd55fe3575plougher{
638443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
639443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
640443c15812032991c98b33b5424b17bcd55fe3575plougher
6419dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	for(hash_table_entry = hash_table[hash]; hash_table_entry;
6429dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				hash_table_entry = hash_table_entry->next)
643443c15812032991c98b33b5424b17bcd55fe3575plougher		if(hash_table_entry->start == start)
644443c15812032991c98b33b5424b17bcd55fe3575plougher			return hash_table_entry->bytes;
645443c15812032991c98b33b5424b17bcd55fe3575plougher
646443c15812032991c98b33b5424b17bcd55fe3575plougher	return -1;
647443c15812032991c98b33b5424b17bcd55fe3575plougher}
648443c15812032991c98b33b5424b17bcd55fe3575plougher
649443c15812032991c98b33b5424b17bcd55fe3575plougher
650443c15812032991c98b33b5424b17bcd55fe3575plougherint read_bytes(long long byte, int bytes, char *buff)
651443c15812032991c98b33b5424b17bcd55fe3575plougher{
652443c15812032991c98b33b5424b17bcd55fe3575plougher	off_t off = byte;
653443c15812032991c98b33b5424b17bcd55fe3575plougher
654fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes);
655fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
656443c15812032991c98b33b5424b17bcd55fe3575plougher	if(lseek(fd, off, SEEK_SET) == -1) {
6575d415c6659faaa7a69c9baa7175610d889747142plougher		ERROR("Lseek failed because %s\n", strerror(errno));
658443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
659443c15812032991c98b33b5424b17bcd55fe3575plougher	}
660443c15812032991c98b33b5424b17bcd55fe3575plougher
661443c15812032991c98b33b5424b17bcd55fe3575plougher	if(read(fd, buff, bytes) == -1) {
662443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("Read on destination failed because %s\n", strerror(errno));
663443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
664443c15812032991c98b33b5424b17bcd55fe3575plougher	}
665443c15812032991c98b33b5424b17bcd55fe3575plougher
666443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
667443c15812032991c98b33b5424b17bcd55fe3575plougher}
668443c15812032991c98b33b5424b17bcd55fe3575plougher
669443c15812032991c98b33b5424b17bcd55fe3575plougher
67002bc3bcabf2b219f63961f07293b83629948f026plougherint read_block(long long start, long long *next, char *block)
671443c15812032991c98b33b5424b17bcd55fe3575plougher{
672443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned short c_byte;
673443c15812032991c98b33b5424b17bcd55fe3575plougher	int offset = 2;
674443c15812032991c98b33b5424b17bcd55fe3575plougher
675443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
676443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, 2, block) == FALSE)
677fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
678443c15812032991c98b33b5424b17bcd55fe3575plougher		((unsigned char *) &c_byte)[1] = block[0];
679443c15812032991c98b33b5424b17bcd55fe3575plougher		((unsigned char *) &c_byte)[0] = block[1];
680443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
681443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, 2, (char *)&c_byte) == FALSE)
682fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
683fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
684fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ? "compressed" : "uncompressed");
685443c15812032991c98b33b5424b17bcd55fe3575plougher
68602bc3bcabf2b219f63961f07293b83629948f026plougher	if(SQUASHFS_CHECK_DATA(sBlk.flags))
687443c15812032991c98b33b5424b17bcd55fe3575plougher		offset = 3;
688443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED(c_byte)) {
689443c15812032991c98b33b5424b17bcd55fe3575plougher		char buffer[SQUASHFS_METADATA_SIZE];
690443c15812032991c98b33b5424b17bcd55fe3575plougher		int res;
691443c15812032991c98b33b5424b17bcd55fe3575plougher		unsigned long bytes = SQUASHFS_METADATA_SIZE;
692443c15812032991c98b33b5424b17bcd55fe3575plougher
693443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
694443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start + offset, c_byte, buffer) == FALSE)
695fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
696443c15812032991c98b33b5424b17bcd55fe3575plougher
697545404219cdd79c1e06ac7d0698d02a15240c4c3plougher		res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) buffer, c_byte);
698545404219cdd79c1e06ac7d0698d02a15240c4c3plougher
699545404219cdd79c1e06ac7d0698d02a15240c4c3plougher		if(res != Z_OK) {
700443c15812032991c98b33b5424b17bcd55fe3575plougher			if(res == Z_MEM_ERROR)
701443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough memory\n");
702443c15812032991c98b33b5424b17bcd55fe3575plougher			else if(res == Z_BUF_ERROR)
703443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough room in output buffer\n");
704443c15812032991c98b33b5424b17bcd55fe3575plougher			else
705443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, unknown error %d\n", res);
706fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
707443c15812032991c98b33b5424b17bcd55fe3575plougher		}
708443c15812032991c98b33b5424b17bcd55fe3575plougher		if(next)
709443c15812032991c98b33b5424b17bcd55fe3575plougher			*next = start + offset + c_byte;
710443c15812032991c98b33b5424b17bcd55fe3575plougher		return bytes;
711443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
712443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
713443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start + offset, c_byte, block) == FALSE)
714fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
715443c15812032991c98b33b5424b17bcd55fe3575plougher		if(next)
716443c15812032991c98b33b5424b17bcd55fe3575plougher			*next = start + offset + c_byte;
717443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
718443c15812032991c98b33b5424b17bcd55fe3575plougher	}
719fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
720fe3ca0609d02d78bcd11637c1220b2ff428f466aplougherfailed:
721fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	return FALSE;
722443c15812032991c98b33b5424b17bcd55fe3575plougher}
723443c15812032991c98b33b5424b17bcd55fe3575plougher
724443c15812032991c98b33b5424b17bcd55fe3575plougher
725443c15812032991c98b33b5424b17bcd55fe3575plougherint read_data_block(long long start, unsigned int size, char *block)
726443c15812032991c98b33b5424b17bcd55fe3575plougher{
727443c15812032991c98b33b5424b17bcd55fe3575plougher	int res;
728443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned long bytes = block_size;
729443c15812032991c98b33b5424b17bcd55fe3575plougher	int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
730443c15812032991c98b33b5424b17bcd55fe3575plougher
731fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte), SQUASHFS_COMPRESSED_BLOCK(c_byte) ? "compressed" : "uncompressed");
732fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
733443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED_BLOCK(size)) {
734443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, c_byte, data) == FALSE)
735443c15812032991c98b33b5424b17bcd55fe3575plougher			return 0;
736443c15812032991c98b33b5424b17bcd55fe3575plougher
737545404219cdd79c1e06ac7d0698d02a15240c4c3plougher		res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) data, c_byte);
738545404219cdd79c1e06ac7d0698d02a15240c4c3plougher
739545404219cdd79c1e06ac7d0698d02a15240c4c3plougher		if(res != Z_OK) {
740443c15812032991c98b33b5424b17bcd55fe3575plougher			if(res == Z_MEM_ERROR)
741443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough memory\n");
742443c15812032991c98b33b5424b17bcd55fe3575plougher			else if(res == Z_BUF_ERROR)
743443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough room in output buffer\n");
744443c15812032991c98b33b5424b17bcd55fe3575plougher			else
745443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, unknown error %d\n", res);
746443c15812032991c98b33b5424b17bcd55fe3575plougher			return 0;
747443c15812032991c98b33b5424b17bcd55fe3575plougher		}
748443c15812032991c98b33b5424b17bcd55fe3575plougher
749443c15812032991c98b33b5424b17bcd55fe3575plougher		return bytes;
750443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
751443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, c_byte, block) == FALSE)
752443c15812032991c98b33b5424b17bcd55fe3575plougher			return 0;
753443c15812032991c98b33b5424b17bcd55fe3575plougher
754443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
755443c15812032991c98b33b5424b17bcd55fe3575plougher	}
756443c15812032991c98b33b5424b17bcd55fe3575plougher}
757443c15812032991c98b33b5424b17bcd55fe3575plougher
758443c15812032991c98b33b5424b17bcd55fe3575plougher
759545404219cdd79c1e06ac7d0698d02a15240c4c3ploughervoid read_block_list(unsigned int *block_list, char *block_ptr, int blocks)
760ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher{
761ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	if(swap) {
762ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		unsigned int sblock_list[blocks];
763ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		memcpy(sblock_list, block_ptr, blocks * sizeof(unsigned int));
764ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks);
765ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	} else
766ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		memcpy(block_list, block_ptr, blocks * sizeof(unsigned int));
767ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher}
768ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
769ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
770545404219cdd79c1e06ac7d0698d02a15240c4c3ploughervoid read_block_list_1(unsigned int *block_list, char *block_ptr, int blocks)
771ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher{
772ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	unsigned short block_size;
773ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	int i;
774ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
775ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	for(i = 0; i < blocks; i++, block_ptr += 2) {
776ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		if(swap) {
777ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			unsigned short sblock_size;
778ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			memcpy(&sblock_size, block_ptr, sizeof(unsigned short));
779ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			SQUASHFS_SWAP_SHORTS((&block_size), &sblock_size, 1);
780ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		} else
781ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			memcpy(&block_size, block_ptr, sizeof(unsigned short));
782ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		block_list[i] = SQUASHFS_COMPRESSED_SIZE(block_size) | (SQUASHFS_COMPRESSED(block_size) ? 0 : SQUASHFS_COMPRESSED_BIT_BLOCK);
783ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	}
784ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher}
785ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
786ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
78702bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_inode_table(long long start, long long end)
788443c15812032991c98b33b5424b17bcd55fe3575plougher{
789443c15812032991c98b33b5424b17bcd55fe3575plougher	int size = 0, bytes = 0, res;
790443c15812032991c98b33b5424b17bcd55fe3575plougher
791443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
792443c15812032991c98b33b5424b17bcd55fe3575plougher		if((size - bytes < SQUASHFS_METADATA_SIZE) &&
7939dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				((inode_table = realloc(inode_table, size +=
7949dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				SQUASHFS_METADATA_SIZE)) == NULL))
795443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_inode_table: out of memory in realloc\n");
796443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("uncompress_inode_table: reading block 0x%llx\n", start);
797443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(inode_table_hash, start, bytes);
79802bc3bcabf2b219f63961f07293b83629948f026plougher		if((res = read_block(start, &start, inode_table + bytes)) == 0) {
799443c15812032991c98b33b5424b17bcd55fe3575plougher			free(inode_table);
800443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_inode_table: failed to read block\n");
801443c15812032991c98b33b5424b17bcd55fe3575plougher		}
802443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
803443c15812032991c98b33b5424b17bcd55fe3575plougher	}
804443c15812032991c98b33b5424b17bcd55fe3575plougher}
805443c15812032991c98b33b5424b17bcd55fe3575plougher
806443c15812032991c98b33b5424b17bcd55fe3575plougher
8076f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time, unsigned int set_mode)
808443c15812032991c98b33b5424b17bcd55fe3575plougher{
8096f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	struct utimbuf times = { time, time };
810443c15812032991c98b33b5424b17bcd55fe3575plougher
811443c15812032991c98b33b5424b17bcd55fe3575plougher	if(utime(pathname, &times) == -1) {
812443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("set_attributes: failed to set time on %s, because %s\n", pathname, strerror(errno));
813443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
814443c15812032991c98b33b5424b17bcd55fe3575plougher	}
815443c15812032991c98b33b5424b17bcd55fe3575plougher
8169dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if(root_process) {
8176f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(chown(pathname, uid, guid) == -1) {
818443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("set_attributes: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno));
819443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
820443c15812032991c98b33b5424b17bcd55fe3575plougher		}
8219dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	} else
8229dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		mode &= ~07000;
8239dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
8249dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) {
8259dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		ERROR("set_attributes: failed to change mode %s, because %s\n", pathname, strerror(errno));
8269dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		return FALSE;
827443c15812032991c98b33b5424b17bcd55fe3575plougher	}
828443c15812032991c98b33b5424b17bcd55fe3575plougher
829443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
830443c15812032991c98b33b5424b17bcd55fe3575plougher}
831443c15812032991c98b33b5424b17bcd55fe3575plougher
832443c15812032991c98b33b5424b17bcd55fe3575plougher
83302bc3bcabf2b219f63961f07293b83629948f026ploughervoid read_uids_guids()
834443c15812032991c98b33b5424b17bcd55fe3575plougher{
83502bc3bcabf2b219f63961f07293b83629948f026plougher	if((uid_table = malloc((sBlk.no_uids + sBlk.no_guids) * sizeof(unsigned int))) == NULL)
836443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("read_uids_guids: failed to allocate uid/gid table\n");
837443c15812032991c98b33b5424b17bcd55fe3575plougher
83802bc3bcabf2b219f63961f07293b83629948f026plougher	guid_table = uid_table + sBlk.no_uids;
839443c15812032991c98b33b5424b17bcd55fe3575plougher
840fc9aa5457df027969c6616cdf93fc1945ad7688eplougher	if(swap) {
84102bc3bcabf2b219f63961f07293b83629948f026plougher		unsigned int suid_table[sBlk.no_uids + sBlk.no_guids];
842fc9aa5457df027969c6616cdf93fc1945ad7688eplougher
84302bc3bcabf2b219f63961f07293b83629948f026plougher		if(read_bytes(sBlk.uid_start, (sBlk.no_uids + sBlk.no_guids)
8449dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				* sizeof(unsigned int), (char *) suid_table) ==
8459dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				FALSE)
846fc9aa5457df027969c6616cdf93fc1945ad7688eplougher			EXIT_UNSQUASH("read_uids_guids: failed to read uid/gid table\n");
84702bc3bcabf2b219f63961f07293b83629948f026plougher		SQUASHFS_SWAP_INTS(uid_table, suid_table, sBlk.no_uids + sBlk.no_guids);
848fc9aa5457df027969c6616cdf93fc1945ad7688eplougher	} else
84902bc3bcabf2b219f63961f07293b83629948f026plougher		if(read_bytes(sBlk.uid_start, (sBlk.no_uids + sBlk.no_guids)
8509dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				* sizeof(unsigned int), (char *) uid_table) ==
8519dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				FALSE)
852fc9aa5457df027969c6616cdf93fc1945ad7688eplougher			EXIT_UNSQUASH("read_uids_guids: failed to read uid/gid table\n");
853443c15812032991c98b33b5424b17bcd55fe3575plougher}
854443c15812032991c98b33b5424b17bcd55fe3575plougher
855443c15812032991c98b33b5424b17bcd55fe3575plougher
85602bc3bcabf2b219f63961f07293b83629948f026ploughervoid read_fragment_table()
857443c15812032991c98b33b5424b17bcd55fe3575plougher{
85802bc3bcabf2b219f63961f07293b83629948f026plougher	int i, indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk.fragments);
859443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_fragment_index fragment_table_index[indexes];
860443c15812032991c98b33b5424b17bcd55fe3575plougher
86102bc3bcabf2b219f63961f07293b83629948f026plougher	TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk.fragments, indexes, sBlk.fragment_table_start);
8629dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
86302bc3bcabf2b219f63961f07293b83629948f026plougher	if(sBlk.fragments == 0)
864443c15812032991c98b33b5424b17bcd55fe3575plougher		return;
865443c15812032991c98b33b5424b17bcd55fe3575plougher
8669dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	if((fragment_table = (squashfs_fragment_entry *)
86702bc3bcabf2b219f63961f07293b83629948f026plougher			malloc(sBlk.fragments *
8689dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			sizeof(squashfs_fragment_entry))) == NULL)
869443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("read_fragment_table: failed to allocate fragment table\n");
870443c15812032991c98b33b5424b17bcd55fe3575plougher
871443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
872443c15812032991c98b33b5424b17bcd55fe3575plougher		squashfs_fragment_index sfragment_table_index[indexes];
873443c15812032991c98b33b5424b17bcd55fe3575plougher
87402bc3bcabf2b219f63961f07293b83629948f026plougher		read_bytes(sBlk.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk.fragments), (char *) sfragment_table_index);
875443c15812032991c98b33b5424b17bcd55fe3575plougher		SQUASHFS_SWAP_FRAGMENT_INDEXES(fragment_table_index, sfragment_table_index, indexes);
876443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
87702bc3bcabf2b219f63961f07293b83629948f026plougher		read_bytes(sBlk.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk.fragments), (char *) fragment_table_index);
878443c15812032991c98b33b5424b17bcd55fe3575plougher
879443c15812032991c98b33b5424b17bcd55fe3575plougher	for(i = 0; i < indexes; i++) {
8809dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		int length = read_block(fragment_table_index[i], NULL,
88102bc3bcabf2b219f63961f07293b83629948f026plougher		((char *) fragment_table) + (i * SQUASHFS_METADATA_SIZE));
882fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher		TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length);
883443c15812032991c98b33b5424b17bcd55fe3575plougher	}
884443c15812032991c98b33b5424b17bcd55fe3575plougher
885443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
886443c15812032991c98b33b5424b17bcd55fe3575plougher		squashfs_fragment_entry sfragment;
88702bc3bcabf2b219f63961f07293b83629948f026plougher		for(i = 0; i < sBlk.fragments; i++) {
888443c15812032991c98b33b5424b17bcd55fe3575plougher			SQUASHFS_SWAP_FRAGMENT_ENTRY((&sfragment), (&fragment_table[i]));
889443c15812032991c98b33b5424b17bcd55fe3575plougher			memcpy((char *) &fragment_table[i], (char *) &sfragment, sizeof(squashfs_fragment_entry));
890443c15812032991c98b33b5424b17bcd55fe3575plougher		}
891443c15812032991c98b33b5424b17bcd55fe3575plougher	}
892443c15812032991c98b33b5424b17bcd55fe3575plougher}
893443c15812032991c98b33b5424b17bcd55fe3575plougher
894443c15812032991c98b33b5424b17bcd55fe3575plougher
89502bc3bcabf2b219f63961f07293b83629948f026ploughervoid read_fragment_table_2()
89602bc3bcabf2b219f63961f07293b83629948f026plougher{
89702bc3bcabf2b219f63961f07293b83629948f026plougher	int i, indexes = SQUASHFS_FRAGMENT_INDEXES_2(sBlk.fragments);
89802bc3bcabf2b219f63961f07293b83629948f026plougher	unsigned int fragment_table_index[indexes];
89902bc3bcabf2b219f63961f07293b83629948f026plougher
90002bc3bcabf2b219f63961f07293b83629948f026plougher	TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk.fragments, indexes, sBlk.fragment_table_start);
90102bc3bcabf2b219f63961f07293b83629948f026plougher
90202bc3bcabf2b219f63961f07293b83629948f026plougher	if(sBlk.fragments == 0)
90302bc3bcabf2b219f63961f07293b83629948f026plougher		return;
90402bc3bcabf2b219f63961f07293b83629948f026plougher
90502bc3bcabf2b219f63961f07293b83629948f026plougher	if((fragment_table_2 = (squashfs_fragment_entry_2 *)
90602bc3bcabf2b219f63961f07293b83629948f026plougher			malloc(sBlk.fragments *
90702bc3bcabf2b219f63961f07293b83629948f026plougher			sizeof(squashfs_fragment_entry))) == NULL)
90802bc3bcabf2b219f63961f07293b83629948f026plougher		EXIT_UNSQUASH("read_fragment_table: failed to allocate fragment table\n");
90902bc3bcabf2b219f63961f07293b83629948f026plougher
91002bc3bcabf2b219f63961f07293b83629948f026plougher	if(swap) {
91102bc3bcabf2b219f63961f07293b83629948f026plougher		 unsigned int sfragment_table_index[indexes];
91202bc3bcabf2b219f63961f07293b83629948f026plougher
91302bc3bcabf2b219f63961f07293b83629948f026plougher		read_bytes(sBlk.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sBlk.fragments), (char *) sfragment_table_index);
91402bc3bcabf2b219f63961f07293b83629948f026plougher		SQUASHFS_SWAP_FRAGMENT_INDEXES_2(fragment_table_index, sfragment_table_index, indexes);
91502bc3bcabf2b219f63961f07293b83629948f026plougher	} else
91602bc3bcabf2b219f63961f07293b83629948f026plougher		read_bytes(sBlk.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sBlk.fragments), (char *) fragment_table_index);
91702bc3bcabf2b219f63961f07293b83629948f026plougher
91802bc3bcabf2b219f63961f07293b83629948f026plougher	for(i = 0; i < indexes; i++) {
91902bc3bcabf2b219f63961f07293b83629948f026plougher		int length = read_block(fragment_table_index[i], NULL,
92002bc3bcabf2b219f63961f07293b83629948f026plougher		((char *) fragment_table_2) + (i * SQUASHFS_METADATA_SIZE));
921545404219cdd79c1e06ac7d0698d02a15240c4c3plougher		TRACE("Read fragment table block %d, from 0x%x, length %d\n", i, fragment_table_index[i], length);
92202bc3bcabf2b219f63961f07293b83629948f026plougher	}
92302bc3bcabf2b219f63961f07293b83629948f026plougher
92402bc3bcabf2b219f63961f07293b83629948f026plougher	if(swap) {
92502bc3bcabf2b219f63961f07293b83629948f026plougher		squashfs_fragment_entry_2 sfragment;
92602bc3bcabf2b219f63961f07293b83629948f026plougher		for(i = 0; i < sBlk.fragments; i++) {
92702bc3bcabf2b219f63961f07293b83629948f026plougher			SQUASHFS_SWAP_FRAGMENT_ENTRY_2((&sfragment), (&fragment_table_2[i]));
92802bc3bcabf2b219f63961f07293b83629948f026plougher			memcpy((char *) &fragment_table_2[i], (char *) &sfragment, sizeof(squashfs_fragment_entry_2));
92902bc3bcabf2b219f63961f07293b83629948f026plougher		}
93002bc3bcabf2b219f63961f07293b83629948f026plougher	}
93102bc3bcabf2b219f63961f07293b83629948f026plougher}
93202bc3bcabf2b219f63961f07293b83629948f026plougher
93302bc3bcabf2b219f63961f07293b83629948f026plougher
934ba3d412c7c811a9b335a52ec497ce511e35b2bc8ploughervoid read_fragment_table_1()
935ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher{
936ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher}
937ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
938ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
9398888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid read_fragment(unsigned int fragment, long long *start_block, int *size)
940443c15812032991c98b33b5424b17bcd55fe3575plougher{
941fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_fragment: reading fragment %d\n", fragment);
942fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
9438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	squashfs_fragment_entry *fragment_entry = &fragment_table[fragment];
9448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	*start_block = fragment_entry->start_block;
9458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	*size = fragment_entry->size;
946443c15812032991c98b33b5424b17bcd55fe3575plougher}
947443c15812032991c98b33b5424b17bcd55fe3575plougher
948443c15812032991c98b33b5424b17bcd55fe3575plougher
9498888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid read_fragment_2(unsigned int fragment, long long *start_block, int *size)
95002bc3bcabf2b219f63961f07293b83629948f026plougher{
95102bc3bcabf2b219f63961f07293b83629948f026plougher	TRACE("read_fragment: reading fragment %d\n", fragment);
95202bc3bcabf2b219f63961f07293b83629948f026plougher
9538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	squashfs_fragment_entry_2 *fragment_entry = &fragment_table_2[fragment];
9548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	*start_block = fragment_entry->start_block;
9558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	*size = fragment_entry->size;
95602bc3bcabf2b219f63961f07293b83629948f026plougher}
95702bc3bcabf2b219f63961f07293b83629948f026plougher
95802bc3bcabf2b219f63961f07293b83629948f026plougher
959b9cee889506e674726856035dba52d5e1cceeb99plougherint lseek_broken = FALSE;
960b9cee889506e674726856035dba52d5e1cceeb99plougherchar *zero_data;
961b9cee889506e674726856035dba52d5e1cceeb99plougher
9628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherint write_block(int file_fd, char *buffer, int size, int hole)
963b9cee889506e674726856035dba52d5e1cceeb99plougher{
964b9cee889506e674726856035dba52d5e1cceeb99plougher	off_t off = hole;
965b9cee889506e674726856035dba52d5e1cceeb99plougher
966b9cee889506e674726856035dba52d5e1cceeb99plougher	if(hole) {
967b9cee889506e674726856035dba52d5e1cceeb99plougher		if(lseek_broken == FALSE && lseek(file_fd, off, SEEK_CUR) == -1) {
968b9cee889506e674726856035dba52d5e1cceeb99plougher			/* failed to seek beyond end of file */
969b9cee889506e674726856035dba52d5e1cceeb99plougher			if((zero_data = malloc(block_size)) == NULL)
970b9cee889506e674726856035dba52d5e1cceeb99plougher				EXIT_UNSQUASH("write_block: failed to alloc zero data block\n");
971b9cee889506e674726856035dba52d5e1cceeb99plougher			memset(zero_data, 0, block_size);
972b9cee889506e674726856035dba52d5e1cceeb99plougher			lseek_broken = TRUE;
973b9cee889506e674726856035dba52d5e1cceeb99plougher		}
974b9cee889506e674726856035dba52d5e1cceeb99plougher		if(lseek_broken) {
975b9cee889506e674726856035dba52d5e1cceeb99plougher			int blocks = (hole + block_size -1) / block_size;
976b9cee889506e674726856035dba52d5e1cceeb99plougher			int avail_bytes, i;
977b9cee889506e674726856035dba52d5e1cceeb99plougher			for(i = 0; i < blocks; i++, hole -= avail_bytes) {
978b9cee889506e674726856035dba52d5e1cceeb99plougher				avail_bytes = hole > block_size ? block_size : hole;
979b9cee889506e674726856035dba52d5e1cceeb99plougher				if(write(file_fd, zero_data, avail_bytes) < avail_bytes)
980b9cee889506e674726856035dba52d5e1cceeb99plougher					goto failure;
981b9cee889506e674726856035dba52d5e1cceeb99plougher			}
982b9cee889506e674726856035dba52d5e1cceeb99plougher		}
983b9cee889506e674726856035dba52d5e1cceeb99plougher	}
984b9cee889506e674726856035dba52d5e1cceeb99plougher
985b9cee889506e674726856035dba52d5e1cceeb99plougher	if(write(file_fd, buffer, size) < size)
986b9cee889506e674726856035dba52d5e1cceeb99plougher		goto failure;
987b9cee889506e674726856035dba52d5e1cceeb99plougher
988b9cee889506e674726856035dba52d5e1cceeb99plougher	return TRUE;
989b9cee889506e674726856035dba52d5e1cceeb99plougher
990b9cee889506e674726856035dba52d5e1cceeb99plougherfailure:
991b9cee889506e674726856035dba52d5e1cceeb99plougher	return FALSE;
992b9cee889506e674726856035dba52d5e1cceeb99plougher}
993b9cee889506e674726856035dba52d5e1cceeb99plougher
9948888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
9958888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct file_entry {
9968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int offset;
9978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int size;
9988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct cache_entry *buffer;
9998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher};
10008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
10018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
10028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougherstruct squashfs_file {
10038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int fd;
10048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int blocks;
100579df93becb68081effabebba3006c794be308598plougher	long long file_size;
100679df93becb68081effabebba3006c794be308598plougher	int mode;
100779df93becb68081effabebba3006c794be308598plougher	uid_t uid;
100879df93becb68081effabebba3006c794be308598plougher	gid_t gid;
100979df93becb68081effabebba3006c794be308598plougher	time_t time;
101079df93becb68081effabebba3006c794be308598plougher	char *pathname;
10118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher};
10128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
10138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
101479df93becb68081effabebba3006c794be308598plougherint write_file(struct inode *inode, char *pathname)
1015443c15812032991c98b33b5424b17bcd55fe3575plougher{
10168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	unsigned int file_fd, i;
1017f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher	unsigned int *block_list;
101879df93becb68081effabebba3006c794be308598plougher	int file_end = inode->data / block_size;
101979df93becb68081effabebba3006c794be308598plougher	long long start = inode->start;
10208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	struct squashfs_file *file;
1021443c15812032991c98b33b5424b17bcd55fe3575plougher
102279df93becb68081effabebba3006c794be308598plougher	TRACE("write_file: regular file, blocks %d\n", inode->blocks);
1023443c15812032991c98b33b5424b17bcd55fe3575plougher
102479df93becb68081effabebba3006c794be308598plougher	if((file_fd = open(pathname, O_CREAT | O_WRONLY | (force ? O_TRUNC : 0), (mode_t) inode->mode & 0777)) == -1) {
1025443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("write_file: failed to create file %s, because %s\n", pathname,
1026443c15812032991c98b33b5424b17bcd55fe3575plougher			strerror(errno));
1027443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
1028443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1029443c15812032991c98b33b5424b17bcd55fe3575plougher
103079df93becb68081effabebba3006c794be308598plougher	if((block_list = malloc(inode->blocks * sizeof(unsigned int))) == NULL)
10318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("write_file: unable to malloc block list\n");
1032443c15812032991c98b33b5424b17bcd55fe3575plougher
103379df93becb68081effabebba3006c794be308598plougher	s_ops.read_block_list(block_list, inode->block_ptr, inode->blocks);
1034443c15812032991c98b33b5424b17bcd55fe3575plougher
10358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if((file = malloc(sizeof(struct squashfs_file))) == NULL)
10368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("write_file: unable to malloc file\n");
1037443c15812032991c98b33b5424b17bcd55fe3575plougher
10388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	/* the writer thread is queued a squashfs_file structure describing the
10398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * file.  If the file has one or more blocks or a fragments they are queued
10408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 	 * separately (references to blocks in the cache). */
10418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	file->fd = file_fd;
104279df93becb68081effabebba3006c794be308598plougher	file->file_size = inode->data;
104379df93becb68081effabebba3006c794be308598plougher	file->mode = inode->mode;
104479df93becb68081effabebba3006c794be308598plougher	file->gid = inode->gid;
104579df93becb68081effabebba3006c794be308598plougher	file->uid = inode->uid;
104679df93becb68081effabebba3006c794be308598plougher	file->time = inode->time;
104779df93becb68081effabebba3006c794be308598plougher	file->pathname = strdup(pathname);
104879df93becb68081effabebba3006c794be308598plougher	file->blocks = inode->blocks + (inode->frag_bytes > 0);
10498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_put(to_writer, file);
1050443c15812032991c98b33b5424b17bcd55fe3575plougher
105179df93becb68081effabebba3006c794be308598plougher	for(i = 0; i < inode->blocks; i++) {
10528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
10538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct file_entry *block = malloc(sizeof(struct file_entry *));
10548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
10558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
10568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
10578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->offset = 0;
105879df93becb68081effabebba3006c794be308598plougher		block->size = i == file_end ? inode->data & (block_size - 1) : block_size;
10598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block_list[i] == 0) /* sparse file */
10608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			block->buffer = NULL;
10618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else {
10628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			block->buffer = cache_get(data_cache, start, block_list[i]);
10638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(block->buffer == NULL)
10648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				EXIT_UNSQUASH("write_file: cache_get failed\n");
10658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			start += c_byte;
1066443c15812032991c98b33b5424b17bcd55fe3575plougher		}
10678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
1068443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1069443c15812032991c98b33b5424b17bcd55fe3575plougher
107079df93becb68081effabebba3006c794be308598plougher	if(inode->frag_bytes) {
10718888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int size;
10728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		long long start;
10738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct file_entry *block = malloc(sizeof(struct file_entry *));
10748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
10758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block == NULL)
10768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: unable to malloc file\n");
107779df93becb68081effabebba3006c794be308598plougher		s_ops.read_fragment(inode->fragment, &start, &size);
10788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		block->buffer = cache_get(fragment_cache, start, size);
10798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(block->buffer == NULL)
10808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("write_file: cache_get failed\n");
108179df93becb68081effabebba3006c794be308598plougher		block->offset = inode->offset;
108279df93becb68081effabebba3006c794be308598plougher		block->size = inode->frag_bytes;
10838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		queue_put(to_writer, block);
1084b9cee889506e674726856035dba52d5e1cceeb99plougher	}
1085b9cee889506e674726856035dba52d5e1cceeb99plougher
1086b9cee889506e674726856035dba52d5e1cceeb99plougher	free(block_list);
1087443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1088443c15812032991c98b33b5424b17bcd55fe3575plougher}
1089476dcb48b24efff22caa970f000e151f1b28918dplougher
1090476dcb48b24efff22caa970f000e151f1b28918dplougher
10916f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherstatic struct inode *read_inode(unsigned int start_block, unsigned int offset)
1092476dcb48b24efff22caa970f000e151f1b28918dplougher{
1093476dcb48b24efff22caa970f000e151f1b28918dplougher	static squashfs_inode_header header;
1094476dcb48b24efff22caa970f000e151f1b28918dplougher	long long start = sBlk.inode_table_start + start_block;
1095545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	int bytes = lookup_entry(inode_table_hash, start);
1096476dcb48b24efff22caa970f000e151f1b28918dplougher	char *block_ptr = inode_table + bytes + offset;
10976f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	static struct inode i;
1098476dcb48b24efff22caa970f000e151f1b28918dplougher
1099476dcb48b24efff22caa970f000e151f1b28918dplougher	if(bytes == -1)
1100476dcb48b24efff22caa970f000e151f1b28918dplougher		goto error;
1101476dcb48b24efff22caa970f000e151f1b28918dplougher
1102476dcb48b24efff22caa970f000e151f1b28918dplougher	if(swap) {
1103476dcb48b24efff22caa970f000e151f1b28918dplougher		squashfs_base_inode_header sinode;
1104476dcb48b24efff22caa970f000e151f1b28918dplougher		memcpy(&sinode, block_ptr, sizeof(header.base));
1105476dcb48b24efff22caa970f000e151f1b28918dplougher		SQUASHFS_SWAP_BASE_INODE_HEADER(&header.base, &sinode, sizeof(squashfs_base_inode_header));
1106476dcb48b24efff22caa970f000e151f1b28918dplougher	} else
1107476dcb48b24efff22caa970f000e151f1b28918dplougher		memcpy(&header.base, block_ptr, sizeof(header.base));
1108476dcb48b24efff22caa970f000e151f1b28918dplougher
11096f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.uid = (uid_t) uid_table[header.base.uid];
11106f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.gid = header.base.guid == SQUASHFS_GUIDS ? i.uid : (uid_t) guid_table[header.base.guid];
11116f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.mode = lookup_type[header.base.inode_type] | header.base.mode;
11126f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.type = header.base.inode_type;
11136f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.time = header.base.mtime;
11146f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.inode_number = header.base.inode_number;
1115476dcb48b24efff22caa970f000e151f1b28918dplougher
1116476dcb48b24efff22caa970f000e151f1b28918dplougher	switch(header.base.inode_type) {
1117476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_DIR_TYPE: {
1118476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_dir_inode_header *inode = &header.dir;
1119476dcb48b24efff22caa970f000e151f1b28918dplougher
1120476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1121476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_dir_inode_header sinode;
1122476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinode, block_ptr, sizeof(header.dir));
1123476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_DIR_INODE_HEADER(&header.dir, &sinode);
1124476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1125476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&header.dir, block_ptr, sizeof(header.dir));
1126476dcb48b24efff22caa970f000e151f1b28918dplougher
11276f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inode->file_size;
11286f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.offset = inode->offset;
11296f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.start = inode->start_block;
11303edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
1131476dcb48b24efff22caa970f000e151f1b28918dplougher		}
1132476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_LDIR_TYPE: {
1133476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_ldir_inode_header *inode = &header.ldir;
1134476dcb48b24efff22caa970f000e151f1b28918dplougher
1135476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1136476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_ldir_inode_header sinode;
1137476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinode, block_ptr, sizeof(header.ldir));
1138476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_LDIR_INODE_HEADER(&header.ldir, &sinode);
1139476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1140476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&header.ldir, block_ptr, sizeof(header.ldir));
1141476dcb48b24efff22caa970f000e151f1b28918dplougher
11426f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inode->file_size;
11436f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.offset = inode->offset;
11446f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.start = inode->start_block;
11453edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
1146476dcb48b24efff22caa970f000e151f1b28918dplougher		}
1147476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_FILE_TYPE: {
1148476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_reg_inode_header *inode = &header.reg;
1149476dcb48b24efff22caa970f000e151f1b28918dplougher
1150476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1151476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_reg_inode_header sinode;
1152476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinode, block_ptr, sizeof(sinode));
1153476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_REG_INODE_HEADER(inode, &sinode);
1154476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1155476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(inode, block_ptr, sizeof(*inode));
1156476dcb48b24efff22caa970f000e151f1b28918dplougher
11576f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inode->file_size;
11586f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ?
11596f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				0 : inode->file_size % sBlk.block_size;
11606f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.fragment = inode->fragment;
11616f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.offset = inode->offset;
11626f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ?
11636f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				(inode->file_size + sBlk.block_size - 1) >>
11646f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				sBlk.block_log : inode->file_size >> sBlk.block_log;
11656f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.start = inode->start_block;
11666f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.block_ptr = block_ptr + sizeof(*inode);
1167476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1168476dcb48b24efff22caa970f000e151f1b28918dplougher		}
1169476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_LREG_TYPE: {
1170476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_lreg_inode_header *inode = &header.lreg;
1171476dcb48b24efff22caa970f000e151f1b28918dplougher
1172476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1173476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_lreg_inode_header sinode;
1174476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinode, block_ptr, sizeof(sinode));
1175476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_LREG_INODE_HEADER(inode, &sinode);
1176476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1177476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(inode, block_ptr, sizeof(*inode));
1178476dcb48b24efff22caa970f000e151f1b28918dplougher
11796f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inode->file_size;
11806f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ?
11816f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				0 : inode->file_size % sBlk.block_size;
11826f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.fragment = inode->fragment;
11836f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.offset = inode->offset;
11846f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ?
11856f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				(inode->file_size + sBlk.block_size - 1) >>
11866f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				sBlk.block_log : inode->file_size >> sBlk.block_log;
11876f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.start = inode->start_block;
11886f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.block_ptr = block_ptr + sizeof(*inode);
1189476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1190476dcb48b24efff22caa970f000e151f1b28918dplougher		}
1191476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_SYMLINK_TYPE: {
1192476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_symlink_inode_header *inodep = &header.symlink;
1193476dcb48b24efff22caa970f000e151f1b28918dplougher
1194476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1195476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_symlink_inode_header sinodep;
1196476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinodep, block_ptr, sizeof(sinodep));
1197476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, &sinodep);
1198476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1199476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(inodep, block_ptr, sizeof(*inodep));
1200476dcb48b24efff22caa970f000e151f1b28918dplougher
12016f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			strncpy(i.symlink, block_ptr + sizeof(squashfs_symlink_inode_header), inodep->symlink_size);
12026f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.symlink[inodep->symlink_size] = '\0';
12036f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inodep->symlink_size;
1204476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1205476dcb48b24efff22caa970f000e151f1b28918dplougher		}
1206476dcb48b24efff22caa970f000e151f1b28918dplougher 		case SQUASHFS_BLKDEV_TYPE:
1207476dcb48b24efff22caa970f000e151f1b28918dplougher	 	case SQUASHFS_CHRDEV_TYPE: {
1208476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_dev_inode_header *inodep = &header.dev;
1209476dcb48b24efff22caa970f000e151f1b28918dplougher
1210476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1211476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_dev_inode_header sinodep;
1212476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinodep, block_ptr, sizeof(sinodep));
1213476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, &sinodep);
1214476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1215476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(inodep, block_ptr, sizeof(*inodep));
1216476dcb48b24efff22caa970f000e151f1b28918dplougher
12176f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inodep->rdev;
1218476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1219476dcb48b24efff22caa970f000e151f1b28918dplougher			}
1220476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_FIFO_TYPE:
1221476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_SOCKET_TYPE:
12226f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = 0;
1223476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1224476dcb48b24efff22caa970f000e151f1b28918dplougher		default:
12256f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			ERROR("Unknown inode type %d in read_inode!\n", header.base.inode_type);
1226476dcb48b24efff22caa970f000e151f1b28918dplougher			return NULL;
1227476dcb48b24efff22caa970f000e151f1b28918dplougher	}
12286f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	return &i;
1229476dcb48b24efff22caa970f000e151f1b28918dplougher
1230476dcb48b24efff22caa970f000e151f1b28918dploughererror:
1231476dcb48b24efff22caa970f000e151f1b28918dplougher	return NULL;
1232476dcb48b24efff22caa970f000e151f1b28918dplougher}
1233476dcb48b24efff22caa970f000e151f1b28918dplougher
1234443c15812032991c98b33b5424b17bcd55fe3575plougher
12356f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherint create_inode(char *pathname, struct inode *i)
1236443c15812032991c98b33b5424b17bcd55fe3575plougher{
12376f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	TRACE("create_inode: pathname %s\n", pathname);
1238443c15812032991c98b33b5424b17bcd55fe3575plougher
12396f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	if(created_inode[i->inode_number - 1]) {
1240443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("create_inode: hard link\n");
12416013a30bd39550decc2546a47e5168e57bfcfde8plougher		if(force)
12426013a30bd39550decc2546a47e5168e57bfcfde8plougher			unlink(pathname);
12436013a30bd39550decc2546a47e5168e57bfcfde8plougher
12446f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		if(link(created_inode[i->inode_number - 1], pathname) == -1) {
1245443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("create_inode: failed to create hardlink, because %s\n", strerror(errno));
1246443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
1247443c15812032991c98b33b5424b17bcd55fe3575plougher		}
1248443c15812032991c98b33b5424b17bcd55fe3575plougher
1249443c15812032991c98b33b5424b17bcd55fe3575plougher		return TRUE;
1250443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1251443c15812032991c98b33b5424b17bcd55fe3575plougher
12526f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(i->type) {
12536f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_FILE_TYPE:
12546f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_LREG_TYPE:
12556f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			TRACE("create_inode: regular file, file_size %lld, blocks %d\n", i->data, i->blocks);
1256443c15812032991c98b33b5424b17bcd55fe3575plougher
125779df93becb68081effabebba3006c794be308598plougher			if(write_file(i, pathname))
1258443c15812032991c98b33b5424b17bcd55fe3575plougher				file_count ++;
1259443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
12606f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		case SQUASHFS_SYMLINK_TYPE:
1261545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			TRACE("create_inode: symlink, symlink_size %lld\n", i->data);
1262443c15812032991c98b33b5424b17bcd55fe3575plougher
1263a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
1264a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
1265a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
12666f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(symlink(i->symlink, pathname) == -1) {
1267443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("create_inode: failed to create symlink %s, because %s\n", pathname,
1268443c15812032991c98b33b5424b17bcd55fe3575plougher					strerror(errno));
1269443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
1270443c15812032991c98b33b5424b17bcd55fe3575plougher			}
1271443c15812032991c98b33b5424b17bcd55fe3575plougher
12729dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
12736f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(lchown(pathname, i->uid, i->gid) == -1)
1274443c15812032991c98b33b5424b17bcd55fe3575plougher					ERROR("create_inode: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno));
1275443c15812032991c98b33b5424b17bcd55fe3575plougher			}
1276443c15812032991c98b33b5424b17bcd55fe3575plougher
1277443c15812032991c98b33b5424b17bcd55fe3575plougher			sym_count ++;
1278443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1279443c15812032991c98b33b5424b17bcd55fe3575plougher 		case SQUASHFS_BLKDEV_TYPE:
1280443c15812032991c98b33b5424b17bcd55fe3575plougher	 	case SQUASHFS_CHRDEV_TYPE: {
12816f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			int chrdev = i->type == SQUASHFS_CHRDEV_TYPE;
1282545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			TRACE("create_inode: dev, rdev 0x%llx\n", i->data);
1283443c15812032991c98b33b5424b17bcd55fe3575plougher
12849dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher			if(root_process) {
1285a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				if(force)
1286a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher					unlink(pathname);
1287a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
12886f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				if(mknod(pathname, chrdev ? S_IFCHR : S_IFBLK,
12896f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher					makedev((i->data >> 8) & 0xff, i->data & 0xff)) == -1) {
1290443c15812032991c98b33b5424b17bcd55fe3575plougher					ERROR("create_inode: failed to create %s device %s, because %s\n",
12916f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher						chrdev ? "character" : "block", pathname, strerror(errno));
1292443c15812032991c98b33b5424b17bcd55fe3575plougher					break;
1293443c15812032991c98b33b5424b17bcd55fe3575plougher				}
12946f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				set_attributes(pathname, i->mode, i->uid, i->gid, i->time, TRUE);
1295443c15812032991c98b33b5424b17bcd55fe3575plougher				dev_count ++;
1296443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
1297443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("create_inode: could not create %s device %s, because you're not superuser!\n",
1298545404219cdd79c1e06ac7d0698d02a15240c4c3plougher					chrdev ? "character" : "block", pathname);
1299443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
13006f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		}
1301443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_FIFO_TYPE:
1302443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: fifo\n");
1303443c15812032991c98b33b5424b17bcd55fe3575plougher
1304a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			if(force)
1305a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher				unlink(pathname);
1306a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher
1307443c15812032991c98b33b5424b17bcd55fe3575plougher			if(mknod(pathname, S_IFIFO, 0) == -1) {
1308443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("create_inode: failed to create fifo %s, because %s\n",
1309443c15812032991c98b33b5424b17bcd55fe3575plougher					pathname, strerror(errno));
1310443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
1311443c15812032991c98b33b5424b17bcd55fe3575plougher			}
13126f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			set_attributes(pathname, i->mode, i->uid, i->gid, i->time, TRUE);
1313443c15812032991c98b33b5424b17bcd55fe3575plougher			fifo_count ++;
1314443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1315443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_SOCKET_TYPE:
1316443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: socket\n");
1317443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("create_inode: socket %s ignored\n", pathname);
1318443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
1319443c15812032991c98b33b5424b17bcd55fe3575plougher		default:
13206f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			ERROR("Unknown inode type %d in create_inode_table!\n", i->type);
1321443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
1322443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1323fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
13246f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	created_inode[i->inode_number - 1] = strdup(pathname);
1325443c15812032991c98b33b5424b17bcd55fe3575plougher
1326443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1327443c15812032991c98b33b5424b17bcd55fe3575plougher}
1328443c15812032991c98b33b5424b17bcd55fe3575plougher
1329443c15812032991c98b33b5424b17bcd55fe3575plougher
13306f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherstruct inode *read_inode_2(unsigned int start_block, unsigned int offset)
1331476dcb48b24efff22caa970f000e151f1b28918dplougher{
1332476dcb48b24efff22caa970f000e151f1b28918dplougher	static squashfs_inode_header_2 header;
1333476dcb48b24efff22caa970f000e151f1b28918dplougher	long long start = sBlk.inode_table_start + start_block;
1334545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	int bytes = lookup_entry(inode_table_hash, start);
1335476dcb48b24efff22caa970f000e151f1b28918dplougher	char *block_ptr = inode_table + bytes + offset;
13366f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	static struct inode i;
13376f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	static int inode_number = 1;
1338476dcb48b24efff22caa970f000e151f1b28918dplougher
1339476dcb48b24efff22caa970f000e151f1b28918dplougher	if(bytes == -1)
1340476dcb48b24efff22caa970f000e151f1b28918dplougher		goto error;
1341476dcb48b24efff22caa970f000e151f1b28918dplougher
1342476dcb48b24efff22caa970f000e151f1b28918dplougher	if(swap) {
1343476dcb48b24efff22caa970f000e151f1b28918dplougher		squashfs_base_inode_header_2 sinode;
1344476dcb48b24efff22caa970f000e151f1b28918dplougher		memcpy(&sinode, block_ptr, sizeof(header.base));
1345476dcb48b24efff22caa970f000e151f1b28918dplougher		SQUASHFS_SWAP_BASE_INODE_HEADER_2(&header.base, &sinode, sizeof(squashfs_base_inode_header_2));
1346476dcb48b24efff22caa970f000e151f1b28918dplougher	} else
1347476dcb48b24efff22caa970f000e151f1b28918dplougher		memcpy(&header.base, block_ptr, sizeof(header.base));
1348476dcb48b24efff22caa970f000e151f1b28918dplougher
13496f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher    i.uid = (uid_t) uid_table[header.base.uid];
13506f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher    i.gid = header.base.guid == SQUASHFS_GUIDS ? i.uid : (uid_t) guid_table[header.base.guid];
13516f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.mode = lookup_type[header.base.inode_type] | header.base.mode;
13526f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.type = header.base.inode_type;
13536f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.time = sBlk.mkfs_time;
13546f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.inode_number = inode_number++;
1355476dcb48b24efff22caa970f000e151f1b28918dplougher
1356476dcb48b24efff22caa970f000e151f1b28918dplougher	switch(header.base.inode_type) {
1357476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_DIR_TYPE: {
1358476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_dir_inode_header_2 *inode = &header.dir;
1359476dcb48b24efff22caa970f000e151f1b28918dplougher
1360476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1361476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_dir_inode_header sinode;
1362476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinode, block_ptr, sizeof(header.dir));
1363476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_DIR_INODE_HEADER_2(&header.dir, &sinode);
1364476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1365476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&header.dir, block_ptr, sizeof(header.dir));
1366476dcb48b24efff22caa970f000e151f1b28918dplougher
13676f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inode->file_size;
13686f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.offset = inode->offset;
13696f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.start = inode->start_block;
13706f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.time = inode->mtime;
13713edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
1372476dcb48b24efff22caa970f000e151f1b28918dplougher		}
1373476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_LDIR_TYPE: {
1374476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_ldir_inode_header_2 *inode = &header.ldir;
1375476dcb48b24efff22caa970f000e151f1b28918dplougher
1376476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1377476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_ldir_inode_header sinode;
1378476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinode, block_ptr, sizeof(header.ldir));
1379476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_LDIR_INODE_HEADER_2(&header.ldir, &sinode);
1380476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1381476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&header.ldir, block_ptr, sizeof(header.ldir));
1382476dcb48b24efff22caa970f000e151f1b28918dplougher
13836f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inode->file_size;
13846f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.offset = inode->offset;
13856f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.start = inode->start_block;
13866f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.time = inode->mtime;
13873edfa57b6a463f7d441d995559143f4861d62e98plougher			break;
1388476dcb48b24efff22caa970f000e151f1b28918dplougher		}
1389476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_FILE_TYPE: {
1390476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_reg_inode_header_2 *inode = &header.reg;
1391476dcb48b24efff22caa970f000e151f1b28918dplougher
1392476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1393476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_reg_inode_header_2 sinode;
1394476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinode, block_ptr, sizeof(sinode));
1395476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_REG_INODE_HEADER_2(inode, &sinode);
1396476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1397476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(inode, block_ptr, sizeof(*inode));
1398476dcb48b24efff22caa970f000e151f1b28918dplougher
13996f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inode->file_size;
14006f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.time = inode->mtime;
14016f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ?
14026f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				0 : inode->file_size % sBlk.block_size;
14036f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.fragment = inode->fragment;
14046f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.offset = inode->offset;
14056f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ?
14066f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				(inode->file_size + sBlk.block_size - 1) >>
14076f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				sBlk.block_log : inode->file_size >> sBlk.block_log;
14086f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.start = inode->start_block;
14096f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.block_ptr = block_ptr + sizeof(*inode);
1410476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1411476dcb48b24efff22caa970f000e151f1b28918dplougher		}
1412476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_SYMLINK_TYPE: {
1413476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_symlink_inode_header_2 *inodep = &header.symlink;
1414476dcb48b24efff22caa970f000e151f1b28918dplougher
1415476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1416476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_symlink_inode_header_2 sinodep;
1417476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinodep, block_ptr, sizeof(sinodep));
1418476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, &sinodep);
1419476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1420476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(inodep, block_ptr, sizeof(*inodep));
1421476dcb48b24efff22caa970f000e151f1b28918dplougher
14226f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			strncpy(i.symlink, block_ptr + sizeof(squashfs_symlink_inode_header_2), inodep->symlink_size);
14236f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.symlink[inodep->symlink_size] = '\0';
14246f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inodep->symlink_size;
1425476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1426476dcb48b24efff22caa970f000e151f1b28918dplougher		}
1427476dcb48b24efff22caa970f000e151f1b28918dplougher 		case SQUASHFS_BLKDEV_TYPE:
1428476dcb48b24efff22caa970f000e151f1b28918dplougher	 	case SQUASHFS_CHRDEV_TYPE: {
1429476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_dev_inode_header_2 *inodep = &header.dev;
1430476dcb48b24efff22caa970f000e151f1b28918dplougher
1431476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1432476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_dev_inode_header_2 sinodep;
1433476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinodep, block_ptr, sizeof(sinodep));
1434476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, &sinodep);
1435476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1436476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(inodep, block_ptr, sizeof(*inodep));
1437476dcb48b24efff22caa970f000e151f1b28918dplougher
14386f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inodep->rdev;
1439476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1440476dcb48b24efff22caa970f000e151f1b28918dplougher			}
1441476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_FIFO_TYPE:
1442476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_SOCKET_TYPE:
14436f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = 0;
1444476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1445476dcb48b24efff22caa970f000e151f1b28918dplougher		default:
1446476dcb48b24efff22caa970f000e151f1b28918dplougher			ERROR("Unknown inode type %d in read_inode_header_2!\n", header.base.inode_type);
1447476dcb48b24efff22caa970f000e151f1b28918dplougher			return NULL;
1448476dcb48b24efff22caa970f000e151f1b28918dplougher	}
14496f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	return &i;
1450476dcb48b24efff22caa970f000e151f1b28918dplougher
1451476dcb48b24efff22caa970f000e151f1b28918dploughererror:
1452476dcb48b24efff22caa970f000e151f1b28918dplougher	return NULL;
1453476dcb48b24efff22caa970f000e151f1b28918dplougher}
1454476dcb48b24efff22caa970f000e151f1b28918dplougher
1455476dcb48b24efff22caa970f000e151f1b28918dplougher
14566f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougherstruct inode *read_inode_1(unsigned int start_block, unsigned int offset)
1457476dcb48b24efff22caa970f000e151f1b28918dplougher{
1458476dcb48b24efff22caa970f000e151f1b28918dplougher	static squashfs_inode_header_1 header;
1459476dcb48b24efff22caa970f000e151f1b28918dplougher	long long start = sBlk.inode_table_start + start_block;
1460545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	int bytes = lookup_entry(inode_table_hash, start);
1461476dcb48b24efff22caa970f000e151f1b28918dplougher	char *block_ptr = inode_table + bytes + offset;
14626f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	static struct inode i;
14636f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	static int inode_number = 1;
1464476dcb48b24efff22caa970f000e151f1b28918dplougher
1465476dcb48b24efff22caa970f000e151f1b28918dplougher	if(bytes == -1)
1466476dcb48b24efff22caa970f000e151f1b28918dplougher		goto error;
1467476dcb48b24efff22caa970f000e151f1b28918dplougher
1468476dcb48b24efff22caa970f000e151f1b28918dplougher	if(swap) {
1469476dcb48b24efff22caa970f000e151f1b28918dplougher		squashfs_base_inode_header_1 sinode;
1470476dcb48b24efff22caa970f000e151f1b28918dplougher		memcpy(&sinode, block_ptr, sizeof(header.base));
1471476dcb48b24efff22caa970f000e151f1b28918dplougher		SQUASHFS_SWAP_BASE_INODE_HEADER_1(&header.base, &sinode, sizeof(squashfs_base_inode_header_1));
1472476dcb48b24efff22caa970f000e151f1b28918dplougher	} else
1473476dcb48b24efff22caa970f000e151f1b28918dplougher		memcpy(&header.base, block_ptr, sizeof(header.base));
1474476dcb48b24efff22caa970f000e151f1b28918dplougher
14756f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher    i.uid = (uid_t) uid_table[(header.base.inode_type - 1) / SQUASHFS_TYPES * 16 + header.base.uid];
1476476dcb48b24efff22caa970f000e151f1b28918dplougher	if(header.base.inode_type == SQUASHFS_IPC_TYPE) {
1477476dcb48b24efff22caa970f000e151f1b28918dplougher		squashfs_ipc_inode_header_1 *inodep = &header.ipc;
1478476dcb48b24efff22caa970f000e151f1b28918dplougher
1479476dcb48b24efff22caa970f000e151f1b28918dplougher		if(swap) {
1480476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_ipc_inode_header_1 sinodep;
1481476dcb48b24efff22caa970f000e151f1b28918dplougher			memcpy(&sinodep, block_ptr, sizeof(sinodep));
1482476dcb48b24efff22caa970f000e151f1b28918dplougher			SQUASHFS_SWAP_IPC_INODE_HEADER_1(inodep, &sinodep);
1483476dcb48b24efff22caa970f000e151f1b28918dplougher		} else
1484476dcb48b24efff22caa970f000e151f1b28918dplougher			memcpy(inodep, block_ptr, sizeof(*inodep));
1485476dcb48b24efff22caa970f000e151f1b28918dplougher
1486476dcb48b24efff22caa970f000e151f1b28918dplougher		if(inodep->type == SQUASHFS_SOCKET_TYPE) {
14876f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.mode = S_IFSOCK | header.base.mode;
14886f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.type = SQUASHFS_SOCKET_TYPE;
148988facddfd83e48a907b82210ddccbb4f84d80aecplougher		} else {
14906f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.mode = S_IFIFO | header.base.mode;
14916f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.type = SQUASHFS_FIFO_TYPE;
1492476dcb48b24efff22caa970f000e151f1b28918dplougher		}
14936f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		i.uid = (uid_t) uid_table[inodep->offset * 16 + inodep->uid];
1494476dcb48b24efff22caa970f000e151f1b28918dplougher	} else {
14956f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		i.mode = lookup_type[(header.base.inode_type - 1) % SQUASHFS_TYPES + 1] | header.base.mode;
14966f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		i.type = (header.base.inode_type - 1) % SQUASHFS_TYPES + 1;
1497476dcb48b24efff22caa970f000e151f1b28918dplougher	}
14986f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher    i.gid = header.base.guid == 15 ? i.uid : (uid_t) guid_table[header.base.guid];
14996f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.time = sBlk.mkfs_time;
15006f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	i.inode_number = inode_number ++;
1501476dcb48b24efff22caa970f000e151f1b28918dplougher
15026f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	switch(i.type) {
150388facddfd83e48a907b82210ddccbb4f84d80aecplougher		case SQUASHFS_DIR_TYPE: {
150488facddfd83e48a907b82210ddccbb4f84d80aecplougher			squashfs_dir_inode_header_1 *inode = &header.dir;
15056f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
150688facddfd83e48a907b82210ddccbb4f84d80aecplougher			if(swap) {
150788facddfd83e48a907b82210ddccbb4f84d80aecplougher				squashfs_dir_inode_header_1 sinode;
150888facddfd83e48a907b82210ddccbb4f84d80aecplougher				memcpy(&sinode, block_ptr, sizeof(header.dir));
150988facddfd83e48a907b82210ddccbb4f84d80aecplougher				SQUASHFS_SWAP_DIR_INODE_HEADER_1(inode, &sinode);
151088facddfd83e48a907b82210ddccbb4f84d80aecplougher			} else
1511e05e7ae96eb9af6bb7e46c52f55b12469c24c7d9plougher			memcpy(inode, block_ptr, sizeof(header.dir));
151288facddfd83e48a907b82210ddccbb4f84d80aecplougher
15136f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inode->file_size;
15146f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.start = inode->start_block;
15156f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.time = inode->mtime;
1516e05e7ae96eb9af6bb7e46c52f55b12469c24c7d9plougher			break;
151788facddfd83e48a907b82210ddccbb4f84d80aecplougher		}
1518476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_FILE_TYPE: {
1519476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_reg_inode_header_1 *inode = &header.reg;
1520476dcb48b24efff22caa970f000e151f1b28918dplougher
1521476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1522476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_reg_inode_header_1 sinode;
1523476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinode, block_ptr, sizeof(sinode));
1524476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_REG_INODE_HEADER_1(inode, &sinode);
1525476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1526476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(inode, block_ptr, sizeof(*inode));
1527476dcb48b24efff22caa970f000e151f1b28918dplougher
15286f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inode->file_size;
15296f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.time = inode->mtime;
15306f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.blocks = (inode->file_size + sBlk.block_size - 1) >>
15316f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				sBlk.block_log;
15326f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.start = inode->start_block;
15336f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.block_ptr = block_ptr + sizeof(*inode);
15346f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.fragment = 0;
15356f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.frag_bytes = 0;
15366f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.offset = 0;
1537e05e7ae96eb9af6bb7e46c52f55b12469c24c7d9plougher			break;
1538476dcb48b24efff22caa970f000e151f1b28918dplougher		}
1539476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_SYMLINK_TYPE: {
1540476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_symlink_inode_header_1 *inodep = &header.symlink;
1541476dcb48b24efff22caa970f000e151f1b28918dplougher
1542476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1543476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_symlink_inode_header_1 sinodep;
1544476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinodep, block_ptr, sizeof(sinodep));
1545476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(inodep, &sinodep);
1546476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1547476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(inodep, block_ptr, sizeof(*inodep));
1548476dcb48b24efff22caa970f000e151f1b28918dplougher
15496f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			strncpy(i.symlink, block_ptr + sizeof(squashfs_symlink_inode_header_1), inodep->symlink_size);
15506f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.symlink[inodep->symlink_size] = '\0';
15516f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inodep->symlink_size;
1552476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1553476dcb48b24efff22caa970f000e151f1b28918dplougher		}
1554476dcb48b24efff22caa970f000e151f1b28918dplougher 		case SQUASHFS_BLKDEV_TYPE:
1555476dcb48b24efff22caa970f000e151f1b28918dplougher	 	case SQUASHFS_CHRDEV_TYPE: {
1556476dcb48b24efff22caa970f000e151f1b28918dplougher			squashfs_dev_inode_header_1 *inodep = &header.dev;
1557476dcb48b24efff22caa970f000e151f1b28918dplougher
1558476dcb48b24efff22caa970f000e151f1b28918dplougher			if(swap) {
1559476dcb48b24efff22caa970f000e151f1b28918dplougher				squashfs_dev_inode_header_1 sinodep;
1560476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(&sinodep, block_ptr, sizeof(sinodep));
1561476dcb48b24efff22caa970f000e151f1b28918dplougher				SQUASHFS_SWAP_DEV_INODE_HEADER_1(inodep, &sinodep);
1562476dcb48b24efff22caa970f000e151f1b28918dplougher			} else
1563476dcb48b24efff22caa970f000e151f1b28918dplougher				memcpy(inodep, block_ptr, sizeof(*inodep));
1564476dcb48b24efff22caa970f000e151f1b28918dplougher
15656f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = inodep->rdev;
1566476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1567476dcb48b24efff22caa970f000e151f1b28918dplougher			}
1568476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_FIFO_TYPE:
1569476dcb48b24efff22caa970f000e151f1b28918dplougher		case SQUASHFS_SOCKET_TYPE: {
15706f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			i.data = 0;
1571476dcb48b24efff22caa970f000e151f1b28918dplougher			break;
1572476dcb48b24efff22caa970f000e151f1b28918dplougher			}
1573476dcb48b24efff22caa970f000e151f1b28918dplougher		default:
1574476dcb48b24efff22caa970f000e151f1b28918dplougher			ERROR("Unknown inode type %d in read_inode_header_1!\n", header.base.inode_type);
1575476dcb48b24efff22caa970f000e151f1b28918dplougher			return NULL;
1576476dcb48b24efff22caa970f000e151f1b28918dplougher	}
15776f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	return &i;
1578476dcb48b24efff22caa970f000e151f1b28918dplougher
1579476dcb48b24efff22caa970f000e151f1b28918dploughererror:
1580476dcb48b24efff22caa970f000e151f1b28918dplougher	return NULL;
1581476dcb48b24efff22caa970f000e151f1b28918dplougher}
1582476dcb48b24efff22caa970f000e151f1b28918dplougher
1583476dcb48b24efff22caa970f000e151f1b28918dplougher
158402bc3bcabf2b219f63961f07293b83629948f026ploughervoid uncompress_directory_table(long long start, long long end)
1585443c15812032991c98b33b5424b17bcd55fe3575plougher{
1586443c15812032991c98b33b5424b17bcd55fe3575plougher	int bytes = 0, size = 0, res;
1587443c15812032991c98b33b5424b17bcd55fe3575plougher
1588443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
15899dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		if(size - bytes < SQUASHFS_METADATA_SIZE && (directory_table =
15909dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				realloc(directory_table, size +=
15919dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher				SQUASHFS_METADATA_SIZE)) == NULL)
1592443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_directory_table: out of memory in realloc\n");
1593443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("uncompress_directory_table: reading block 0x%llx\n", start);
1594443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(directory_table_hash, start, bytes);
159502bc3bcabf2b219f63961f07293b83629948f026plougher		if((res = read_block(start, &start, directory_table + bytes)) == 0)
1596443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_directory_table: failed to read block\n");
1597443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
1598443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1599443c15812032991c98b33b5424b17bcd55fe3575plougher}
1600443c15812032991c98b33b5424b17bcd55fe3575plougher
1601443c15812032991c98b33b5424b17bcd55fe3575plougher
1602443c15812032991c98b33b5424b17bcd55fe3575plougher#define DIR_ENT_SIZE	16
1603443c15812032991c98b33b5424b17bcd55fe3575plougher
1604443c15812032991c98b33b5424b17bcd55fe3575plougherstruct dir_ent	{
1605443c15812032991c98b33b5424b17bcd55fe3575plougher	char		name[SQUASHFS_NAME_LEN + 1];
1606443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	start_block;
1607443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	offset;
1608443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	type;
1609443c15812032991c98b33b5424b17bcd55fe3575plougher};
1610443c15812032991c98b33b5424b17bcd55fe3575plougher
1611443c15812032991c98b33b5424b17bcd55fe3575plougherstruct dir {
1612443c15812032991c98b33b5424b17bcd55fe3575plougher	int		dir_count;
1613443c15812032991c98b33b5424b17bcd55fe3575plougher	int 		cur_entry;
1614443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	mode;
16156f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	uid_t		uid;
16166f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	gid_t		guid;
1617443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	mtime;
1618443c15812032991c98b33b5424b17bcd55fe3575plougher	struct dir_ent	*dirs;
1619443c15812032991c98b33b5424b17bcd55fe3575plougher};
1620443c15812032991c98b33b5424b17bcd55fe3575plougher
1621443c15812032991c98b33b5424b17bcd55fe3575plougher
1622eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherstruct dir *squashfs_opendir(unsigned int block_start, unsigned int offset, struct inode **i)
1623443c15812032991c98b33b5424b17bcd55fe3575plougher{
1624443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_dir_header dirh;
1625443c15812032991c98b33b5424b17bcd55fe3575plougher	char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
1626443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer;
16276f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	long long start;
16286f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int bytes;
1629443c15812032991c98b33b5424b17bcd55fe3575plougher	int dir_count, size;
1630443c15812032991c98b33b5424b17bcd55fe3575plougher	struct dir_ent *new_dir;
1631443c15812032991c98b33b5424b17bcd55fe3575plougher	struct dir *dir;
1632443c15812032991c98b33b5424b17bcd55fe3575plougher
1633fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("squashfs_opendir: inode start block %d, offset %d\n", block_start, offset);
1634443c15812032991c98b33b5424b17bcd55fe3575plougher
1635eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if((*i = s_ops.read_inode(block_start, offset)) == NULL) {
16366f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		ERROR("squashfs_opendir: failed to read directory inode %d\n", block_start);
1637443c15812032991c98b33b5424b17bcd55fe3575plougher		return NULL;
1638443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1639443c15812032991c98b33b5424b17bcd55fe3575plougher
1640eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	start = sBlk.directory_table_start + (*i)->start;
1641443c15812032991c98b33b5424b17bcd55fe3575plougher	bytes = lookup_entry(directory_table_hash, start);
1642443c15812032991c98b33b5424b17bcd55fe3575plougher
1643443c15812032991c98b33b5424b17bcd55fe3575plougher	if(bytes == -1) {
1644fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher		ERROR("squashfs_opendir: directory block %d not found!\n", block_start);
1645443c15812032991c98b33b5424b17bcd55fe3575plougher		return NULL;
1646443c15812032991c98b33b5424b17bcd55fe3575plougher	}
16476f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
1648eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	bytes += (*i)->offset;
1649eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	size = (*i)->data + bytes - 3;
1650443c15812032991c98b33b5424b17bcd55fe3575plougher
1651443c15812032991c98b33b5424b17bcd55fe3575plougher	if((dir = malloc(sizeof(struct dir))) == NULL) {
1652443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("squashfs_opendir: malloc failed!\n");
1653443c15812032991c98b33b5424b17bcd55fe3575plougher		return NULL;
1654443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1655443c15812032991c98b33b5424b17bcd55fe3575plougher
1656443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->dir_count = 0;
1657443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->cur_entry = 0;
1658eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	dir->mode = (*i)->mode;
1659eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	dir->uid = (*i)->uid;
1660eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	dir->guid = (*i)->gid;
1661eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	dir->mtime = (*i)->time;
1662443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->dirs = NULL;
1663443c15812032991c98b33b5424b17bcd55fe3575plougher
1664fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	while(bytes < size) {
1665443c15812032991c98b33b5424b17bcd55fe3575plougher		if(swap) {
1666443c15812032991c98b33b5424b17bcd55fe3575plougher			squashfs_dir_header sdirh;
1667443c15812032991c98b33b5424b17bcd55fe3575plougher			memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
1668443c15812032991c98b33b5424b17bcd55fe3575plougher			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
1669443c15812032991c98b33b5424b17bcd55fe3575plougher		} else
1670443c15812032991c98b33b5424b17bcd55fe3575plougher			memcpy(&dirh, directory_table + bytes, sizeof(dirh));
1671fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
1672443c15812032991c98b33b5424b17bcd55fe3575plougher		dir_count = dirh.count + 1;
1673fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher		TRACE("squashfs_opendir: Read directory header @ byte position %d, %d directory entries\n", bytes, dir_count);
1674443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += sizeof(dirh);
1675443c15812032991c98b33b5424b17bcd55fe3575plougher
1676443c15812032991c98b33b5424b17bcd55fe3575plougher		while(dir_count--) {
1677443c15812032991c98b33b5424b17bcd55fe3575plougher			if(swap) {
1678443c15812032991c98b33b5424b17bcd55fe3575plougher				squashfs_dir_entry sdire;
1679443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(&sdire, directory_table + bytes, sizeof(sdire));
1680443c15812032991c98b33b5424b17bcd55fe3575plougher				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
1681443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
1682443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(dire, directory_table + bytes, sizeof(dire));
1683443c15812032991c98b33b5424b17bcd55fe3575plougher			bytes += sizeof(*dire);
1684443c15812032991c98b33b5424b17bcd55fe3575plougher
1685443c15812032991c98b33b5424b17bcd55fe3575plougher			memcpy(dire->name, directory_table + bytes, dire->size + 1);
1686443c15812032991c98b33b5424b17bcd55fe3575plougher			dire->name[dire->size + 1] = '\0';
1687fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			TRACE("squashfs_opendir: directory entry %s, inode %d:%d, type %d\n", dire->name, dirh.start_block, dire->offset, dire->type);
1688443c15812032991c98b33b5424b17bcd55fe3575plougher			if((dir->dir_count % DIR_ENT_SIZE) == 0) {
1689443c15812032991c98b33b5424b17bcd55fe3575plougher				if((new_dir = realloc(dir->dirs, (dir->dir_count + DIR_ENT_SIZE) * sizeof(struct dir_ent))) == NULL) {
1690443c15812032991c98b33b5424b17bcd55fe3575plougher					ERROR("squashfs_opendir: realloc failed!\n");
1691443c15812032991c98b33b5424b17bcd55fe3575plougher					free(dir->dirs);
1692443c15812032991c98b33b5424b17bcd55fe3575plougher					free(dir);
1693443c15812032991c98b33b5424b17bcd55fe3575plougher					return NULL;
1694443c15812032991c98b33b5424b17bcd55fe3575plougher				}
1695443c15812032991c98b33b5424b17bcd55fe3575plougher				dir->dirs = new_dir;
1696443c15812032991c98b33b5424b17bcd55fe3575plougher			}
1697443c15812032991c98b33b5424b17bcd55fe3575plougher			strcpy(dir->dirs[dir->dir_count].name, dire->name);
1698443c15812032991c98b33b5424b17bcd55fe3575plougher			dir->dirs[dir->dir_count].start_block = dirh.start_block;
1699443c15812032991c98b33b5424b17bcd55fe3575plougher			dir->dirs[dir->dir_count].offset = dire->offset;
1700443c15812032991c98b33b5424b17bcd55fe3575plougher			dir->dirs[dir->dir_count].type = dire->type;
1701443c15812032991c98b33b5424b17bcd55fe3575plougher			dir->dir_count ++;
1702443c15812032991c98b33b5424b17bcd55fe3575plougher			bytes += dire->size + 1;
1703443c15812032991c98b33b5424b17bcd55fe3575plougher		}
1704443c15812032991c98b33b5424b17bcd55fe3575plougher	}
1705443c15812032991c98b33b5424b17bcd55fe3575plougher
1706443c15812032991c98b33b5424b17bcd55fe3575plougher	return dir;
1707443c15812032991c98b33b5424b17bcd55fe3575plougher}
1708443c15812032991c98b33b5424b17bcd55fe3575plougher
1709443c15812032991c98b33b5424b17bcd55fe3575plougher
1710eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherstruct dir *squashfs_opendir_2(unsigned int block_start, unsigned int offset, struct inode **i)
171102bc3bcabf2b219f63961f07293b83629948f026plougher{
171202bc3bcabf2b219f63961f07293b83629948f026plougher	squashfs_dir_header_2 dirh;
171302bc3bcabf2b219f63961f07293b83629948f026plougher	char buffer[sizeof(squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1];
171402bc3bcabf2b219f63961f07293b83629948f026plougher	squashfs_dir_entry_2 *dire = (squashfs_dir_entry_2 *) buffer;
17156f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	long long start;
17166f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher	int bytes;
171702bc3bcabf2b219f63961f07293b83629948f026plougher	int dir_count, size;
171802bc3bcabf2b219f63961f07293b83629948f026plougher	struct dir_ent *new_dir;
171902bc3bcabf2b219f63961f07293b83629948f026plougher	struct dir *dir;
172002bc3bcabf2b219f63961f07293b83629948f026plougher
172102bc3bcabf2b219f63961f07293b83629948f026plougher	TRACE("squashfs_opendir: inode start block %d, offset %d\n", block_start, offset);
172202bc3bcabf2b219f63961f07293b83629948f026plougher
1723eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(((*i) = s_ops.read_inode(block_start, offset)) == NULL) {
17246f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		ERROR("squashfs_opendir: failed to read directory inode %d\n", block_start);
172502bc3bcabf2b219f63961f07293b83629948f026plougher		return NULL;
172602bc3bcabf2b219f63961f07293b83629948f026plougher	}
172702bc3bcabf2b219f63961f07293b83629948f026plougher
1728eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	start = sBlk.directory_table_start + (*i)->start;
172902bc3bcabf2b219f63961f07293b83629948f026plougher	bytes = lookup_entry(directory_table_hash, start);
173002bc3bcabf2b219f63961f07293b83629948f026plougher
173102bc3bcabf2b219f63961f07293b83629948f026plougher	if(bytes == -1) {
173202bc3bcabf2b219f63961f07293b83629948f026plougher		ERROR("squashfs_opendir: directory block %d not found!\n", block_start);
173302bc3bcabf2b219f63961f07293b83629948f026plougher		return NULL;
173402bc3bcabf2b219f63961f07293b83629948f026plougher	}
1735ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
1736eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	bytes += (*i)->offset;
1737eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	size = (*i)->data + bytes;
1738ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
1739ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	if((dir = malloc(sizeof(struct dir))) == NULL) {
1740ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		ERROR("squashfs_opendir: malloc failed!\n");
1741ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		return NULL;
1742ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	}
1743ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
1744ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	dir->dir_count = 0;
1745ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	dir->cur_entry = 0;
1746eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	dir->mode = (*i)->mode;
1747eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	dir->uid = (*i)->uid;
1748eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	dir->guid = (*i)->gid;
1749eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	dir->mtime = (*i)->time;
1750ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	dir->dirs = NULL;
1751ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
1752ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	while(bytes < size) {
1753ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		if(swap) {
1754ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			squashfs_dir_header_2 sdirh;
1755ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
1756ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
1757ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		} else
1758ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			memcpy(&dirh, directory_table + bytes, sizeof(dirh));
1759ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
1760ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		dir_count = dirh.count + 1;
1761ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		TRACE("squashfs_opendir: Read directory header @ byte position %d, %d directory entries\n", bytes, dir_count);
1762ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		bytes += sizeof(dirh);
1763ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
1764ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		while(dir_count--) {
1765ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			if(swap) {
1766ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher				squashfs_dir_entry_2 sdire;
1767ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher				memcpy(&sdire, directory_table + bytes, sizeof(sdire));
1768ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher				SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
1769ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			} else
1770ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher				memcpy(dire, directory_table + bytes, sizeof(dire));
1771ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			bytes += sizeof(*dire);
1772ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
1773ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			memcpy(dire->name, directory_table + bytes, dire->size + 1);
1774ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			dire->name[dire->size + 1] = '\0';
1775ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			TRACE("squashfs_opendir: directory entry %s, inode %d:%d, type %d\n", dire->name, dirh.start_block, dire->offset, dire->type);
1776ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			if((dir->dir_count % DIR_ENT_SIZE) == 0) {
1777ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher				if((new_dir = realloc(dir->dirs, (dir->dir_count + DIR_ENT_SIZE) * sizeof(struct dir_ent))) == NULL) {
1778ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher					ERROR("squashfs_opendir: realloc failed!\n");
1779ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher					free(dir->dirs);
1780ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher					free(dir);
1781ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher					return NULL;
1782ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher				}
1783ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher				dir->dirs = new_dir;
1784ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			}
1785ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			strcpy(dir->dirs[dir->dir_count].name, dire->name);
1786ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			dir->dirs[dir->dir_count].start_block = dirh.start_block;
1787ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			dir->dirs[dir->dir_count].offset = dire->offset;
1788ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			dir->dirs[dir->dir_count].type = dire->type;
1789ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			dir->dir_count ++;
1790ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			bytes += dire->size + 1;
1791ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		}
1792ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	}
1793ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
1794ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	return dir;
1795ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher}
1796ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
1797ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
17989dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherint squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block,
17999dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougherunsigned int *offset, unsigned int *type)
1800443c15812032991c98b33b5424b17bcd55fe3575plougher{
1801443c15812032991c98b33b5424b17bcd55fe3575plougher	if(dir->cur_entry == dir->dir_count)
1802443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
1803443c15812032991c98b33b5424b17bcd55fe3575plougher
1804443c15812032991c98b33b5424b17bcd55fe3575plougher	*name = dir->dirs[dir->cur_entry].name;
1805443c15812032991c98b33b5424b17bcd55fe3575plougher	*start_block = dir->dirs[dir->cur_entry].start_block;
1806443c15812032991c98b33b5424b17bcd55fe3575plougher	*offset = dir->dirs[dir->cur_entry].offset;
1807443c15812032991c98b33b5424b17bcd55fe3575plougher	*type = dir->dirs[dir->cur_entry].type;
1808443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->cur_entry ++;
1809443c15812032991c98b33b5424b17bcd55fe3575plougher
1810443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
1811443c15812032991c98b33b5424b17bcd55fe3575plougher}
1812443c15812032991c98b33b5424b17bcd55fe3575plougher
1813443c15812032991c98b33b5424b17bcd55fe3575plougher
1814443c15812032991c98b33b5424b17bcd55fe3575ploughervoid squashfs_closedir(struct dir *dir)
1815443c15812032991c98b33b5424b17bcd55fe3575plougher{
1816443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir->dirs);
1817443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir);
1818443c15812032991c98b33b5424b17bcd55fe3575plougher}
1819443c15812032991c98b33b5424b17bcd55fe3575plougher
1820443c15812032991c98b33b5424b17bcd55fe3575plougher
1821b54566f5c433764830c29c83151691d0034de094plougherchar *get_component(char *target, char *targname)
1822b54566f5c433764830c29c83151691d0034de094plougher{
1823b54566f5c433764830c29c83151691d0034de094plougher	while(*target == '/')
18243cef656655723444fb1e2de1a001e6c2a54cf81erlougher		target ++;
1825b54566f5c433764830c29c83151691d0034de094plougher
1826b54566f5c433764830c29c83151691d0034de094plougher	while(*target != '/' && *target!= '\0')
1827b54566f5c433764830c29c83151691d0034de094plougher		*targname ++ = *target ++;
1828b54566f5c433764830c29c83151691d0034de094plougher
1829b54566f5c433764830c29c83151691d0034de094plougher	*targname = '\0';
1830b54566f5c433764830c29c83151691d0034de094plougher
1831b54566f5c433764830c29c83151691d0034de094plougher	return target;
1832b54566f5c433764830c29c83151691d0034de094plougher}
1833b54566f5c433764830c29c83151691d0034de094plougher
1834b54566f5c433764830c29c83151691d0034de094plougher
183571add234b27054974d5e29f95b3fab3072792a62plougherstruct path_entry {
183671add234b27054974d5e29f95b3fab3072792a62plougher	char *name;
18374dba330d7b952f2f044d38e342e2ae3ea78910d6plougher	regex_t *preg;
183871add234b27054974d5e29f95b3fab3072792a62plougher	struct pathname *paths;
183971add234b27054974d5e29f95b3fab3072792a62plougher};
184071add234b27054974d5e29f95b3fab3072792a62plougher
184171add234b27054974d5e29f95b3fab3072792a62plougherstruct pathname {
184271add234b27054974d5e29f95b3fab3072792a62plougher	int names;
184371add234b27054974d5e29f95b3fab3072792a62plougher	struct path_entry *name;
184471add234b27054974d5e29f95b3fab3072792a62plougher};
184571add234b27054974d5e29f95b3fab3072792a62plougher
1846a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames {
1847a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	int count;
1848a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathname *path[0];
1849a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher};
1850a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher#define PATHS_ALLOC_SIZE 10
185171add234b27054974d5e29f95b3fab3072792a62plougher
18526ee88c6b5da9f7b3ea88ab7481db126efa01c8f4ploughervoid free_path(struct pathname *paths)
18536ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher{
18546ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	int i;
18556ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
18566ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	for(i = 0; i < paths->names; i++) {
18576ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths)
18586ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
18596ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		free(paths->name[i].name);
18606ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].preg) {
18616ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			regfree(paths->name[i].preg);
18626ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free(paths->name[i].preg);
18636ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		}
18646ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	}
18656ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
18666ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	free(paths);
18676ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher}
18686ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
18696ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
18704dba330d7b952f2f044d38e342e2ae3ea78910d6plougherstruct pathname *add_path(struct pathname *paths, char *target, char *alltarget)
1871b54566f5c433764830c29c83151691d0034de094plougher{
187271add234b27054974d5e29f95b3fab3072792a62plougher	char targname[1024];
18734dba330d7b952f2f044d38e342e2ae3ea78910d6plougher	int i, error;
187471add234b27054974d5e29f95b3fab3072792a62plougher
187571add234b27054974d5e29f95b3fab3072792a62plougher	target = get_component(target, targname);
187671add234b27054974d5e29f95b3fab3072792a62plougher
187771add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
18784dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		if((paths = malloc(sizeof(struct pathname))) == NULL)
18794dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			EXIT_UNSQUASH("failed to allocate paths\n");
18804dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
188171add234b27054974d5e29f95b3fab3072792a62plougher		paths->names = 0;
188271add234b27054974d5e29f95b3fab3072792a62plougher		paths->name = NULL;
188371add234b27054974d5e29f95b3fab3072792a62plougher	}
188471add234b27054974d5e29f95b3fab3072792a62plougher
188571add234b27054974d5e29f95b3fab3072792a62plougher	for(i = 0; i < paths->names; i++)
188671add234b27054974d5e29f95b3fab3072792a62plougher		if(strcmp(paths->name[i].name, targname) == 0)
188771add234b27054974d5e29f95b3fab3072792a62plougher			break;
188871add234b27054974d5e29f95b3fab3072792a62plougher
18896ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	if(i == paths->names) {
18906ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		/* allocate new name entry */
189171add234b27054974d5e29f95b3fab3072792a62plougher		paths->names ++;
189271add234b27054974d5e29f95b3fab3072792a62plougher		paths->name = realloc(paths->name, (i + 1) * sizeof(struct path_entry));
189371add234b27054974d5e29f95b3fab3072792a62plougher		paths->name[i].name = strdup(targname);
18946ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		paths->name[i].paths = NULL;
18954dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		if(use_regex) {
18964dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = malloc(sizeof(regex_t));
1897545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			error = regcomp(paths->name[i].preg, targname, REG_EXTENDED|REG_NOSUB);
1898545404219cdd79c1e06ac7d0698d02a15240c4c3plougher			if(error) {
18994dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				char str[1024];
19004dba330d7b952f2f044d38e342e2ae3ea78910d6plougher
19014dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				regerror(error, paths->name[i].preg, str, 1024);
19024dba330d7b952f2f044d38e342e2ae3ea78910d6plougher				EXIT_UNSQUASH("invalid regex %s in export %s, because %s\n", targname, alltarget, str);
19034dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			}
19044dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		} else
19054dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].preg = NULL;
19066ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
19076ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(target[0] == '\0')
19086ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			/* at leaf pathname component */
190971add234b27054974d5e29f95b3fab3072792a62plougher			paths->name[i].paths = NULL;
191071add234b27054974d5e29f95b3fab3072792a62plougher		else
19116ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			/* recurse adding child components */
19124dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			paths->name[i].paths = add_path(NULL, target, alltarget);
19136ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher	} else {
19146ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		/* existing matching entry */
19156ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		if(paths->name[i].paths == NULL) {
19166ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			/* No sub-directory which means this is the leaf component of a
19176ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		   	   pre-existing extract which subsumes the extract currently
19186ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		   	   being added, in which case stop adding components */
19196ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else if(target[0] == '\0') {
19206ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			/* at leaf pathname component and child components exist from more
19216ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		       specific extracts, delete as they're subsumed by this extract
19226ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			*/
19236ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			free_path(paths->name[i].paths);
19246ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			paths->name[i].paths = NULL;
19256ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher		} else
19266ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			/* recurse adding child components */
19276ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher			add_path(paths->name[i].paths, target, alltarget);
192871add234b27054974d5e29f95b3fab3072792a62plougher	}
192971add234b27054974d5e29f95b3fab3072792a62plougher
193071add234b27054974d5e29f95b3fab3072792a62plougher	return paths;
193171add234b27054974d5e29f95b3fab3072792a62plougher}
19326ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
19336ee88c6b5da9f7b3ea88ab7481db126efa01c8f4plougher
1934a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *init_subdir()
193571add234b27054974d5e29f95b3fab3072792a62plougher{
1936a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *new = malloc(sizeof(struct pathnames *));
1937a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	new->count = 0;
1938a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return new;
1939a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1940a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1941a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1942a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathnames *add_subdir(struct pathnames *paths, struct pathname *path)
1943a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1944a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if(paths->count % PATHS_ALLOC_SIZE == 0)
1945a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = realloc(paths, sizeof(struct pathnames *) + (paths->count + PATHS_ALLOC_SIZE) * sizeof(struct pathname *));
1946a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1947a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	paths->path[paths->count++] = path;
1948a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return paths;
1949a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1950a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1951a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1952a706f1b6bb48f288ecaf74e218ce20504bda52c6ploughervoid free_subdir(struct pathnames *paths)
1953a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1954a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free(paths);
1955a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher}
1956a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1957a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1958a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherint matches(struct pathnames *paths, char *name, struct pathnames **new)
1959a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher{
1960a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	int i, n;
196171add234b27054974d5e29f95b3fab3072792a62plougher
196271add234b27054974d5e29f95b3fab3072792a62plougher	if(paths == NULL) {
196371add234b27054974d5e29f95b3fab3072792a62plougher		*new = NULL;
1964b54566f5c433764830c29c83151691d0034de094plougher		return TRUE;
196571add234b27054974d5e29f95b3fab3072792a62plougher	}
196671add234b27054974d5e29f95b3fab3072792a62plougher
1967a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = init_subdir();
1968a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1969a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	for(n = 0; n < paths->count; n++) {
1970a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		struct pathname *path = paths->path[n];
1971a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		for(i = 0; i < path->names; i++) {
1972a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			int match = use_regex ?
1973a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				regexec(path->name[i].preg, name, (size_t) 0, NULL, 0) == 0 :
1974a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				fnmatch(path->name[i].name, name, FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0;
1975a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match && path->name[i].paths == NULL)
1976a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				/* match on a leaf component, any subdirectories will
1977a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				 * implicitly match, therefore return an empty new search set */
1978a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				goto empty_set;
1979a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1980a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			if(match)
1981a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				/* match on a non-leaf component, add any subdirectories to
1982a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				 * the new set of subdirectories to scan for this name */
1983a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher				*new = add_subdir(*new, path->name[i].paths);
1984a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		}
1985a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1986b54566f5c433764830c29c83151691d0034de094plougher
1987a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if((*new)->count == 0) {
1988a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		/* no matching names found, delete empty search set, and return
1989a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher        * FALSE */
1990a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(*new);
1991a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		*new = NULL;
1992a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		return FALSE;
1993a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
1994a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1995a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	/* one or more matches with sub-directories found (no leaf matches),
1996a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher     * return new search set and return TRUE */
1997a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
1998a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
1999a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherempty_set:
2000a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher   /* found matching leaf exclude, return empty search set and return TRUE */
2001a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	free_subdir(*new);
2002a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	*new = NULL;
2003a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return TRUE;
2004b54566f5c433764830c29c83151691d0034de094plougher}
2005b54566f5c433764830c29c83151691d0034de094plougher
2006b54566f5c433764830c29c83151691d0034de094plougher
2007eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougherint pre_scan(char *parent_name, unsigned int start_block, unsigned int offset, struct pathnames *paths)
2008eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
2009eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	unsigned int type;
2010eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	char *name, pathname[1024];
2011eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct pathnames *new;
2012eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
2013eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
2014eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2015eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(dir == NULL) {
2016eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		ERROR("pre_scan: Failed to read directory %s (%x:%x)\n", parent_name, start_block, offset);
2017eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		return FALSE;
2018eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
2019eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2020eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
2021eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		struct inode *i;
2022eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2023eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		TRACE("pre_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type);
2024eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2025eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(!matches(paths, name, &new))
2026eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			continue;
2027eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2028eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
2029eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2030eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(type == SQUASHFS_DIR_TYPE)
2031eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			pre_scan(parent_name, start_block, offset, new);
2032eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		else if(new == NULL) {
2033eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			if(type == SQUASHFS_FILE_TYPE || type == SQUASHFS_LREG_TYPE) {
2034eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				if((i = s_ops.read_inode(start_block, offset)) == NULL) {
2035eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher					ERROR("failed to read header\n");
2036eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher					continue;
2037eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
2038eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				if(created_inode[i->inode_number - 1] == NULL) {
2039eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher					created_inode[i->inode_number - 1] = (char *) i;
2040eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher					total_blocks += (i->data + (block_size - 1)) >> block_log;
2041eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
2042eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				total_files ++;
2043eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			}
2044eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			total_inodes ++;
2045eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		}
2046eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2047eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		free_subdir(new);
2048eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
2049eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2050eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	squashfs_closedir(dir);
2051eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2052eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	return TRUE;
2053eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
2054eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2055eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2056a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherint dir_scan(char *parent_name, unsigned int start_block, unsigned int offset, struct pathnames *paths)
2057443c15812032991c98b33b5424b17bcd55fe3575plougher{
2058443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int type;
2059443c15812032991c98b33b5424b17bcd55fe3575plougher	char *name, pathname[1024];
2060a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *new;
2061eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct inode *i;
2062eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i);
2063443c15812032991c98b33b5424b17bcd55fe3575plougher
2064443c15812032991c98b33b5424b17bcd55fe3575plougher	if(dir == NULL) {
2065fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher		ERROR("dir_scan: Failed to read directory %s (%x:%x)\n", parent_name, start_block, offset);
2066443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
2067443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2068443c15812032991c98b33b5424b17bcd55fe3575plougher
2069eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(lsonly || info)
2070eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		print_filename(parent_name, i);
2071eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2072a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher	if(!lsonly && mkdir(parent_name, (mode_t) dir->mode) == -1 && (!force || errno != EEXIST)) {
2073443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("dir_scan: failed to open directory %s, because %s\n", parent_name, strerror(errno));
2074443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
2075443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2076443c15812032991c98b33b5424b17bcd55fe3575plougher
2077443c15812032991c98b33b5424b17bcd55fe3575plougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
20786f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type);
2079b54566f5c433764830c29c83151691d0034de094plougher
208071add234b27054974d5e29f95b3fab3072792a62plougher
208171add234b27054974d5e29f95b3fab3072792a62plougher		if(!matches(paths, name, &new))
2082b54566f5c433764830c29c83151691d0034de094plougher			continue;
2083b54566f5c433764830c29c83151691d0034de094plougher
2084443c15812032991c98b33b5424b17bcd55fe3575plougher		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
2085fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
2086443c15812032991c98b33b5424b17bcd55fe3575plougher		if(type == SQUASHFS_DIR_TYPE)
208771add234b27054974d5e29f95b3fab3072792a62plougher			dir_scan(pathname, start_block, offset, new);
2088a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		else if(new == NULL) {
20896f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if((i = s_ops.read_inode(start_block, offset)) == NULL) {
20906f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				ERROR("failed to read header\n");
20916f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				continue;
20926f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			}
20936f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
20946f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			if(lsonly || info)
20956f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				print_filename(pathname, i);
20966f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher
2097eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			if(!lsonly) {
20986f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher				create_inode(pathname, i);
2099eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				update_progress_bar();
2100eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher				}
21016f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		}
2102a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
2103a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		free_subdir(new);
2104443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2105443c15812032991c98b33b5424b17bcd55fe3575plougher
2106074d3f1129eae914655f6637773488052bf22327rlougher	if(!lsonly)
2107074d3f1129eae914655f6637773488052bf22327rlougher		set_attributes(parent_name, dir->mode, dir->uid, dir->guid, dir->mtime, force);
2108443c15812032991c98b33b5424b17bcd55fe3575plougher
2109443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_closedir(dir);
2110443c15812032991c98b33b5424b17bcd55fe3575plougher	dir_count ++;
2111443c15812032991c98b33b5424b17bcd55fe3575plougher
2112443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
2113443c15812032991c98b33b5424b17bcd55fe3575plougher}
2114443c15812032991c98b33b5424b17bcd55fe3575plougher
2115443c15812032991c98b33b5424b17bcd55fe3575plougher
2116b624936abba03d38b7e9245c647339d8f6f34274ploughervoid squashfs_stat(char *source)
2117b624936abba03d38b7e9245c647339d8f6f34274plougher{
2118b624936abba03d38b7e9245c647339d8f6f34274plougher	time_t mkfs_time = (time_t) sBlk.mkfs_time;
2119b624936abba03d38b7e9245c647339d8f6f34274plougher	char *mkfs_str = ctime(&mkfs_time);
2120b624936abba03d38b7e9245c647339d8f6f34274plougher
2121b624936abba03d38b7e9245c647339d8f6f34274plougher#if __BYTE_ORDER == __BIG_ENDIAN
2122b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Found a valid %s endian SQUASHFS %d:%d superblock on %s.\n", swap ? "little" : "big", sBlk.s_major, sBlk.s_minor, source);
2123b624936abba03d38b7e9245c647339d8f6f34274plougher#else
2124b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Found a valid %s endian SQUASHFS %d:%d superblock on %s.\n", swap ? "big" : "little", sBlk.s_major, sBlk.s_minor, source);
2125b624936abba03d38b7e9245c647339d8f6f34274plougher#endif
2126b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Creation or last append time %s", mkfs_str ? mkfs_str : "failed to get time\n");
2127b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Filesystem is %sexportable via NFS\n", SQUASHFS_EXPORTABLE(sBlk.flags) ? "" : "not ");
2128b624936abba03d38b7e9245c647339d8f6f34274plougher
2129b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags) ? "un" : "");
2130b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags) ? "un" : "");
2131b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1 && !SQUASHFS_NO_FRAGMENTS(sBlk.flags))
2132b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Fragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags) ? "un" : "");
2133b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Check data is %spresent in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk.flags) ? "" : "not ");
2134b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1) {
2135b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Fragments are %spresent in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk.flags) ? "not " : "");
2136b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Always_use_fragments option is %sspecified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags) ? "" : "not ");
2137b624936abba03d38b7e9245c647339d8f6f34274plougher	} else
2138b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Fragments are not supported by the filesystem\n");
2139b624936abba03d38b7e9245c647339d8f6f34274plougher
21400337de3977eec74e6a3d28e0d0863299246de8b7plougher	if(sBlk.s_major > 1)
21410337de3977eec74e6a3d28e0d0863299246de8b7plougher		printf("Duplicates are %sremoved\n", SQUASHFS_DUPLICATES(sBlk.flags) ? "" : "not ");
21420337de3977eec74e6a3d28e0d0863299246de8b7plougher	else
21430337de3977eec74e6a3d28e0d0863299246de8b7plougher		printf("Duplicates are removed\n");
2144b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk.bytes_used / 1024.0, sBlk.bytes_used / (1024.0 * 1024.0));
2145b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Block size %d\n", sBlk.block_size);
2146b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1)
2147b624936abba03d38b7e9245c647339d8f6f34274plougher		printf("Number of fragments %d\n", sBlk.fragments);
2148b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Number of inodes %d\n", sBlk.inodes);
2149b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Number of uids %d\n", sBlk.no_uids);
2150b624936abba03d38b7e9245c647339d8f6f34274plougher	printf("Number of gids %d\n", sBlk.no_guids);
2151b624936abba03d38b7e9245c647339d8f6f34274plougher
2152b624936abba03d38b7e9245c647339d8f6f34274plougher	TRACE("sBlk.inode_table_start 0x%llx\n", sBlk.inode_table_start);
2153b624936abba03d38b7e9245c647339d8f6f34274plougher	TRACE("sBlk.directory_table_start 0x%llx\n", sBlk.directory_table_start);
2154b624936abba03d38b7e9245c647339d8f6f34274plougher	TRACE("sBlk.uid_start 0x%llx\n", sBlk.uid_start);
2155b624936abba03d38b7e9245c647339d8f6f34274plougher	if(sBlk.s_major > 1)
2156b624936abba03d38b7e9245c647339d8f6f34274plougher		TRACE("sBlk.fragment_table_start 0x%llx\n\n", sBlk.fragment_table_start);
2157b624936abba03d38b7e9245c647339d8f6f34274plougher}
2158b624936abba03d38b7e9245c647339d8f6f34274plougher
2159b624936abba03d38b7e9245c647339d8f6f34274plougher
216002bc3bcabf2b219f63961f07293b83629948f026plougherint read_super(char *source)
2161443c15812032991c98b33b5424b17bcd55fe3575plougher{
216202bc3bcabf2b219f63961f07293b83629948f026plougher	read_bytes(SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk);
2163443c15812032991c98b33b5424b17bcd55fe3575plougher
2164443c15812032991c98b33b5424b17bcd55fe3575plougher	/* Check it is a SQUASHFS superblock */
2165443c15812032991c98b33b5424b17bcd55fe3575plougher	swap = 0;
216602bc3bcabf2b219f63961f07293b83629948f026plougher	if(sBlk.s_magic != SQUASHFS_MAGIC) {
216702bc3bcabf2b219f63961f07293b83629948f026plougher		if(sBlk.s_magic == SQUASHFS_MAGIC_SWAP) {
2168443c15812032991c98b33b5424b17bcd55fe3575plougher			squashfs_super_block sblk;
2169443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("Reading a different endian SQUASHFS filesystem on %s\n", source);
217002bc3bcabf2b219f63961f07293b83629948f026plougher			SQUASHFS_SWAP_SUPER_BLOCK(&sblk, &sBlk);
217102bc3bcabf2b219f63961f07293b83629948f026plougher			memcpy(&sBlk, &sblk, sizeof(squashfs_super_block));
2172443c15812032991c98b33b5424b17bcd55fe3575plougher			swap = 1;
2173443c15812032991c98b33b5424b17bcd55fe3575plougher		} else  {
2174443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("Can't find a SQUASHFS superblock on %s\n", source);
2175443c15812032991c98b33b5424b17bcd55fe3575plougher			goto failed_mount;
2176443c15812032991c98b33b5424b17bcd55fe3575plougher		}
2177443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2178443c15812032991c98b33b5424b17bcd55fe3575plougher
2179443c15812032991c98b33b5424b17bcd55fe3575plougher	/* Check the MAJOR & MINOR versions */
2180ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher	if(sBlk.s_major == 1 || sBlk.s_major == 2) {
218102bc3bcabf2b219f63961f07293b83629948f026plougher		sBlk.bytes_used = sBlk.bytes_used_2;
218202bc3bcabf2b219f63961f07293b83629948f026plougher		sBlk.uid_start = sBlk.uid_start_2;
218302bc3bcabf2b219f63961f07293b83629948f026plougher		sBlk.guid_start = sBlk.guid_start_2;
218402bc3bcabf2b219f63961f07293b83629948f026plougher		sBlk.inode_table_start = sBlk.inode_table_start_2;
218502bc3bcabf2b219f63961f07293b83629948f026plougher		sBlk.directory_table_start = sBlk.directory_table_start_2;
218602bc3bcabf2b219f63961f07293b83629948f026plougher
2187ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		if(sBlk.s_major == 1) {
2188ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			sBlk.block_size = sBlk.block_size_1;
2189ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			sBlk.fragment_table_start = sBlk.uid_start;
21906f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.squashfs_opendir = squashfs_opendir_2;
2191ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_1;
2192ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_block_list = read_block_list_1;
21936f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_1;
2194ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		} else {
2195ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			sBlk.fragment_table_start = sBlk.fragment_table_start_2;
2196ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.squashfs_opendir = squashfs_opendir_2;
2197ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment = read_fragment_2;
2198ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_fragment_table = read_fragment_table_2;
2199ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher			s_ops.read_block_list = read_block_list;
22006f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher			s_ops.read_inode = read_inode_2;
2201ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		}
22024c99cb7f458d8e1c598f1c80793daf3696c9b528plougher	} else if(sBlk.s_major == 3 && sBlk.s_minor <= 1) {
220302bc3bcabf2b219f63961f07293b83629948f026plougher		s_ops.squashfs_opendir = squashfs_opendir;
220402bc3bcabf2b219f63961f07293b83629948f026plougher		s_ops.read_fragment = read_fragment;
220502bc3bcabf2b219f63961f07293b83629948f026plougher		s_ops.read_fragment_table = read_fragment_table;
2206ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher		s_ops.read_block_list = read_block_list;
22076f59236ae37e220ca132b18d58f78ef1f5a1d4fbplougher		s_ops.read_inode = read_inode;
220802bc3bcabf2b219f63961f07293b83629948f026plougher	} else {
22094c99cb7f458d8e1c598f1c80793daf3696c9b528plougher		ERROR("Filesystem on %s is (%d:%d), ", source, sBlk.s_major, sBlk.s_minor);
22104c99cb7f458d8e1c598f1c80793daf3696c9b528plougher		ERROR("which is a later filesystem version than I support!\n");
2211443c15812032991c98b33b5424b17bcd55fe3575plougher		goto failed_mount;
2212443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2213443c15812032991c98b33b5424b17bcd55fe3575plougher
2214443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
2215443c15812032991c98b33b5424b17bcd55fe3575plougher
2216443c15812032991c98b33b5424b17bcd55fe3575plougherfailed_mount:
2217443c15812032991c98b33b5424b17bcd55fe3575plougher	return FALSE;
2218443c15812032991c98b33b5424b17bcd55fe3575plougher}
2219443c15812032991c98b33b5424b17bcd55fe3575plougher
2220443c15812032991c98b33b5424b17bcd55fe3575plougher
2221a706f1b6bb48f288ecaf74e218ce20504bda52c6plougherstruct pathname *process_extract_files(struct pathname *path, char *filename)
222271add234b27054974d5e29f95b3fab3072792a62plougher{
222371add234b27054974d5e29f95b3fab3072792a62plougher	FILE *fd;
222471add234b27054974d5e29f95b3fab3072792a62plougher	char name[16384];
222571add234b27054974d5e29f95b3fab3072792a62plougher
22264dba330d7b952f2f044d38e342e2ae3ea78910d6plougher	if((fd = fopen(filename, "r")) == NULL)
22274dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		EXIT_UNSQUASH("Could not open %s, because %s\n", filename, strerror(errno));
222871add234b27054974d5e29f95b3fab3072792a62plougher
222971add234b27054974d5e29f95b3fab3072792a62plougher	while(fscanf(fd, "%16384[^\n]\n", name) != EOF)
2230a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, name, name);
223171add234b27054974d5e29f95b3fab3072792a62plougher
223271add234b27054974d5e29f95b3fab3072792a62plougher	fclose(fd);
2233a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	return path;
223471add234b27054974d5e29f95b3fab3072792a62plougher}
223571add234b27054974d5e29f95b3fab3072792a62plougher
223671add234b27054974d5e29f95b3fab3072792a62plougher
22378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* reader thread.  This thread processes read requests queued by the
22388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * cache_get() routine. */
22398888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *reader(void *arg)
22408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
22418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
22428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct cache_entry *entry = queue_get(to_reader);
22438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int res = read_bytes(entry->block,
22448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size),
22458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			entry->data);
22468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
22478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(res && SQUASHFS_COMPRESSED_BLOCK(entry->size))
22488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			/* queue successfully read block to the deflate thread(s)
22498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 			 * for further processing */
22508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			queue_put(to_deflate, entry);
22518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		else
22528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			/* block has either been successfully read and is uncompressed,
22538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 			 * or an error has occurred, clear pending flag, set
22548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 			 * error appropriately, and wake up any threads waiting on
22558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 			 * this buffer */
22568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_ready(entry, !res);
22578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
22588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
22598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
22608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
22618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* writer thread.  This processes file write requests queued by the
22628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher * write_file() routine. */
22638888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *writer(void *arg)
22648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
22658888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int i;
22668888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
22678888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
22688888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct squashfs_file *file = queue_get(to_writer);
22698888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int file_fd;
22708888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int hole = 0;
227127636cb2cec37a68313f9eb825c0548245eecad0plougher		int failed = FALSE;
22728888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
22738888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(file == NULL) {
22748888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			queue_put(from_writer, NULL);
22758888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			continue;
22768888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
22778888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
22788888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		TRACE("writer: regular file, blocks %d\n", file->blocks);
22798888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
22808888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		file_fd = file->fd;
22818888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2282eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		for(i = 0; i < file->blocks; i++, cur_blocks ++) {
22838888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			struct file_entry *block = queue_get(to_writer);
22848888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
22858888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(block->buffer == 0) { /* sparse file */
22868888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole += block->size;
22878888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				free(block);
22888888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				continue;
22898888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
22908888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
22918888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_wait(block->buffer);
229227636cb2cec37a68313f9eb825c0548245eecad0plougher
229327636cb2cec37a68313f9eb825c0548245eecad0plougher			if(block->buffer->error)
229427636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
229527636cb2cec37a68313f9eb825c0548245eecad0plougher
229627636cb2cec37a68313f9eb825c0548245eecad0plougher			if(failed == FALSE && write_block(file_fd, block->buffer->data + block->offset, block->size, hole) == FALSE) {
22978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				ERROR("writer: failed to write data block %d\n", i);
229827636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
22998888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
23008888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			hole = 0;
23018888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			cache_block_put(block->buffer);
23028888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			free(block);
23038888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
23048888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
230527636cb2cec37a68313f9eb825c0548245eecad0plougher		if(hole && failed == FALSE) {
23068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			/* corner case for hole extending to end of file */
23078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(lseek(file_fd, hole, SEEK_CUR) == -1) {
23088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				/* for broken lseeks which cannot seek beyond end of
23098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 			 	* file, write_block will do the right thing */
23108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				hole --;
23118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				if(write_block(file_fd, "\0", 1, hole) == FALSE) {
23128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher					ERROR("writer: failed to write sparse data block\n");
231327636cb2cec37a68313f9eb825c0548245eecad0plougher					failed = TRUE;
23148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				}
23158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			} else if(ftruncate(file_fd, file->file_size) == -1) {
23168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				ERROR("writer: failed to write sparse data block\n");
231727636cb2cec37a68313f9eb825c0548245eecad0plougher				failed = TRUE;
23188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			}
23198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
23208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		close(file_fd);
232227636cb2cec37a68313f9eb825c0548245eecad0plougher		if(failed == FALSE)
232327636cb2cec37a68313f9eb825c0548245eecad0plougher			set_attributes(file->pathname, file->mode, file->uid, file->gid, file->time, force);
232427636cb2cec37a68313f9eb825c0548245eecad0plougher		else {
232527636cb2cec37a68313f9eb825c0548245eecad0plougher			ERROR("Failed to write %s, skipping\n", file->pathname);
232627636cb2cec37a68313f9eb825c0548245eecad0plougher			unlink(file->pathname);
232727636cb2cec37a68313f9eb825c0548245eecad0plougher		}
232879df93becb68081effabebba3006c794be308598plougher		free(file->pathname);
23298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		free(file);
233027636cb2cec37a68313f9eb825c0548245eecad0plougher
23318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
23328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
23338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher/* decompress thread.  This decompresses buffers queued by the read thread */
23368888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid *deflator(void *arg)
23378888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
23388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	char tmp[block_size];
23398888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	while(1) {
23418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		struct cache_entry *entry = queue_get(to_deflate);
23428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int res;
23438888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		unsigned long bytes = block_size;
23448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		res = uncompress((unsigned char *) tmp, &bytes, (const unsigned char *) entry->data, SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size));
23468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(res != Z_OK) {
23488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			if(res == Z_MEM_ERROR)
23498888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				ERROR("zlib::uncompress failed, not enough memory\n");
23508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			else if(res == Z_BUF_ERROR)
23518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				ERROR("zlib::uncompress failed, not enough room in output buffer\n");
23528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			else
23538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher				ERROR("zlib::uncompress failed, unknown error %d\n", res);
23548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		} else
23558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			memcpy(entry->data, tmp, bytes);
23568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		/* block has been either successfully decompressed, or an error
23588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * occurred, clear pending flag, set error appropriately and
23598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher 		 * wake up any threads waiting on this block */
23608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		cache_block_ready(entry, res != Z_OK);
23618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
23628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
23638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
23648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2365eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid *progress_thread(void *arg)
2366eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
2367eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct timeval timeval;
2368eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct timespec timespec;
23691b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct itimerval itimerval;
23701b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	struct winsize winsize;
23711b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
23721b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	if(ioctl(1, TIOCGWINSZ, &winsize) == -1) {
23731b42101056befe25b5f19d5b099e806a2ecee9cdplougher		ERROR("TIOCGWINZ ioctl failed, defaulting to 80 columns\n");
23741b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = 80;
23751b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	} else
23761b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher		columns = winsize.ws_col;
23771b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGWINCH, sigwinch_handler);
23781b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	signal(SIGALRM, sigalrm_handler);
23791b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher
23801b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_sec = 0;
23811b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_value.tv_usec = 250000;
23821b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_sec = 0;
23831b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	itimerval.it_interval.tv_usec = 250000;
23841b5f6c5145f284683a2628b73ab5f8a0e37dd7b4plougher	setitimer(ITIMER_REAL, &itimerval, NULL);
2385eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2386eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_cond_init(&progress_wait, NULL);
2387eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
23881b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
2389eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(1) {
2390eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		gettimeofday(&timeval, NULL);
2391eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		timespec.tv_sec = timeval.tv_sec;
2392eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		if(timeval.tv_usec + 250000 > 999999)
2393eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher			timespec.tv_sec++;
2394eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		timespec.tv_nsec = ((timeval.tv_usec + 250000) % 1000000) * 1000;
23951b42101056befe25b5f19d5b099e806a2ecee9cdplougher		pthread_cond_timedwait(&progress_wait, &screen_mutex, &timespec);
23961b42101056befe25b5f19d5b099e806a2ecee9cdplougher		if(progress_enabled)
23971b42101056befe25b5f19d5b099e806a2ecee9cdplougher			progress_bar(sym_count + dev_count +
23981b42101056befe25b5f19d5b099e806a2ecee9cdplougher				fifo_count + cur_blocks, total_inodes - total_files +
23991b42101056befe25b5f19d5b099e806a2ecee9cdplougher				total_blocks, columns);
2400eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
2401eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
2402eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2403eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
24048888b61f8ff4680247d10f7e5beb2ff35e8c867dploughervoid initialise_threads(int fragment_buffer_size, int data_buffer_size)
24058888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher{
24068888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int i;
24078888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigset_t sigmask, old_mask;
24088888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	int all_buffers_size = fragment_buffer_size + data_buffer_size;
24098888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
24108888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigemptyset(&sigmask);
24118888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigaddset(&sigmask, SIGINT);
24128888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	sigaddset(&sigmask, SIGQUIT);
24138888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(sigprocmask(SIG_BLOCK, &sigmask, &old_mask) == -1)
24148888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads\n");
24158888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
24168888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(processors == -1) {
24178888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifndef linux
24188888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		int mib[2];
24198888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		size_t len = sizeof(processors);
24208888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
24218888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[0] = CTL_HW;
24228888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#ifdef HW_AVAILCPU
24238888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_AVAILCPU;
24248888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
24258888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		mib[1] = HW_NCPU;
24268888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
24278888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
24288888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) {
24298888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			ERROR("Failed to get number of available processors.  Defaulting to 1\n");
24308888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors = 1;
24318888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		}
24328888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#else
24338888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		processors = get_nprocs();
24348888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher#endif
24358888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
24368888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2437eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if((thread = malloc((3 + processors) * sizeof(pthread_t))) == NULL)
24388888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
2439eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	deflator_thread = &thread[3];
24408888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
24418888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	to_reader = queue_init(all_buffers_size);
24428888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	to_deflate = queue_init(all_buffers_size);
2443eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	to_writer = queue_init(1000);
24448888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	from_writer = queue_init(1);
24458888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	fragment_cache = cache_init(block_size, fragment_buffer_size);
24468888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	data_cache = cache_init(block_size, data_buffer_size);
24478888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[0], NULL, reader, NULL);
24488888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_create(&thread[1], NULL, writer, NULL);
2449eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_create(&thread[2], NULL, progress_thread, NULL);
24508888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	pthread_mutex_init(&fragment_mutex, NULL);
24518888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
24528888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	for(i = 0; i < processors; i++) {
24538888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		if(pthread_create(&deflator_thread[i], NULL, deflator, NULL) != 0 )
24548888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			EXIT_UNSQUASH("Failed to create thread\n");
24558888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	}
24568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
24578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	printf("Parallel unsquashfs: Using %d processor%s\n", processors,
24588888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher			processors == 1 ? "" : "s");
24598888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
24608888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	if(sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1)
24618888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher		EXIT_UNSQUASH("Failed to set signal mask in intialise_threads\n");
24628888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher}
24638888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
24648888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
24651b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid enable_progress_bar()
24661b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
24671b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
24681b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_enabled = TRUE;
24691b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
24701b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
24711b42101056befe25b5f19d5b099e806a2ecee9cdplougher
24721b42101056befe25b5f19d5b099e806a2ecee9cdplougher
24731b42101056befe25b5f19d5b099e806a2ecee9cdploughervoid disable_progress_bar()
24741b42101056befe25b5f19d5b099e806a2ecee9cdplougher{
24751b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
24761b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_enabled = FALSE;
24771b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
24781b42101056befe25b5f19d5b099e806a2ecee9cdplougher}
24791b42101056befe25b5f19d5b099e806a2ecee9cdplougher
24801b42101056befe25b5f19d5b099e806a2ecee9cdplougher
2481eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid update_progress_bar()
2482eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
24831b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_lock(&screen_mutex);
2484eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pthread_cond_signal(&progress_wait);
24851b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_unlock(&screen_mutex);
2486eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
2487eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2488eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2489eb35c81a4c4500aab9eeea2ba2271c88fe42732aploughervoid progress_bar(long long current, long long max, int columns)
2490eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher{
2491eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	char rotate_list[] = { '|', '/', '-', '\\' };
2492eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	int max_digits = ceil(log10(max));
2493eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	int used = max_digits * 2 + 11;
2494eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	int hashes = (current * (columns - used)) / max;
2495eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	int spaces = columns - used - hashes;
2496eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2497eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(current > max) {
2498eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		printf("%lld %lld\n", current, max);
2499eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		return;
2500eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	}
2501eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2502eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	if(!progress || columns - used < 0)
2503eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		return;
2504eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2505eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("\r[");
2506eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2507eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while (hashes --)
2508eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar('=');
2509eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2510eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	putchar(rotate_list[rotate]);
2511eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2512eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	while(spaces --)
2513eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		putchar(' ');
2514eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2515eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("] %*lld/%*lld", max_digits, current, max_digits, max);
2516eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf(" %3lld%%", current * 100 / max);
2517eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	fflush(stdout);
2518eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher}
2519eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2520eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2521443c15812032991c98b33b5424b17bcd55fe3575plougher#define VERSION() \
25221b42101056befe25b5f19d5b099e806a2ecee9cdplougher	printf("unsquashfs version 1.6-CVS (2008/05/01)\n");\
252379df93becb68081effabebba3006c794be308598plougher	printf("copyright (C) 2008 Phillip Lougher <phillip@lougher.demon.co.uk>\n\n"); \
2524443c15812032991c98b33b5424b17bcd55fe3575plougher    	printf("This program is free software; you can redistribute it and/or\n");\
2525443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("modify it under the terms of the GNU General Public License\n");\
2526443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("as published by the Free Software Foundation; either version 2,\n");\
2527443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("or (at your option) any later version.\n\n");\
2528443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("This program is distributed in the hope that it will be useful,\n");\
2529443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\
2530443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");\
2531443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("GNU General Public License for more details.\n");
2532443c15812032991c98b33b5424b17bcd55fe3575plougherint main(int argc, char *argv[])
2533443c15812032991c98b33b5424b17bcd55fe3575plougher{
2534443c15812032991c98b33b5424b17bcd55fe3575plougher	char *dest = "squashfs-root";
2535b624936abba03d38b7e9245c647339d8f6f34274plougher	int i, stat_sys = FALSE, version = FALSE;
2536545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	int n;
2537a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathnames *paths = NULL;
2538a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	struct pathname *path = NULL;
2539ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int fragment_buffer_size = FRAGMENT_BUFFER_DEFAULT;
2540ae271cc93e3684d5314bcdc45b631e497ae43166plougher	int data_buffer_size = DATA_BUFFER_DEFAULT;
25410cf5c297bec42c7c220d2825f12f9499f2293279plougher	char *b;
2542eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	struct winsize winsize;
2543443c15812032991c98b33b5424b17bcd55fe3575plougher
25441b42101056befe25b5f19d5b099e806a2ecee9cdplougher	pthread_mutex_init(&screen_mutex, NULL);
2545545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	root_process = geteuid() == 0;
2546545404219cdd79c1e06ac7d0698d02a15240c4c3plougher	if(root_process)
25479dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher		umask(0);
25489dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher
2549443c15812032991c98b33b5424b17bcd55fe3575plougher	for(i = 1; i < argc; i++) {
2550443c15812032991c98b33b5424b17bcd55fe3575plougher		if(*argv[i] != '-')
2551443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
2552a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher		if(strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) {
2553443c15812032991c98b33b5424b17bcd55fe3575plougher			VERSION();
2554443c15812032991c98b33b5424b17bcd55fe3575plougher			version = TRUE;
2555a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher		} else if(strcmp(argv[i], "-info") == 0 || strcmp(argv[i], "-i") == 0)
2556443c15812032991c98b33b5424b17bcd55fe3575plougher			info = TRUE;
2557a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher		else if(strcmp(argv[i], "-ls") == 0 || strcmp(argv[i], "-l") == 0)
2558443c15812032991c98b33b5424b17bcd55fe3575plougher			lsonly = TRUE;
2559a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher		else if(strcmp(argv[i], "-dest") == 0 || strcmp(argv[i], "-d") == 0) {
256071add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
256171add234b27054974d5e29f95b3fab3072792a62plougher				fprintf(stderr, "%s: -dest missing filename\n", argv[0]);
256271add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
256371add234b27054974d5e29f95b3fab3072792a62plougher			}
2564443c15812032991c98b33b5424b17bcd55fe3575plougher			dest = argv[i];
25650cf5c297bec42c7c220d2825f12f9499f2293279plougher		} else if(strcmp(argv[i], "-processors") == 0 || strcmp(argv[i], "-p") == 0) {
25660cf5c297bec42c7c220d2825f12f9499f2293279plougher			if((++i == argc) || (processors = strtol(argv[i], &b, 10), *b != '\0')) {
25670cf5c297bec42c7c220d2825f12f9499f2293279plougher				ERROR("%s: -processors missing or invalid processor number\n", argv[0]);
25680cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
25690cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
25700cf5c297bec42c7c220d2825f12f9499f2293279plougher			if(processors < 1) {
25710cf5c297bec42c7c220d2825f12f9499f2293279plougher				ERROR("%s: -processors should be 1 or larger\n", argv[0]);
25720cf5c297bec42c7c220d2825f12f9499f2293279plougher				exit(1);
25730cf5c297bec42c7c220d2825f12f9499f2293279plougher			}
2574ae271cc93e3684d5314bcdc45b631e497ae43166plougher		} else if(strcmp(argv[i], "-data-queue") == 0 || strcmp(argv[i], "-da") == 0) {
2575ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if((++i == argc) || (data_buffer_size = strtol(argv[i], &b, 10), *b != '\0')) {
2576ae271cc93e3684d5314bcdc45b631e497ae43166plougher				ERROR("%s: -data-queue missing or invalid queue size\n", argv[0]);
2577ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2578ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2579ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(data_buffer_size < 1) {
2580ae271cc93e3684d5314bcdc45b631e497ae43166plougher				ERROR("%s: -data-queue should be 1 Mbyte or larger\n", argv[0]);
2581ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2582ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2583ae271cc93e3684d5314bcdc45b631e497ae43166plougher		} else if(strcmp(argv[i], "-frag-queue") == 0 || strcmp(argv[i], "-fr") == 0) {
2584ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if((++i == argc) || (fragment_buffer_size = strtol(argv[i], &b, 10), *b != '\0')) {
2585ae271cc93e3684d5314bcdc45b631e497ae43166plougher				ERROR("%s: -frag-queue missing or invalid queue size\n", argv[0]);
2586ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2587ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2588ae271cc93e3684d5314bcdc45b631e497ae43166plougher			if(fragment_buffer_size < 1) {
2589ae271cc93e3684d5314bcdc45b631e497ae43166plougher				ERROR("%s: -frag-queue should be 1 Mbyte or larger\n", argv[0]);
2590ae271cc93e3684d5314bcdc45b631e497ae43166plougher				exit(1);
2591ae271cc93e3684d5314bcdc45b631e497ae43166plougher			}
2592a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher		} else if(strcmp(argv[i], "-force") == 0 || strcmp(argv[i], "-f") == 0)
2593a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			force = TRUE;
2594b624936abba03d38b7e9245c647339d8f6f34274plougher		else if(strcmp(argv[i], "-stat") == 0 || strcmp(argv[i], "-s") == 0)
2595b624936abba03d38b7e9245c647339d8f6f34274plougher			stat_sys = TRUE;
25969baf35a00f38816d2054deb70184943d0686d03eplougher		else if(strcmp(argv[i], "-lls") == 0 || strcmp(argv[i], "-ll") == 0) {
25979baf35a00f38816d2054deb70184943d0686d03eplougher			lsonly = TRUE;
25989baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
25993edfa57b6a463f7d441d995559143f4861d62e98plougher		} else if(strcmp(argv[i], "-linfo") == 0 || strcmp(argv[i], "-li") == 0) {
26009baf35a00f38816d2054deb70184943d0686d03eplougher			info = TRUE;
26019baf35a00f38816d2054deb70184943d0686d03eplougher			short_ls = FALSE;
260271add234b27054974d5e29f95b3fab3072792a62plougher		} else if(strcmp(argv[i], "-ef") == 0 || strcmp(argv[i], "-e") == 0) {
260371add234b27054974d5e29f95b3fab3072792a62plougher			if(++i == argc) {
260471add234b27054974d5e29f95b3fab3072792a62plougher				fprintf(stderr, "%s: -ef missing filename\n", argv[0]);
260571add234b27054974d5e29f95b3fab3072792a62plougher				exit(1);
260671add234b27054974d5e29f95b3fab3072792a62plougher			}
2607a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher			path = process_extract_files(path, argv[i]);
26084dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		} else if(strcmp(argv[i], "-regex") == 0 || strcmp(argv[i], "-r") == 0)
26094dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			use_regex = TRUE;
26104dba330d7b952f2f044d38e342e2ae3ea78910d6plougher		else
2611b624936abba03d38b7e9245c647339d8f6f34274plougher			goto options;
2612443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2613443c15812032991c98b33b5424b17bcd55fe3575plougher
2614443c15812032991c98b33b5424b17bcd55fe3575plougher	if(i == argc) {
2615443c15812032991c98b33b5424b17bcd55fe3575plougher		if(!version) {
2616443c15812032991c98b33b5424b17bcd55fe3575plougheroptions:
261771add234b27054974d5e29f95b3fab3072792a62plougher			ERROR("SYNTAX: %s [options] filesystem [directories or files to extract]\n", argv[0]);
2618a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			ERROR("\t-v[ersion]\t\tprint version, licence and copyright information\n");
26190cf5c297bec42c7c220d2825f12f9499f2293279plougher			ERROR("\t-d[est] <pathname>\tunsquash to <pathname>, default \"squashfs-root\"\n");
26200cf5c297bec42c7c220d2825f12f9499f2293279plougher			ERROR("\t-p[rocessors] <number>\tuse <number> processors.  By default will use\n\t\t\t\tnumber of processors available\n");
2621a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			ERROR("\t-i[nfo]\t\t\tprint files as they are unsquashed\n");
26229baf35a00f38816d2054deb70184943d0686d03eplougher			ERROR("\t-li[nfo]\t\tprint files as they are unsquashed with file\n\t\t\t\tattributes (like ls -l output)\n");
26239baf35a00f38816d2054deb70184943d0686d03eplougher			ERROR("\t-l[s]\t\t\tlist filesystem, but don't unsquash\n");
26249baf35a00f38816d2054deb70184943d0686d03eplougher			ERROR("\t-ll[s]\t\t\tlist filesystem with file attributes (like\n\t\t\t\tls -l output), but don't unsquash\n");
2625a52d4c1b3b62c5bd1c63c392a8365afcebbf5b78plougher			ERROR("\t-f[orce]\t\tif file already exists then overwrite\n");
26260337de3977eec74e6a3d28e0d0863299246de8b7plougher			ERROR("\t-s[tat]\t\t\tdisplay filesystem superblock information\n");
262771add234b27054974d5e29f95b3fab3072792a62plougher			ERROR("\t-e[f] <extract file>\tlist of directories or files to extract.\n\t\t\t\tOne per line\n");
2628ae271cc93e3684d5314bcdc45b631e497ae43166plougher			ERROR("\t-da[ta-queue] <size>\tSet data queue to <size> Mbytes.  Default %d\n\t\t\t\tMbytes\n", DATA_BUFFER_DEFAULT);
2629ae271cc93e3684d5314bcdc45b631e497ae43166plougher			ERROR("\t-fr[ag-queue] <size>\tSet fagment queue to <size> Mbytes.  Default %d\n\t\t\t\tMbytes\n", FRAGMENT_BUFFER_DEFAULT);
26304dba330d7b952f2f044d38e342e2ae3ea78910d6plougher			ERROR("\t-r[egex]\t\ttreat extract names as POSIX regular expressions\n\t\t\t\trather than use the default shell wildcard\n\t\t\t\texpansion (globbing)\n");
2631443c15812032991c98b33b5424b17bcd55fe3575plougher		}
2632443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2633443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2634443c15812032991c98b33b5424b17bcd55fe3575plougher
263571add234b27054974d5e29f95b3fab3072792a62plougher	for(n = i + 1; n < argc; n++)
2636a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		path = add_path(path, argv[n], argv[n]);
2637b54566f5c433764830c29c83151691d0034de094plougher
2638443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fd = open(argv[i], O_RDONLY)) == -1) {
2639443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("Could not open %s, because %s\n", argv[i], strerror(errno));
2640443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2641443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2642443c15812032991c98b33b5424b17bcd55fe3575plougher
264302bc3bcabf2b219f63961f07293b83629948f026plougher	if(read_super(argv[i]) == FALSE)
2644443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
2645443c15812032991c98b33b5424b17bcd55fe3575plougher
2646b624936abba03d38b7e9245c647339d8f6f34274plougher	if(stat_sys) {
2647b624936abba03d38b7e9245c647339d8f6f34274plougher		squashfs_stat(argv[i]);
2648b624936abba03d38b7e9245c647339d8f6f34274plougher		exit(0);
2649b624936abba03d38b7e9245c647339d8f6f34274plougher	}
2650b624936abba03d38b7e9245c647339d8f6f34274plougher
2651443c15812032991c98b33b5424b17bcd55fe3575plougher	block_size = sBlk.block_size;
2652ae271cc93e3684d5314bcdc45b631e497ae43166plougher	block_log = sBlk.block_log;
2653ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
2654ae271cc93e3684d5314bcdc45b631e497ae43166plougher	fragment_buffer_size <<= 20 - block_log;
2655ae271cc93e3684d5314bcdc45b631e497ae43166plougher	data_buffer_size <<= 20 - block_log;
26568888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	initialise_threads(fragment_buffer_size, data_buffer_size);
26578888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
2658443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fragment_data = malloc(block_size)) == NULL)
2659443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate fragment_data\n");
2660443c15812032991c98b33b5424b17bcd55fe3575plougher
2661443c15812032991c98b33b5424b17bcd55fe3575plougher	if((file_data = malloc(block_size)) == NULL)
2662443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate file_data");
2663443c15812032991c98b33b5424b17bcd55fe3575plougher
2664443c15812032991c98b33b5424b17bcd55fe3575plougher	if((data = malloc(block_size)) == NULL)
2665eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher		EXIT_UNSQUASH("failed to allocate data\n");
2666443c15812032991c98b33b5424b17bcd55fe3575plougher
2667443c15812032991c98b33b5424b17bcd55fe3575plougher	if((created_inode = malloc(sBlk.inodes * sizeof(char *))) == NULL)
2668443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate created_inode\n");
2669443c15812032991c98b33b5424b17bcd55fe3575plougher
2670443c15812032991c98b33b5424b17bcd55fe3575plougher	memset(created_inode, 0, sBlk.inodes * sizeof(char *));
2671443c15812032991c98b33b5424b17bcd55fe3575plougher
267202bc3bcabf2b219f63961f07293b83629948f026plougher	read_uids_guids();
2673ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
267402bc3bcabf2b219f63961f07293b83629948f026plougher	s_ops.read_fragment_table();
2675ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
267602bc3bcabf2b219f63961f07293b83629948f026plougher	uncompress_inode_table(sBlk.inode_table_start, sBlk.directory_table_start);
2677ba3d412c7c811a9b335a52ec497ce511e35b2bc8plougher
267802bc3bcabf2b219f63961f07293b83629948f026plougher	uncompress_directory_table(sBlk.directory_table_start, sBlk.fragment_table_start);
2679443c15812032991c98b33b5424b17bcd55fe3575plougher
2680a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	if(path) {
2681a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = init_subdir();
2682a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher		paths = add_subdir(paths, path);
2683a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher	}
2684a706f1b6bb48f288ecaf74e218ce20504bda52c6plougher
2685eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	pre_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode), SQUASHFS_INODE_OFFSET(sBlk.root_inode), paths);
2686eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2687eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	memset(created_inode, 0, sBlk.inodes * sizeof(char *));
2688eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2689eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher	printf("%d files (%d blocks) to write\n\n", total_inodes, total_inodes - total_files + total_blocks);
2690eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
26911b42101056befe25b5f19d5b099e806a2ecee9cdplougher	if(progress)
26921b42101056befe25b5f19d5b099e806a2ecee9cdplougher		enable_progress_bar();
26931b42101056befe25b5f19d5b099e806a2ecee9cdplougher
269471add234b27054974d5e29f95b3fab3072792a62plougher	dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode), SQUASHFS_INODE_OFFSET(sBlk.root_inode), paths);
2695443c15812032991c98b33b5424b17bcd55fe3575plougher
26968888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_put(to_writer, NULL);
26978888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher	queue_get(from_writer);
26988888b61f8ff4680247d10f7e5beb2ff35e8c867dplougher
26991b42101056befe25b5f19d5b099e806a2ecee9cdplougher	if(progress)
27001b42101056befe25b5f19d5b099e806a2ecee9cdplougher		disable_progress_bar();
27011b42101056befe25b5f19d5b099e806a2ecee9cdplougher
27021b42101056befe25b5f19d5b099e806a2ecee9cdplougher	progress_bar(sym_count + dev_count + fifo_count + cur_blocks,
27031b42101056befe25b5f19d5b099e806a2ecee9cdplougher			total_inodes - total_files + total_blocks, columns);
2704eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
2705443c15812032991c98b33b5424b17bcd55fe3575plougher	if(!lsonly) {
2706443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("\n");
2707443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d files\n", file_count);
2708443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d directories\n", dir_count);
2709443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d symlinks\n", sym_count);
2710443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d devices\n", dev_count);
2711443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d fifos\n", fifo_count);
2712443c15812032991c98b33b5424b17bcd55fe3575plougher	}
2713eb35c81a4c4500aab9eeea2ba2271c88fe42732aplougher
27149dd8c7a7c2983faeb60c5e5791c3bef2cbbba088plougher	return 0;
2715443c15812032991c98b33b5424b17bcd55fe3575plougher}
2716