unsquashfs.c revision b54566f5c433764830c29c83151691d0034de094
1443c15812032991c98b33b5424b17bcd55fe3575plougher/*
2443c15812032991c98b33b5424b17bcd55fe3575plougher * Unsquash a squashfs filesystem.  This is a highly compressed read only filesystem.
3443c15812032991c98b33b5424b17bcd55fe3575plougher *
4769592935b09063a5493ebeb530c599753ece5d2plougher * Copyright (c) 2002, 2003, 2004, 2005, 2006
59b5bf8c73c0eaf4f1ba0461615f4ed0d405a30ccplougher *  Phillip Lougher <phillip@lougher.org.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
24443c15812032991c98b33b5424b17bcd55fe3575plougher#define TRUE 1
25443c15812032991c98b33b5424b17bcd55fe3575plougher#define FALSE 0
26443c15812032991c98b33b5424b17bcd55fe3575plougher#include <stdio.h>
27443c15812032991c98b33b5424b17bcd55fe3575plougher#include <sys/types.h>
28443c15812032991c98b33b5424b17bcd55fe3575plougher#include <sys/stat.h>
29443c15812032991c98b33b5424b17bcd55fe3575plougher#include <fcntl.h>
30443c15812032991c98b33b5424b17bcd55fe3575plougher#include <errno.h>
31443c15812032991c98b33b5424b17bcd55fe3575plougher#include <string.h>
32443c15812032991c98b33b5424b17bcd55fe3575plougher#include <zlib.h>
33443c15812032991c98b33b5424b17bcd55fe3575plougher#include <sys/mman.h>
34443c15812032991c98b33b5424b17bcd55fe3575plougher#include <utime.h>
35443c15812032991c98b33b5424b17bcd55fe3575plougher
36443c15812032991c98b33b5424b17bcd55fe3575plougher#ifndef linux
37443c15812032991c98b33b5424b17bcd55fe3575plougher#define __BYTE_ORDER BYTE_ORDER
38443c15812032991c98b33b5424b17bcd55fe3575plougher#define __BIG_ENDIAN BIG_ENDIAN
39443c15812032991c98b33b5424b17bcd55fe3575plougher#define __LITTLE_ENDIAN LITTLE_ENDIAN
40443c15812032991c98b33b5424b17bcd55fe3575plougher#else
41443c15812032991c98b33b5424b17bcd55fe3575plougher#include <endian.h>
42443c15812032991c98b33b5424b17bcd55fe3575plougher#endif
43443c15812032991c98b33b5424b17bcd55fe3575plougher
44443c15812032991c98b33b5424b17bcd55fe3575plougher#include <squashfs_fs.h>
45443c15812032991c98b33b5424b17bcd55fe3575plougher#include "read_fs.h"
46443c15812032991c98b33b5424b17bcd55fe3575plougher#include "global.h"
47443c15812032991c98b33b5424b17bcd55fe3575plougher
48443c15812032991c98b33b5424b17bcd55fe3575plougher#include <stdlib.h>
49443c15812032991c98b33b5424b17bcd55fe3575plougher
50443c15812032991c98b33b5424b17bcd55fe3575plougher#ifdef SQUASHFS_TRACE
51443c15812032991c98b33b5424b17bcd55fe3575plougher#define TRACE(s, args...)		do { \
52443c15812032991c98b33b5424b17bcd55fe3575plougher						printf("mksquashfs: "s, ## args); \
53443c15812032991c98b33b5424b17bcd55fe3575plougher					} while(0)
54443c15812032991c98b33b5424b17bcd55fe3575plougher#else
55443c15812032991c98b33b5424b17bcd55fe3575plougher#define TRACE(s, args...)
56443c15812032991c98b33b5424b17bcd55fe3575plougher#endif
57443c15812032991c98b33b5424b17bcd55fe3575plougher
58443c15812032991c98b33b5424b17bcd55fe3575plougher#define ERROR(s, args...)		do { \
59443c15812032991c98b33b5424b17bcd55fe3575plougher						fprintf(stderr, s, ## args); \
60443c15812032991c98b33b5424b17bcd55fe3575plougher					} while(0)
61443c15812032991c98b33b5424b17bcd55fe3575plougher
62443c15812032991c98b33b5424b17bcd55fe3575plougher#define EXIT_UNSQUASH(s, args...)	do { \
63443c15812032991c98b33b5424b17bcd55fe3575plougher						fprintf(stderr, "FATAL ERROR aborting: "s, ## args); \
64443c15812032991c98b33b5424b17bcd55fe3575plougher					} while(0)
65443c15812032991c98b33b5424b17bcd55fe3575plougher
66443c15812032991c98b33b5424b17bcd55fe3575plougherstruct hash_table_entry {
67443c15812032991c98b33b5424b17bcd55fe3575plougher	int	start;
68443c15812032991c98b33b5424b17bcd55fe3575plougher	int	bytes;
69443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *next;
70443c15812032991c98b33b5424b17bcd55fe3575plougher};
71443c15812032991c98b33b5424b17bcd55fe3575plougher
72443c15812032991c98b33b5424b17bcd55fe3575plougherint bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0, dev_count = 0, fifo_count = 0;
73443c15812032991c98b33b5424b17bcd55fe3575plougherchar *inode_table = NULL, *directory_table = NULL;
74443c15812032991c98b33b5424b17bcd55fe3575plougherstruct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536];
75443c15812032991c98b33b5424b17bcd55fe3575plougherint fd;
76443c15812032991c98b33b5424b17bcd55fe3575ploughersquashfs_fragment_entry *fragment_table;
77443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int *uid_table, *guid_table;
78443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int cached_frag = SQUASHFS_INVALID_FRAG;
79443c15812032991c98b33b5424b17bcd55fe3575plougherchar *fragment_data;
80443c15812032991c98b33b5424b17bcd55fe3575plougherchar *file_data;
81443c15812032991c98b33b5424b17bcd55fe3575plougherchar *data;
82443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int block_size;
83443c15812032991c98b33b5424b17bcd55fe3575plougherint lsonly = FALSE, info = FALSE;
84443c15812032991c98b33b5424b17bcd55fe3575plougherchar **created_inode;
85443c15812032991c98b33b5424b17bcd55fe3575plougher
86443c15812032991c98b33b5424b17bcd55fe3575plougher#define CALCULATE_HASH(start)	(start & 0xffff)
87443c15812032991c98b33b5424b17bcd55fe3575plougher
88443c15812032991c98b33b5424b17bcd55fe3575plougherint add_entry(struct hash_table_entry *hash_table[], int start, int bytes)
89443c15812032991c98b33b5424b17bcd55fe3575plougher{
90443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
91443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
92443c15812032991c98b33b5424b17bcd55fe3575plougher
93443c15812032991c98b33b5424b17bcd55fe3575plougher	if((hash_table_entry = malloc(sizeof(struct hash_table_entry))) == NULL) {
94443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("add_hash: out of memory in malloc\n");
95443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
96443c15812032991c98b33b5424b17bcd55fe3575plougher	}
97443c15812032991c98b33b5424b17bcd55fe3575plougher
98443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->start = start;
99443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->bytes = bytes;
100443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table_entry->next = hash_table[hash];
101443c15812032991c98b33b5424b17bcd55fe3575plougher	hash_table[hash] = hash_table_entry;
102443c15812032991c98b33b5424b17bcd55fe3575plougher
103443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
104443c15812032991c98b33b5424b17bcd55fe3575plougher}
105443c15812032991c98b33b5424b17bcd55fe3575plougher
106443c15812032991c98b33b5424b17bcd55fe3575plougher
107443c15812032991c98b33b5424b17bcd55fe3575plougherint lookup_entry(struct hash_table_entry *hash_table[], int start)
108443c15812032991c98b33b5424b17bcd55fe3575plougher{
109443c15812032991c98b33b5424b17bcd55fe3575plougher	int hash = CALCULATE_HASH(start);
110443c15812032991c98b33b5424b17bcd55fe3575plougher	struct hash_table_entry *hash_table_entry;
111443c15812032991c98b33b5424b17bcd55fe3575plougher
112443c15812032991c98b33b5424b17bcd55fe3575plougher	for(hash_table_entry = hash_table[hash]; hash_table_entry; hash_table_entry = hash_table_entry->next)
113443c15812032991c98b33b5424b17bcd55fe3575plougher		if(hash_table_entry->start == start)
114443c15812032991c98b33b5424b17bcd55fe3575plougher			return hash_table_entry->bytes;
115443c15812032991c98b33b5424b17bcd55fe3575plougher
116443c15812032991c98b33b5424b17bcd55fe3575plougher	return -1;
117443c15812032991c98b33b5424b17bcd55fe3575plougher}
118443c15812032991c98b33b5424b17bcd55fe3575plougher
119443c15812032991c98b33b5424b17bcd55fe3575plougher
120443c15812032991c98b33b5424b17bcd55fe3575plougherint read_bytes(long long byte, int bytes, char *buff)
121443c15812032991c98b33b5424b17bcd55fe3575plougher{
122443c15812032991c98b33b5424b17bcd55fe3575plougher	off_t off = byte;
123443c15812032991c98b33b5424b17bcd55fe3575plougher
124fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes);
125fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
126443c15812032991c98b33b5424b17bcd55fe3575plougher	if(lseek(fd, off, SEEK_SET) == -1) {
127443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("Lseek failed because %s\b", strerror(errno));
128443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
129443c15812032991c98b33b5424b17bcd55fe3575plougher	}
130443c15812032991c98b33b5424b17bcd55fe3575plougher
131443c15812032991c98b33b5424b17bcd55fe3575plougher	if(read(fd, buff, bytes) == -1) {
132443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("Read on destination failed because %s\n", strerror(errno));
133443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
134443c15812032991c98b33b5424b17bcd55fe3575plougher	}
135443c15812032991c98b33b5424b17bcd55fe3575plougher
136443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
137443c15812032991c98b33b5424b17bcd55fe3575plougher}
138443c15812032991c98b33b5424b17bcd55fe3575plougher
139443c15812032991c98b33b5424b17bcd55fe3575plougher
140443c15812032991c98b33b5424b17bcd55fe3575plougherint read_block(long long start, long long *next, char *block, squashfs_super_block *sBlk)
141443c15812032991c98b33b5424b17bcd55fe3575plougher{
142443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned short c_byte;
143443c15812032991c98b33b5424b17bcd55fe3575plougher	int offset = 2;
144443c15812032991c98b33b5424b17bcd55fe3575plougher
145443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
146443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, 2, block) == FALSE)
147fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
148443c15812032991c98b33b5424b17bcd55fe3575plougher		((unsigned char *) &c_byte)[1] = block[0];
149443c15812032991c98b33b5424b17bcd55fe3575plougher		((unsigned char *) &c_byte)[0] = block[1];
150443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
151443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, 2, (char *)&c_byte) == FALSE)
152fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
153fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
154fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ? "compressed" : "uncompressed");
155443c15812032991c98b33b5424b17bcd55fe3575plougher
156443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_CHECK_DATA(sBlk->flags))
157443c15812032991c98b33b5424b17bcd55fe3575plougher		offset = 3;
158443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED(c_byte)) {
159443c15812032991c98b33b5424b17bcd55fe3575plougher		char buffer[SQUASHFS_METADATA_SIZE];
160443c15812032991c98b33b5424b17bcd55fe3575plougher		int res;
161443c15812032991c98b33b5424b17bcd55fe3575plougher		unsigned long bytes = SQUASHFS_METADATA_SIZE;
162443c15812032991c98b33b5424b17bcd55fe3575plougher
163443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
164443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start + offset, c_byte, buffer) == FALSE)
165fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
166443c15812032991c98b33b5424b17bcd55fe3575plougher
167443c15812032991c98b33b5424b17bcd55fe3575plougher		if((res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) buffer, c_byte)) != Z_OK) {
168443c15812032991c98b33b5424b17bcd55fe3575plougher			if(res == Z_MEM_ERROR)
169443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough memory\n");
170443c15812032991c98b33b5424b17bcd55fe3575plougher			else if(res == Z_BUF_ERROR)
171443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough room in output buffer\n");
172443c15812032991c98b33b5424b17bcd55fe3575plougher			else
173443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, unknown error %d\n", res);
174fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
175443c15812032991c98b33b5424b17bcd55fe3575plougher		}
176443c15812032991c98b33b5424b17bcd55fe3575plougher		if(next)
177443c15812032991c98b33b5424b17bcd55fe3575plougher			*next = start + offset + c_byte;
178443c15812032991c98b33b5424b17bcd55fe3575plougher		return bytes;
179443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
180443c15812032991c98b33b5424b17bcd55fe3575plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
181443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start + offset, c_byte, block) == FALSE)
182fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			goto failed;
183443c15812032991c98b33b5424b17bcd55fe3575plougher		if(next)
184443c15812032991c98b33b5424b17bcd55fe3575plougher			*next = start + offset + c_byte;
185443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
186443c15812032991c98b33b5424b17bcd55fe3575plougher	}
187fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
188fe3ca0609d02d78bcd11637c1220b2ff428f466aplougherfailed:
189fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	return FALSE;
190443c15812032991c98b33b5424b17bcd55fe3575plougher}
191443c15812032991c98b33b5424b17bcd55fe3575plougher
192443c15812032991c98b33b5424b17bcd55fe3575plougher
193443c15812032991c98b33b5424b17bcd55fe3575plougherint read_data_block(long long start, unsigned int size, char *block)
194443c15812032991c98b33b5424b17bcd55fe3575plougher{
195443c15812032991c98b33b5424b17bcd55fe3575plougher	int res;
196443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned long bytes = block_size;
197443c15812032991c98b33b5424b17bcd55fe3575plougher	int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
198443c15812032991c98b33b5424b17bcd55fe3575plougher
199fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	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");
200fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
201443c15812032991c98b33b5424b17bcd55fe3575plougher	if(SQUASHFS_COMPRESSED_BLOCK(size)) {
202443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, c_byte, data) == FALSE)
203443c15812032991c98b33b5424b17bcd55fe3575plougher			return 0;
204443c15812032991c98b33b5424b17bcd55fe3575plougher
205443c15812032991c98b33b5424b17bcd55fe3575plougher		if((res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) data, c_byte)) != Z_OK) {
206443c15812032991c98b33b5424b17bcd55fe3575plougher			if(res == Z_MEM_ERROR)
207443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough memory\n");
208443c15812032991c98b33b5424b17bcd55fe3575plougher			else if(res == Z_BUF_ERROR)
209443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, not enough room in output buffer\n");
210443c15812032991c98b33b5424b17bcd55fe3575plougher			else
211443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("zlib::uncompress failed, unknown error %d\n", res);
212443c15812032991c98b33b5424b17bcd55fe3575plougher			return 0;
213443c15812032991c98b33b5424b17bcd55fe3575plougher		}
214443c15812032991c98b33b5424b17bcd55fe3575plougher
215443c15812032991c98b33b5424b17bcd55fe3575plougher		return bytes;
216443c15812032991c98b33b5424b17bcd55fe3575plougher	} else {
217443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_bytes(start, c_byte, block) == FALSE)
218443c15812032991c98b33b5424b17bcd55fe3575plougher			return 0;
219443c15812032991c98b33b5424b17bcd55fe3575plougher
220443c15812032991c98b33b5424b17bcd55fe3575plougher		return c_byte;
221443c15812032991c98b33b5424b17bcd55fe3575plougher	}
222443c15812032991c98b33b5424b17bcd55fe3575plougher}
223443c15812032991c98b33b5424b17bcd55fe3575plougher
224443c15812032991c98b33b5424b17bcd55fe3575plougher
225443c15812032991c98b33b5424b17bcd55fe3575ploughervoid uncompress_inode_table(long long start, long long end, squashfs_super_block *sBlk)
226443c15812032991c98b33b5424b17bcd55fe3575plougher{
227443c15812032991c98b33b5424b17bcd55fe3575plougher	int size = 0, bytes = 0, res;
228443c15812032991c98b33b5424b17bcd55fe3575plougher
229443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
230443c15812032991c98b33b5424b17bcd55fe3575plougher		if((size - bytes < SQUASHFS_METADATA_SIZE) &&
231443c15812032991c98b33b5424b17bcd55fe3575plougher				((inode_table = realloc(inode_table, size += SQUASHFS_METADATA_SIZE)) == NULL))
232443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_inode_table: out of memory in realloc\n");
233443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("uncompress_inode_table: reading block 0x%llx\n", start);
234443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(inode_table_hash, start, bytes);
235443c15812032991c98b33b5424b17bcd55fe3575plougher		if((res = read_block(start, &start, inode_table + bytes, sBlk)) == 0) {
236443c15812032991c98b33b5424b17bcd55fe3575plougher			free(inode_table);
237443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_inode_table: failed to read block\n");
238443c15812032991c98b33b5424b17bcd55fe3575plougher		}
239443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
240443c15812032991c98b33b5424b17bcd55fe3575plougher	}
241443c15812032991c98b33b5424b17bcd55fe3575plougher}
242443c15812032991c98b33b5424b17bcd55fe3575plougher
243443c15812032991c98b33b5424b17bcd55fe3575plougher
244443c15812032991c98b33b5424b17bcd55fe3575plougherint set_attributes(char *pathname, unsigned int mode, unsigned int uid, unsigned int guid,
245443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int mtime, unsigned int set_mode)
246443c15812032991c98b33b5424b17bcd55fe3575plougher{
247443c15812032991c98b33b5424b17bcd55fe3575plougher	struct utimbuf times = { (time_t) mtime, (time_t) mtime };
248443c15812032991c98b33b5424b17bcd55fe3575plougher
249443c15812032991c98b33b5424b17bcd55fe3575plougher	if(utime(pathname, &times) == -1) {
250443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("set_attributes: failed to set time on %s, because %s\n", pathname, strerror(errno));
251443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
252443c15812032991c98b33b5424b17bcd55fe3575plougher	}
253443c15812032991c98b33b5424b17bcd55fe3575plougher
254443c15812032991c98b33b5424b17bcd55fe3575plougher	if(set_mode && chmod(pathname, (mode_t) mode) == -1) {
255443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("set_attributes: failed to change mode %s, because %s\n", pathname, strerror(errno));
256443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
257443c15812032991c98b33b5424b17bcd55fe3575plougher	}
258443c15812032991c98b33b5424b17bcd55fe3575plougher
259443c15812032991c98b33b5424b17bcd55fe3575plougher	if(geteuid() == 0) {
260443c15812032991c98b33b5424b17bcd55fe3575plougher		uid_t uid_value = (uid_t) uid_table[uid];
261443c15812032991c98b33b5424b17bcd55fe3575plougher		uid_t guid_value = guid == SQUASHFS_GUIDS ? uid_value : (uid_t) guid_table[guid];
262443c15812032991c98b33b5424b17bcd55fe3575plougher
263443c15812032991c98b33b5424b17bcd55fe3575plougher		if(chown(pathname, uid_value, guid_value) == -1) {
264443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("set_attributes: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno));
265443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
266443c15812032991c98b33b5424b17bcd55fe3575plougher		}
267443c15812032991c98b33b5424b17bcd55fe3575plougher	}
268443c15812032991c98b33b5424b17bcd55fe3575plougher
269443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
270443c15812032991c98b33b5424b17bcd55fe3575plougher}
271443c15812032991c98b33b5424b17bcd55fe3575plougher
272443c15812032991c98b33b5424b17bcd55fe3575plougher
273443c15812032991c98b33b5424b17bcd55fe3575ploughervoid read_uids_guids(squashfs_super_block *sBlk)
274443c15812032991c98b33b5424b17bcd55fe3575plougher{
275443c15812032991c98b33b5424b17bcd55fe3575plougher	if((uid_table = malloc((sBlk->no_uids + sBlk->no_guids) * sizeof(unsigned int))) == NULL)
276443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("read_uids_guids: failed to allocate uid/gid table\n");
277443c15812032991c98b33b5424b17bcd55fe3575plougher
278443c15812032991c98b33b5424b17bcd55fe3575plougher	guid_table = uid_table + sBlk->no_uids;
279443c15812032991c98b33b5424b17bcd55fe3575plougher
280fc9aa5457df027969c6616cdf93fc1945ad7688eplougher	if(swap) {
281fc9aa5457df027969c6616cdf93fc1945ad7688eplougher		unsigned int suid_table[sBlk->no_uids + sBlk->no_guids];
282fc9aa5457df027969c6616cdf93fc1945ad7688eplougher
283fc9aa5457df027969c6616cdf93fc1945ad7688eplougher		if(read_bytes(sBlk->uid_start, (sBlk->no_uids + sBlk->no_guids) * sizeof(unsigned int), (char *) suid_table) ==
284fc9aa5457df027969c6616cdf93fc1945ad7688eplougher			FALSE)
285fc9aa5457df027969c6616cdf93fc1945ad7688eplougher			EXIT_UNSQUASH("read_uids_guids: failed to read uid/gid table\n");
286fc9aa5457df027969c6616cdf93fc1945ad7688eplougher		SQUASHFS_SWAP_INTS(uid_table, suid_table, sBlk->no_uids + sBlk->no_guids);
287fc9aa5457df027969c6616cdf93fc1945ad7688eplougher	} else
288fc9aa5457df027969c6616cdf93fc1945ad7688eplougher		if(read_bytes(sBlk->uid_start, (sBlk->no_uids + sBlk->no_guids) * sizeof(unsigned int), (char *) uid_table) ==
289443c15812032991c98b33b5424b17bcd55fe3575plougher			FALSE)
290fc9aa5457df027969c6616cdf93fc1945ad7688eplougher			EXIT_UNSQUASH("read_uids_guids: failed to read uid/gid table\n");
291443c15812032991c98b33b5424b17bcd55fe3575plougher}
292443c15812032991c98b33b5424b17bcd55fe3575plougher
293443c15812032991c98b33b5424b17bcd55fe3575plougher
294443c15812032991c98b33b5424b17bcd55fe3575ploughervoid read_fragment_table(squashfs_super_block *sBlk)
295443c15812032991c98b33b5424b17bcd55fe3575plougher{
296443c15812032991c98b33b5424b17bcd55fe3575plougher	int i, indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments);
297443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_fragment_index fragment_table_index[indexes];
298443c15812032991c98b33b5424b17bcd55fe3575plougher
299fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk->fragments, indexes, sBlk->fragment_table_start);
300443c15812032991c98b33b5424b17bcd55fe3575plougher	if(sBlk->fragments == 0)
301443c15812032991c98b33b5424b17bcd55fe3575plougher		return;
302443c15812032991c98b33b5424b17bcd55fe3575plougher
303443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fragment_table = (squashfs_fragment_entry *) malloc(sBlk->fragments * sizeof(squashfs_fragment_entry))) == NULL)
304443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("read_fragment_table: failed to allocate fragment table\n");
305443c15812032991c98b33b5424b17bcd55fe3575plougher
306443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
307443c15812032991c98b33b5424b17bcd55fe3575plougher		squashfs_fragment_index sfragment_table_index[indexes];
308443c15812032991c98b33b5424b17bcd55fe3575plougher
309443c15812032991c98b33b5424b17bcd55fe3575plougher		read_bytes(sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) sfragment_table_index);
310443c15812032991c98b33b5424b17bcd55fe3575plougher		SQUASHFS_SWAP_FRAGMENT_INDEXES(fragment_table_index, sfragment_table_index, indexes);
311443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
312443c15812032991c98b33b5424b17bcd55fe3575plougher		read_bytes(sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) fragment_table_index);
313443c15812032991c98b33b5424b17bcd55fe3575plougher
314443c15812032991c98b33b5424b17bcd55fe3575plougher	for(i = 0; i < indexes; i++) {
315443c15812032991c98b33b5424b17bcd55fe3575plougher		int length = read_block(fragment_table_index[i], NULL, ((char *) fragment_table) + (i * SQUASHFS_METADATA_SIZE), sBlk);
316fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher		TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length);
317443c15812032991c98b33b5424b17bcd55fe3575plougher	}
318443c15812032991c98b33b5424b17bcd55fe3575plougher
319443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
320443c15812032991c98b33b5424b17bcd55fe3575plougher		squashfs_fragment_entry sfragment;
321443c15812032991c98b33b5424b17bcd55fe3575plougher		for(i = 0; i < sBlk->fragments; i++) {
322443c15812032991c98b33b5424b17bcd55fe3575plougher			SQUASHFS_SWAP_FRAGMENT_ENTRY((&sfragment), (&fragment_table[i]));
323443c15812032991c98b33b5424b17bcd55fe3575plougher			memcpy((char *) &fragment_table[i], (char *) &sfragment, sizeof(squashfs_fragment_entry));
324443c15812032991c98b33b5424b17bcd55fe3575plougher		}
325443c15812032991c98b33b5424b17bcd55fe3575plougher	}
326443c15812032991c98b33b5424b17bcd55fe3575plougher}
327443c15812032991c98b33b5424b17bcd55fe3575plougher
328443c15812032991c98b33b5424b17bcd55fe3575plougher
329443c15812032991c98b33b5424b17bcd55fe3575plougherchar *read_fragment(unsigned int fragment)
330443c15812032991c98b33b5424b17bcd55fe3575plougher{
331fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("read_fragment: reading fragment %d\n", fragment);
332fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
333443c15812032991c98b33b5424b17bcd55fe3575plougher	if(cached_frag == SQUASHFS_INVALID_FRAG || fragment != cached_frag) {
334443c15812032991c98b33b5424b17bcd55fe3575plougher		squashfs_fragment_entry *fragment_entry = &fragment_table[fragment];
335443c15812032991c98b33b5424b17bcd55fe3575plougher		if(read_data_block(fragment_entry->start_block, fragment_entry->size, fragment_data) == 0) {
336443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("read_fragment: failed to read fragment %d\n", fragment);
337443c15812032991c98b33b5424b17bcd55fe3575plougher			cached_frag = SQUASHFS_INVALID_FRAG;
338443c15812032991c98b33b5424b17bcd55fe3575plougher			return NULL;
339443c15812032991c98b33b5424b17bcd55fe3575plougher		}
340443c15812032991c98b33b5424b17bcd55fe3575plougher		cached_frag = fragment;
341443c15812032991c98b33b5424b17bcd55fe3575plougher	}
342443c15812032991c98b33b5424b17bcd55fe3575plougher
343443c15812032991c98b33b5424b17bcd55fe3575plougher	return fragment_data;
344443c15812032991c98b33b5424b17bcd55fe3575plougher}
345443c15812032991c98b33b5424b17bcd55fe3575plougher
346443c15812032991c98b33b5424b17bcd55fe3575plougher
347443c15812032991c98b33b5424b17bcd55fe3575plougherint write_file(char *pathname, unsigned int fragment, unsigned int frag_bytes, unsigned int offset,
348443c15812032991c98b33b5424b17bcd55fe3575plougherunsigned int blocks, long long start, char *block_ptr, unsigned int mode)
349443c15812032991c98b33b5424b17bcd55fe3575plougher{
350f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher	unsigned int file_fd, bytes, i;
351f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher	unsigned int *block_list;
352443c15812032991c98b33b5424b17bcd55fe3575plougher
353443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("write_file: regular file, blocks %d\n", blocks);
354443c15812032991c98b33b5424b17bcd55fe3575plougher
355f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher	if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) {
356f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher		ERROR("write_file: unable to malloc block list\n");
357f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher		return FALSE;
358f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher	}
359f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher
360443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
361443c15812032991c98b33b5424b17bcd55fe3575plougher		unsigned int sblock_list[blocks];
362443c15812032991c98b33b5424b17bcd55fe3575plougher		memcpy(sblock_list, block_ptr, blocks * sizeof(unsigned int));
363443c15812032991c98b33b5424b17bcd55fe3575plougher		SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks);
364443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
365443c15812032991c98b33b5424b17bcd55fe3575plougher		memcpy(block_list, block_ptr, blocks * sizeof(unsigned int));
366443c15812032991c98b33b5424b17bcd55fe3575plougher
367443c15812032991c98b33b5424b17bcd55fe3575plougher	if((file_fd = open(pathname, O_CREAT | O_WRONLY, (mode_t) mode)) == -1) {
368443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("write_file: failed to create file %s, because %s\n", pathname,
369443c15812032991c98b33b5424b17bcd55fe3575plougher			strerror(errno));
370f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher		free(block_list);
371443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
372443c15812032991c98b33b5424b17bcd55fe3575plougher	}
373443c15812032991c98b33b5424b17bcd55fe3575plougher
374443c15812032991c98b33b5424b17bcd55fe3575plougher	for(i = 0; i < blocks; i++) {
375443c15812032991c98b33b5424b17bcd55fe3575plougher		if((bytes = read_data_block(start, block_list[i], file_data)) == 0) {
376fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			ERROR("write_file: failed to read data block 0x%llx\n", start);
377443c15812032991c98b33b5424b17bcd55fe3575plougher			goto failure;
378443c15812032991c98b33b5424b17bcd55fe3575plougher		}
379443c15812032991c98b33b5424b17bcd55fe3575plougher
380443c15812032991c98b33b5424b17bcd55fe3575plougher		if(write(file_fd, file_data, bytes) < bytes) {
381fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			ERROR("write_file: failed to write data block 0x%llx\n", start);
382443c15812032991c98b33b5424b17bcd55fe3575plougher			goto failure;
383443c15812032991c98b33b5424b17bcd55fe3575plougher		}
384443c15812032991c98b33b5424b17bcd55fe3575plougher
385443c15812032991c98b33b5424b17bcd55fe3575plougher		start += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
386443c15812032991c98b33b5424b17bcd55fe3575plougher	}
387443c15812032991c98b33b5424b17bcd55fe3575plougher
388443c15812032991c98b33b5424b17bcd55fe3575plougher	if(frag_bytes != 0) {
389443c15812032991c98b33b5424b17bcd55fe3575plougher		char *fragment_data = read_fragment(fragment);
390443c15812032991c98b33b5424b17bcd55fe3575plougher
391443c15812032991c98b33b5424b17bcd55fe3575plougher		if(fragment_data == NULL)
392443c15812032991c98b33b5424b17bcd55fe3575plougher			goto failure;
393443c15812032991c98b33b5424b17bcd55fe3575plougher
394443c15812032991c98b33b5424b17bcd55fe3575plougher		if(write(file_fd, fragment_data + offset, frag_bytes) < frag_bytes) {
395fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			ERROR("write_file: failed to write fragment %d\n", fragment);
396443c15812032991c98b33b5424b17bcd55fe3575plougher			goto failure;
397443c15812032991c98b33b5424b17bcd55fe3575plougher		}
398443c15812032991c98b33b5424b17bcd55fe3575plougher	}
399443c15812032991c98b33b5424b17bcd55fe3575plougher
400443c15812032991c98b33b5424b17bcd55fe3575plougher	close(file_fd);
401443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
402443c15812032991c98b33b5424b17bcd55fe3575plougher
403443c15812032991c98b33b5424b17bcd55fe3575plougherfailure:
404443c15812032991c98b33b5424b17bcd55fe3575plougher	close(file_fd);
405f9c72b137336d5c1d4bdf2792f2bc5142713676bplougher	free(block_list);
406443c15812032991c98b33b5424b17bcd55fe3575plougher	return FALSE;
407443c15812032991c98b33b5424b17bcd55fe3575plougher}
408443c15812032991c98b33b5424b17bcd55fe3575plougher
409443c15812032991c98b33b5424b17bcd55fe3575plougher
410443c15812032991c98b33b5424b17bcd55fe3575plougherint create_inode(char *pathname, unsigned int start_block, unsigned int offset, squashfs_super_block *sBlk)
411443c15812032991c98b33b5424b17bcd55fe3575plougher{
412443c15812032991c98b33b5424b17bcd55fe3575plougher	long long start = sBlk->inode_table_start + start_block;
413443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_inode_header header;
414443c15812032991c98b33b5424b17bcd55fe3575plougher	char *block_ptr;
415443c15812032991c98b33b5424b17bcd55fe3575plougher	int bytes = lookup_entry(inode_table_hash, start), file_fd;
416443c15812032991c98b33b5424b17bcd55fe3575plougher
417fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("create_inode: pathname %s, start 0x%llx, offset %d\n", pathname, start, offset);
418443c15812032991c98b33b5424b17bcd55fe3575plougher
419443c15812032991c98b33b5424b17bcd55fe3575plougher	if(bytes == -1) {
420443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("create_inode: inode block 0x%llx out of range!\n", start);
421443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
422443c15812032991c98b33b5424b17bcd55fe3575plougher	}
423443c15812032991c98b33b5424b17bcd55fe3575plougher	block_ptr = inode_table + bytes + offset;
424443c15812032991c98b33b5424b17bcd55fe3575plougher
425443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
426443c15812032991c98b33b5424b17bcd55fe3575plougher		squashfs_base_inode_header sinode;
427443c15812032991c98b33b5424b17bcd55fe3575plougher		memcpy(&sinode, block_ptr, sizeof(header.base));
428443c15812032991c98b33b5424b17bcd55fe3575plougher		SQUASHFS_SWAP_BASE_INODE_HEADER(&header.base, &sinode, sizeof(squashfs_base_inode_header));
429443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
430443c15812032991c98b33b5424b17bcd55fe3575plougher		memcpy(&header.base, block_ptr, sizeof(header.base));
431443c15812032991c98b33b5424b17bcd55fe3575plougher
432443c15812032991c98b33b5424b17bcd55fe3575plougher	if(created_inode[header.base.inode_number - 1]) {
433443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("create_inode: hard link\n");
434443c15812032991c98b33b5424b17bcd55fe3575plougher		if(link(created_inode[header.base.inode_number - 1], pathname) == -1) {
435443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("create_inode: failed to create hardlink, because %s\n", strerror(errno));
436443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
437443c15812032991c98b33b5424b17bcd55fe3575plougher		}
438443c15812032991c98b33b5424b17bcd55fe3575plougher
439443c15812032991c98b33b5424b17bcd55fe3575plougher		return TRUE;
440443c15812032991c98b33b5424b17bcd55fe3575plougher	}
441443c15812032991c98b33b5424b17bcd55fe3575plougher
442443c15812032991c98b33b5424b17bcd55fe3575plougher	switch(header.base.inode_type) {
443443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_FILE_TYPE: {
444443c15812032991c98b33b5424b17bcd55fe3575plougher			unsigned int frag_bytes;
445443c15812032991c98b33b5424b17bcd55fe3575plougher			unsigned int blocks;
446443c15812032991c98b33b5424b17bcd55fe3575plougher			unsigned int offset;
447443c15812032991c98b33b5424b17bcd55fe3575plougher			long long start;
448443c15812032991c98b33b5424b17bcd55fe3575plougher			squashfs_reg_inode_header *inode = &header.reg;
449443c15812032991c98b33b5424b17bcd55fe3575plougher
450443c15812032991c98b33b5424b17bcd55fe3575plougher			if(swap) {
451443c15812032991c98b33b5424b17bcd55fe3575plougher				squashfs_reg_inode_header sinode;
452443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(&sinode, block_ptr, sizeof(sinode));
453443c15812032991c98b33b5424b17bcd55fe3575plougher				SQUASHFS_SWAP_REG_INODE_HEADER(inode, &sinode);
454443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
455443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(inode, block_ptr, sizeof(*inode));
456443c15812032991c98b33b5424b17bcd55fe3575plougher
457443c15812032991c98b33b5424b17bcd55fe3575plougher			frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk->block_size;
458443c15812032991c98b33b5424b17bcd55fe3575plougher			offset = inode->offset;
459443c15812032991c98b33b5424b17bcd55fe3575plougher			blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size
460443c15812032991c98b33b5424b17bcd55fe3575plougher				+ sBlk->block_size - 1) >> sBlk->block_log : inode->file_size >>
461443c15812032991c98b33b5424b17bcd55fe3575plougher				sBlk->block_log;
462443c15812032991c98b33b5424b17bcd55fe3575plougher			start = inode->start_block;
463443c15812032991c98b33b5424b17bcd55fe3575plougher
464443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks);
465443c15812032991c98b33b5424b17bcd55fe3575plougher
466443c15812032991c98b33b5424b17bcd55fe3575plougher			if(write_file(pathname, inode->fragment, frag_bytes, offset, blocks, start,
467443c15812032991c98b33b5424b17bcd55fe3575plougher					block_ptr + sizeof(*inode), inode->mode)) {
468443c15812032991c98b33b5424b17bcd55fe3575plougher				set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, FALSE);
469443c15812032991c98b33b5424b17bcd55fe3575plougher				file_count ++;
470443c15812032991c98b33b5424b17bcd55fe3575plougher			}
471443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
472443c15812032991c98b33b5424b17bcd55fe3575plougher		}
473443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_LREG_TYPE: {
474443c15812032991c98b33b5424b17bcd55fe3575plougher			unsigned int frag_bytes;
475443c15812032991c98b33b5424b17bcd55fe3575plougher			unsigned int blocks;
476443c15812032991c98b33b5424b17bcd55fe3575plougher			unsigned int offset;
477443c15812032991c98b33b5424b17bcd55fe3575plougher			long long start;
478443c15812032991c98b33b5424b17bcd55fe3575plougher			squashfs_lreg_inode_header *inode = &header.lreg;
479443c15812032991c98b33b5424b17bcd55fe3575plougher
480443c15812032991c98b33b5424b17bcd55fe3575plougher			if(swap) {
481443c15812032991c98b33b5424b17bcd55fe3575plougher				squashfs_lreg_inode_header sinode;
482443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(&sinode, block_ptr, sizeof(sinode));
483443c15812032991c98b33b5424b17bcd55fe3575plougher				SQUASHFS_SWAP_LREG_INODE_HEADER(inode, &sinode);
484443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
485443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(inode, block_ptr, sizeof(*inode));
486443c15812032991c98b33b5424b17bcd55fe3575plougher
487443c15812032991c98b33b5424b17bcd55fe3575plougher			frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk->block_size;
488443c15812032991c98b33b5424b17bcd55fe3575plougher			offset = inode->offset;
489443c15812032991c98b33b5424b17bcd55fe3575plougher			blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size
490443c15812032991c98b33b5424b17bcd55fe3575plougher				+ sBlk->block_size - 1) >> sBlk->block_log : inode->file_size >>
491443c15812032991c98b33b5424b17bcd55fe3575plougher				sBlk->block_log;
492443c15812032991c98b33b5424b17bcd55fe3575plougher			start = inode->start_block;
493443c15812032991c98b33b5424b17bcd55fe3575plougher
494443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks);
495443c15812032991c98b33b5424b17bcd55fe3575plougher
496443c15812032991c98b33b5424b17bcd55fe3575plougher			if(write_file(pathname, inode->fragment, frag_bytes, offset, blocks, start,
497443c15812032991c98b33b5424b17bcd55fe3575plougher					block_ptr + sizeof(*inode), inode->mode)) {
498443c15812032991c98b33b5424b17bcd55fe3575plougher				set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, FALSE);
499443c15812032991c98b33b5424b17bcd55fe3575plougher				file_count ++;
500443c15812032991c98b33b5424b17bcd55fe3575plougher			}
501443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
502443c15812032991c98b33b5424b17bcd55fe3575plougher		}
503443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_SYMLINK_TYPE: {
504443c15812032991c98b33b5424b17bcd55fe3575plougher			squashfs_symlink_inode_header *inodep = &header.symlink;
505443c15812032991c98b33b5424b17bcd55fe3575plougher			char name[65536];
506443c15812032991c98b33b5424b17bcd55fe3575plougher
507443c15812032991c98b33b5424b17bcd55fe3575plougher			if(swap) {
508443c15812032991c98b33b5424b17bcd55fe3575plougher				squashfs_symlink_inode_header sinodep;
509443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(&sinodep, block_ptr, sizeof(sinodep));
510443c15812032991c98b33b5424b17bcd55fe3575plougher				SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, &sinodep);
511443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
512443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(inodep, block_ptr, sizeof(*inodep));
513443c15812032991c98b33b5424b17bcd55fe3575plougher
514443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: symlink, symlink_size %d\n", inodep->symlink_size);
515443c15812032991c98b33b5424b17bcd55fe3575plougher
516443c15812032991c98b33b5424b17bcd55fe3575plougher			strncpy(name, block_ptr + sizeof(squashfs_symlink_inode_header), inodep->symlink_size);
517443c15812032991c98b33b5424b17bcd55fe3575plougher			name[inodep->symlink_size] = '\0';
518443c15812032991c98b33b5424b17bcd55fe3575plougher
519443c15812032991c98b33b5424b17bcd55fe3575plougher			if(symlink(name, pathname) == -1) {
520443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("create_inode: failed to create symlink %s, because %s\n", pathname,
521443c15812032991c98b33b5424b17bcd55fe3575plougher					strerror(errno));
522443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
523443c15812032991c98b33b5424b17bcd55fe3575plougher			}
524443c15812032991c98b33b5424b17bcd55fe3575plougher
525443c15812032991c98b33b5424b17bcd55fe3575plougher			if(geteuid() == 0) {
526443c15812032991c98b33b5424b17bcd55fe3575plougher				uid_t uid_value = (uid_t) uid_table[inodep->uid];
527443c15812032991c98b33b5424b17bcd55fe3575plougher				uid_t guid_value = inodep->guid == SQUASHFS_GUIDS ? uid_value : (uid_t) guid_table[inodep->guid];
528443c15812032991c98b33b5424b17bcd55fe3575plougher
529443c15812032991c98b33b5424b17bcd55fe3575plougher				if(lchown(pathname, uid_value, guid_value) == -1)
530443c15812032991c98b33b5424b17bcd55fe3575plougher					ERROR("create_inode: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno));
531443c15812032991c98b33b5424b17bcd55fe3575plougher			}
532443c15812032991c98b33b5424b17bcd55fe3575plougher
533443c15812032991c98b33b5424b17bcd55fe3575plougher			sym_count ++;
534443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
535443c15812032991c98b33b5424b17bcd55fe3575plougher		}
536443c15812032991c98b33b5424b17bcd55fe3575plougher 		case SQUASHFS_BLKDEV_TYPE:
537443c15812032991c98b33b5424b17bcd55fe3575plougher	 	case SQUASHFS_CHRDEV_TYPE: {
538443c15812032991c98b33b5424b17bcd55fe3575plougher			squashfs_dev_inode_header *inodep = &header.dev;
539443c15812032991c98b33b5424b17bcd55fe3575plougher
540443c15812032991c98b33b5424b17bcd55fe3575plougher			if(swap) {
541443c15812032991c98b33b5424b17bcd55fe3575plougher				squashfs_dev_inode_header sinodep;
542443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(&sinodep, block_ptr, sizeof(sinodep));
543443c15812032991c98b33b5424b17bcd55fe3575plougher				SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, &sinodep);
544443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
545443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(inodep, block_ptr, sizeof(*inodep));
546443c15812032991c98b33b5424b17bcd55fe3575plougher
547443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: dev, rdev 0x%x\n", inodep->rdev);
548443c15812032991c98b33b5424b17bcd55fe3575plougher
549443c15812032991c98b33b5424b17bcd55fe3575plougher			if(geteuid() == 0) {
550443c15812032991c98b33b5424b17bcd55fe3575plougher				if(mknod(pathname, inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? S_IFCHR : S_IFBLK,
551443c15812032991c98b33b5424b17bcd55fe3575plougher							makedev((inodep->rdev >> 8) & 0xff, inodep->rdev & 0xff))
552443c15812032991c98b33b5424b17bcd55fe3575plougher							== -1) {
553443c15812032991c98b33b5424b17bcd55fe3575plougher					ERROR("create_inode: failed to create %s device %s, because %s\n",
554443c15812032991c98b33b5424b17bcd55fe3575plougher						inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block",
555443c15812032991c98b33b5424b17bcd55fe3575plougher						pathname, strerror(errno));
556443c15812032991c98b33b5424b17bcd55fe3575plougher					break;
557443c15812032991c98b33b5424b17bcd55fe3575plougher				}
558443c15812032991c98b33b5424b17bcd55fe3575plougher				set_attributes(pathname, inodep->mode, inodep->uid, inodep->guid, inodep->mtime, TRUE);
559443c15812032991c98b33b5424b17bcd55fe3575plougher				dev_count ++;
560443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
561443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("create_inode: could not create %s device %s, because you're not superuser!\n",
562443c15812032991c98b33b5424b17bcd55fe3575plougher					inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block",
563443c15812032991c98b33b5424b17bcd55fe3575plougher					pathname, strerror(errno));
564443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
565fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			}
566443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_FIFO_TYPE:
567443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: fifo\n");
568443c15812032991c98b33b5424b17bcd55fe3575plougher
569443c15812032991c98b33b5424b17bcd55fe3575plougher			if(mknod(pathname, S_IFIFO, 0) == -1) {
570443c15812032991c98b33b5424b17bcd55fe3575plougher				ERROR("create_inode: failed to create fifo %s, because %s\n",
571443c15812032991c98b33b5424b17bcd55fe3575plougher					pathname, strerror(errno));
572443c15812032991c98b33b5424b17bcd55fe3575plougher				break;
573443c15812032991c98b33b5424b17bcd55fe3575plougher			}
574443c15812032991c98b33b5424b17bcd55fe3575plougher			set_attributes(pathname, header.base.mode, header.base.uid, header.base.guid,
575443c15812032991c98b33b5424b17bcd55fe3575plougher				header.base.mtime, TRUE);
576443c15812032991c98b33b5424b17bcd55fe3575plougher			fifo_count ++;
577443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
578443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_SOCKET_TYPE:
579443c15812032991c98b33b5424b17bcd55fe3575plougher			TRACE("create_inode: socket\n");
580443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("create_inode: socket %s ignored\n", pathname);
581443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
582443c15812032991c98b33b5424b17bcd55fe3575plougher		default:
583443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("Unknown inode type %d in create_inode_table!\n", header.base.inode_type);
584443c15812032991c98b33b5424b17bcd55fe3575plougher			return FALSE;
585443c15812032991c98b33b5424b17bcd55fe3575plougher	}
586fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
587443c15812032991c98b33b5424b17bcd55fe3575plougher	created_inode[header.base.inode_number - 1] = strdup(pathname);
588443c15812032991c98b33b5424b17bcd55fe3575plougher
589443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
590443c15812032991c98b33b5424b17bcd55fe3575plougher}
591443c15812032991c98b33b5424b17bcd55fe3575plougher
592443c15812032991c98b33b5424b17bcd55fe3575plougher
593443c15812032991c98b33b5424b17bcd55fe3575ploughervoid uncompress_directory_table(long long start, long long end, squashfs_super_block *sBlk)
594443c15812032991c98b33b5424b17bcd55fe3575plougher{
595443c15812032991c98b33b5424b17bcd55fe3575plougher	int bytes = 0, size = 0, res;
596443c15812032991c98b33b5424b17bcd55fe3575plougher
597443c15812032991c98b33b5424b17bcd55fe3575plougher	while(start < end) {
598443c15812032991c98b33b5424b17bcd55fe3575plougher		if(size - bytes < SQUASHFS_METADATA_SIZE && (directory_table = realloc(directory_table, size += SQUASHFS_METADATA_SIZE)) == NULL)
599443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_directory_table: out of memory in realloc\n");
600443c15812032991c98b33b5424b17bcd55fe3575plougher		TRACE("uncompress_directory_table: reading block 0x%llx\n", start);
601443c15812032991c98b33b5424b17bcd55fe3575plougher		add_entry(directory_table_hash, start, bytes);
602443c15812032991c98b33b5424b17bcd55fe3575plougher		if((res = read_block(start, &start, directory_table + bytes, sBlk)) == 0)
603443c15812032991c98b33b5424b17bcd55fe3575plougher			EXIT_UNSQUASH("uncompress_directory_table: failed to read block\n");
604443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += res;
605443c15812032991c98b33b5424b17bcd55fe3575plougher	}
606443c15812032991c98b33b5424b17bcd55fe3575plougher}
607443c15812032991c98b33b5424b17bcd55fe3575plougher
608443c15812032991c98b33b5424b17bcd55fe3575plougher
609443c15812032991c98b33b5424b17bcd55fe3575plougher#define DIR_ENT_SIZE	16
610443c15812032991c98b33b5424b17bcd55fe3575plougher
611443c15812032991c98b33b5424b17bcd55fe3575plougherstruct dir_ent	{
612443c15812032991c98b33b5424b17bcd55fe3575plougher	char		name[SQUASHFS_NAME_LEN + 1];
613443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	start_block;
614443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	offset;
615443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	type;
616443c15812032991c98b33b5424b17bcd55fe3575plougher};
617443c15812032991c98b33b5424b17bcd55fe3575plougher
618443c15812032991c98b33b5424b17bcd55fe3575plougherstruct dir {
619443c15812032991c98b33b5424b17bcd55fe3575plougher	int		dir_count;
620443c15812032991c98b33b5424b17bcd55fe3575plougher	int 		cur_entry;
621443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	mode;
622443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	uid;
623443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	guid;
624443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int	mtime;
625443c15812032991c98b33b5424b17bcd55fe3575plougher	struct dir_ent	*dirs;
626443c15812032991c98b33b5424b17bcd55fe3575plougher};
627443c15812032991c98b33b5424b17bcd55fe3575plougher
628443c15812032991c98b33b5424b17bcd55fe3575plougher
629443c15812032991c98b33b5424b17bcd55fe3575plougherstruct dir *squashfs_openddir(unsigned int block_start, unsigned int offset, squashfs_super_block *sBlk)
630443c15812032991c98b33b5424b17bcd55fe3575plougher{
631443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_dir_header dirh;
632443c15812032991c98b33b5424b17bcd55fe3575plougher	char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
633443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer;
634443c15812032991c98b33b5424b17bcd55fe3575plougher	long long start = sBlk->inode_table_start + block_start;
635443c15812032991c98b33b5424b17bcd55fe3575plougher	char *block_ptr;
636443c15812032991c98b33b5424b17bcd55fe3575plougher	int bytes = lookup_entry(inode_table_hash, start);
637443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_inode_header header;
638443c15812032991c98b33b5424b17bcd55fe3575plougher	int dir_count, size;
639443c15812032991c98b33b5424b17bcd55fe3575plougher	struct dir_ent *new_dir;
640443c15812032991c98b33b5424b17bcd55fe3575plougher	struct dir *dir;
641443c15812032991c98b33b5424b17bcd55fe3575plougher
642fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("squashfs_opendir: inode start block %d, offset %d\n", block_start, offset);
643443c15812032991c98b33b5424b17bcd55fe3575plougher
644443c15812032991c98b33b5424b17bcd55fe3575plougher	if(bytes == -1) {
645fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher		ERROR("squashfs_opendir: inode block %d not found!\n", block_start);
646443c15812032991c98b33b5424b17bcd55fe3575plougher		return NULL;
647443c15812032991c98b33b5424b17bcd55fe3575plougher	}
648443c15812032991c98b33b5424b17bcd55fe3575plougher	block_ptr = inode_table + bytes + offset;
649443c15812032991c98b33b5424b17bcd55fe3575plougher
650443c15812032991c98b33b5424b17bcd55fe3575plougher	if(swap) {
651443c15812032991c98b33b5424b17bcd55fe3575plougher		squashfs_dir_inode_header sinode;
652443c15812032991c98b33b5424b17bcd55fe3575plougher		memcpy(&sinode, block_ptr, sizeof(header.dir));
653443c15812032991c98b33b5424b17bcd55fe3575plougher		SQUASHFS_SWAP_DIR_INODE_HEADER(&header.dir, &sinode);
654443c15812032991c98b33b5424b17bcd55fe3575plougher	} else
655443c15812032991c98b33b5424b17bcd55fe3575plougher		memcpy(&header.dir, block_ptr, sizeof(header.dir));
656443c15812032991c98b33b5424b17bcd55fe3575plougher
657443c15812032991c98b33b5424b17bcd55fe3575plougher	switch(header.dir.inode_type) {
658443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_DIR_TYPE:
659443c15812032991c98b33b5424b17bcd55fe3575plougher			block_start = header.dir.start_block;
660443c15812032991c98b33b5424b17bcd55fe3575plougher			offset = header.dir.offset;
661443c15812032991c98b33b5424b17bcd55fe3575plougher			size = header.dir.file_size;
662443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
663443c15812032991c98b33b5424b17bcd55fe3575plougher		case SQUASHFS_LDIR_TYPE:
664443c15812032991c98b33b5424b17bcd55fe3575plougher			if(swap) {
665443c15812032991c98b33b5424b17bcd55fe3575plougher				squashfs_ldir_inode_header sinode;
666443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(&sinode, block_ptr, sizeof(header.ldir));
667443c15812032991c98b33b5424b17bcd55fe3575plougher				SQUASHFS_SWAP_LDIR_INODE_HEADER(&header.ldir, &sinode);
668443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
669443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(&header.ldir, block_ptr, sizeof(header.ldir));
670443c15812032991c98b33b5424b17bcd55fe3575plougher			block_start = header.ldir.start_block;
671443c15812032991c98b33b5424b17bcd55fe3575plougher			offset = header.ldir.offset;
672443c15812032991c98b33b5424b17bcd55fe3575plougher			size = header.ldir.file_size;
673443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
674443c15812032991c98b33b5424b17bcd55fe3575plougher		default:
675443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("squashfs_opendir: inode not a directory\n");
676443c15812032991c98b33b5424b17bcd55fe3575plougher			return NULL;
677443c15812032991c98b33b5424b17bcd55fe3575plougher	}
678443c15812032991c98b33b5424b17bcd55fe3575plougher
679443c15812032991c98b33b5424b17bcd55fe3575plougher	start = sBlk->directory_table_start + block_start;
680443c15812032991c98b33b5424b17bcd55fe3575plougher	bytes = lookup_entry(directory_table_hash, start);
681443c15812032991c98b33b5424b17bcd55fe3575plougher
682443c15812032991c98b33b5424b17bcd55fe3575plougher	if(bytes == -1) {
683fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher		ERROR("squashfs_opendir: directory block %d not found!\n", block_start);
684443c15812032991c98b33b5424b17bcd55fe3575plougher		return NULL;
685443c15812032991c98b33b5424b17bcd55fe3575plougher	}
686443c15812032991c98b33b5424b17bcd55fe3575plougher	bytes += offset;
687443c15812032991c98b33b5424b17bcd55fe3575plougher	size += bytes - 3;
688443c15812032991c98b33b5424b17bcd55fe3575plougher
689443c15812032991c98b33b5424b17bcd55fe3575plougher	if((dir = malloc(sizeof(struct dir))) == NULL) {
690443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("squashfs_opendir: malloc failed!\n");
691443c15812032991c98b33b5424b17bcd55fe3575plougher		return NULL;
692443c15812032991c98b33b5424b17bcd55fe3575plougher	}
693443c15812032991c98b33b5424b17bcd55fe3575plougher
694443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->dir_count = 0;
695443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->cur_entry = 0;
696443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->mode = header.dir.mode;
697443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->uid = header.dir.uid;
698443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->guid = header.dir.guid;
699443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->mtime = header.dir.mtime;
700443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->dirs = NULL;
701443c15812032991c98b33b5424b17bcd55fe3575plougher
702fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	while(bytes < size) {
703443c15812032991c98b33b5424b17bcd55fe3575plougher		if(swap) {
704443c15812032991c98b33b5424b17bcd55fe3575plougher			squashfs_dir_header sdirh;
705443c15812032991c98b33b5424b17bcd55fe3575plougher			memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
706443c15812032991c98b33b5424b17bcd55fe3575plougher			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
707443c15812032991c98b33b5424b17bcd55fe3575plougher		} else
708443c15812032991c98b33b5424b17bcd55fe3575plougher			memcpy(&dirh, directory_table + bytes, sizeof(dirh));
709fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
710443c15812032991c98b33b5424b17bcd55fe3575plougher		dir_count = dirh.count + 1;
711fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher		TRACE("squashfs_opendir: Read directory header @ byte position %d, %d directory entries\n", bytes, dir_count);
712443c15812032991c98b33b5424b17bcd55fe3575plougher		bytes += sizeof(dirh);
713443c15812032991c98b33b5424b17bcd55fe3575plougher
714443c15812032991c98b33b5424b17bcd55fe3575plougher		while(dir_count--) {
715443c15812032991c98b33b5424b17bcd55fe3575plougher			if(swap) {
716443c15812032991c98b33b5424b17bcd55fe3575plougher				squashfs_dir_entry sdire;
717443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(&sdire, directory_table + bytes, sizeof(sdire));
718443c15812032991c98b33b5424b17bcd55fe3575plougher				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
719443c15812032991c98b33b5424b17bcd55fe3575plougher			} else
720443c15812032991c98b33b5424b17bcd55fe3575plougher				memcpy(dire, directory_table + bytes, sizeof(dire));
721443c15812032991c98b33b5424b17bcd55fe3575plougher			bytes += sizeof(*dire);
722443c15812032991c98b33b5424b17bcd55fe3575plougher
723443c15812032991c98b33b5424b17bcd55fe3575plougher			memcpy(dire->name, directory_table + bytes, dire->size + 1);
724443c15812032991c98b33b5424b17bcd55fe3575plougher			dire->name[dire->size + 1] = '\0';
725fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher			TRACE("squashfs_opendir: directory entry %s, inode %d:%d, type %d\n", dire->name, dirh.start_block, dire->offset, dire->type);
726443c15812032991c98b33b5424b17bcd55fe3575plougher			if((dir->dir_count % DIR_ENT_SIZE) == 0) {
727443c15812032991c98b33b5424b17bcd55fe3575plougher				if((new_dir = realloc(dir->dirs, (dir->dir_count + DIR_ENT_SIZE) * sizeof(struct dir_ent))) == NULL) {
728443c15812032991c98b33b5424b17bcd55fe3575plougher					ERROR("squashfs_opendir: realloc failed!\n");
729443c15812032991c98b33b5424b17bcd55fe3575plougher					free(dir->dirs);
730443c15812032991c98b33b5424b17bcd55fe3575plougher					free(dir);
731443c15812032991c98b33b5424b17bcd55fe3575plougher					return NULL;
732443c15812032991c98b33b5424b17bcd55fe3575plougher				}
733443c15812032991c98b33b5424b17bcd55fe3575plougher				dir->dirs = new_dir;
734443c15812032991c98b33b5424b17bcd55fe3575plougher			}
735443c15812032991c98b33b5424b17bcd55fe3575plougher			strcpy(dir->dirs[dir->dir_count].name, dire->name);
736443c15812032991c98b33b5424b17bcd55fe3575plougher			dir->dirs[dir->dir_count].start_block = dirh.start_block;
737443c15812032991c98b33b5424b17bcd55fe3575plougher			dir->dirs[dir->dir_count].offset = dire->offset;
738443c15812032991c98b33b5424b17bcd55fe3575plougher			dir->dirs[dir->dir_count].type = dire->type;
739443c15812032991c98b33b5424b17bcd55fe3575plougher			dir->dir_count ++;
740443c15812032991c98b33b5424b17bcd55fe3575plougher			bytes += dire->size + 1;
741443c15812032991c98b33b5424b17bcd55fe3575plougher		}
742443c15812032991c98b33b5424b17bcd55fe3575plougher	}
743443c15812032991c98b33b5424b17bcd55fe3575plougher
744443c15812032991c98b33b5424b17bcd55fe3575plougher	return dir;
745443c15812032991c98b33b5424b17bcd55fe3575plougher}
746443c15812032991c98b33b5424b17bcd55fe3575plougher
747443c15812032991c98b33b5424b17bcd55fe3575plougher
748443c15812032991c98b33b5424b17bcd55fe3575plougherint squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block, unsigned int *offset, unsigned int *type)
749443c15812032991c98b33b5424b17bcd55fe3575plougher{
750443c15812032991c98b33b5424b17bcd55fe3575plougher	if(dir->cur_entry == dir->dir_count)
751443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
752443c15812032991c98b33b5424b17bcd55fe3575plougher
753443c15812032991c98b33b5424b17bcd55fe3575plougher	*name = dir->dirs[dir->cur_entry].name;
754443c15812032991c98b33b5424b17bcd55fe3575plougher	*start_block = dir->dirs[dir->cur_entry].start_block;
755443c15812032991c98b33b5424b17bcd55fe3575plougher	*offset = dir->dirs[dir->cur_entry].offset;
756443c15812032991c98b33b5424b17bcd55fe3575plougher	*type = dir->dirs[dir->cur_entry].type;
757443c15812032991c98b33b5424b17bcd55fe3575plougher	dir->cur_entry ++;
758443c15812032991c98b33b5424b17bcd55fe3575plougher
759443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
760443c15812032991c98b33b5424b17bcd55fe3575plougher}
761443c15812032991c98b33b5424b17bcd55fe3575plougher
762443c15812032991c98b33b5424b17bcd55fe3575plougher
763443c15812032991c98b33b5424b17bcd55fe3575ploughervoid squashfs_closedir(struct dir *dir)
764443c15812032991c98b33b5424b17bcd55fe3575plougher{
765443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir->dirs);
766443c15812032991c98b33b5424b17bcd55fe3575plougher	free(dir);
767443c15812032991c98b33b5424b17bcd55fe3575plougher}
768443c15812032991c98b33b5424b17bcd55fe3575plougher
769443c15812032991c98b33b5424b17bcd55fe3575plougher
770b54566f5c433764830c29c83151691d0034de094plougherchar *get_component(char *target, char *targname)
771b54566f5c433764830c29c83151691d0034de094plougher{
772b54566f5c433764830c29c83151691d0034de094plougher	while(*target == '/')
773b54566f5c433764830c29c83151691d0034de094plougher		*target ++;
774b54566f5c433764830c29c83151691d0034de094plougher
775b54566f5c433764830c29c83151691d0034de094plougher	while(*target != '/' && *target!= '\0')
776b54566f5c433764830c29c83151691d0034de094plougher		*targname ++ = *target ++;
777b54566f5c433764830c29c83151691d0034de094plougher
778b54566f5c433764830c29c83151691d0034de094plougher	*targname = '\0';
779b54566f5c433764830c29c83151691d0034de094plougher
780b54566f5c433764830c29c83151691d0034de094plougher	return target;
781b54566f5c433764830c29c83151691d0034de094plougher}
782b54566f5c433764830c29c83151691d0034de094plougher
783b54566f5c433764830c29c83151691d0034de094plougher
784b54566f5c433764830c29c83151691d0034de094plougherint matches(char *targname, char *name)
785b54566f5c433764830c29c83151691d0034de094plougher{
786b54566f5c433764830c29c83151691d0034de094plougher	if(*targname == '\0' || strcmp(targname, name) == 0)
787b54566f5c433764830c29c83151691d0034de094plougher		return TRUE;
788b54566f5c433764830c29c83151691d0034de094plougher
789b54566f5c433764830c29c83151691d0034de094plougher	return FALSE;
790b54566f5c433764830c29c83151691d0034de094plougher}
791b54566f5c433764830c29c83151691d0034de094plougher
792b54566f5c433764830c29c83151691d0034de094plougher
793b54566f5c433764830c29c83151691d0034de094plougherint dir_scan(char *parent_name, unsigned int start_block, unsigned int offset, squashfs_super_block *sBlk, char *target)
794443c15812032991c98b33b5424b17bcd55fe3575plougher{
795443c15812032991c98b33b5424b17bcd55fe3575plougher	struct dir *dir = squashfs_openddir(start_block, offset, sBlk);
796443c15812032991c98b33b5424b17bcd55fe3575plougher	unsigned int type;
797443c15812032991c98b33b5424b17bcd55fe3575plougher	char *name, pathname[1024];
798b54566f5c433764830c29c83151691d0034de094plougher	char targname[1024];
799b54566f5c433764830c29c83151691d0034de094plougher
800b54566f5c433764830c29c83151691d0034de094plougher	target = get_component(target, targname);
801443c15812032991c98b33b5424b17bcd55fe3575plougher
802443c15812032991c98b33b5424b17bcd55fe3575plougher	if(dir == NULL) {
803fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher		ERROR("dir_scan: Failed to read directory %s (%x:%x)\n", parent_name, start_block, offset);
804443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
805443c15812032991c98b33b5424b17bcd55fe3575plougher	}
806443c15812032991c98b33b5424b17bcd55fe3575plougher
807443c15812032991c98b33b5424b17bcd55fe3575plougher	if(!lsonly && mkdir(parent_name, (mode_t) dir->mode) == -1) {
808443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("dir_scan: failed to open directory %s, because %s\n", parent_name, strerror(errno));
809443c15812032991c98b33b5424b17bcd55fe3575plougher		return FALSE;
810443c15812032991c98b33b5424b17bcd55fe3575plougher	}
811443c15812032991c98b33b5424b17bcd55fe3575plougher
812443c15812032991c98b33b5424b17bcd55fe3575plougher	while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) {
813fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher		TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type);
814443c15812032991c98b33b5424b17bcd55fe3575plougher
815b54566f5c433764830c29c83151691d0034de094plougher
816b54566f5c433764830c29c83151691d0034de094plougher		if(!matches(targname, name))
817b54566f5c433764830c29c83151691d0034de094plougher			continue;
818b54566f5c433764830c29c83151691d0034de094plougher
819443c15812032991c98b33b5424b17bcd55fe3575plougher		strcat(strcat(strcpy(pathname, parent_name), "/"), name);
820fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
821443c15812032991c98b33b5424b17bcd55fe3575plougher		if(lsonly || info)
822443c15812032991c98b33b5424b17bcd55fe3575plougher			printf("%s\n", pathname);
823fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher
824443c15812032991c98b33b5424b17bcd55fe3575plougher		if(type == SQUASHFS_DIR_TYPE)
825b54566f5c433764830c29c83151691d0034de094plougher			dir_scan(pathname, start_block, offset, sBlk, target);
826443c15812032991c98b33b5424b17bcd55fe3575plougher		else
827443c15812032991c98b33b5424b17bcd55fe3575plougher			if(!lsonly)
828443c15812032991c98b33b5424b17bcd55fe3575plougher				create_inode(pathname, start_block, offset, sBlk);
829443c15812032991c98b33b5424b17bcd55fe3575plougher	}
830443c15812032991c98b33b5424b17bcd55fe3575plougher
831443c15812032991c98b33b5424b17bcd55fe3575plougher	!lsonly && set_attributes(parent_name, dir->mode, dir->uid, dir->guid, dir->mtime, TRUE);
832443c15812032991c98b33b5424b17bcd55fe3575plougher
833443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_closedir(dir);
834443c15812032991c98b33b5424b17bcd55fe3575plougher	dir_count ++;
835443c15812032991c98b33b5424b17bcd55fe3575plougher
836443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
837443c15812032991c98b33b5424b17bcd55fe3575plougher}
838443c15812032991c98b33b5424b17bcd55fe3575plougher
839443c15812032991c98b33b5424b17bcd55fe3575plougher
840443c15812032991c98b33b5424b17bcd55fe3575plougherint read_super(squashfs_super_block *sBlk, char *source)
841443c15812032991c98b33b5424b17bcd55fe3575plougher{
842443c15812032991c98b33b5424b17bcd55fe3575plougher	read_bytes(SQUASHFS_START, sizeof(squashfs_super_block), (char *) sBlk);
843443c15812032991c98b33b5424b17bcd55fe3575plougher
844443c15812032991c98b33b5424b17bcd55fe3575plougher	/* Check it is a SQUASHFS superblock */
845443c15812032991c98b33b5424b17bcd55fe3575plougher	swap = 0;
846443c15812032991c98b33b5424b17bcd55fe3575plougher	if(sBlk->s_magic != SQUASHFS_MAGIC) {
847443c15812032991c98b33b5424b17bcd55fe3575plougher		if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) {
848443c15812032991c98b33b5424b17bcd55fe3575plougher			squashfs_super_block sblk;
849443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("Reading a different endian SQUASHFS filesystem on %s\n", source);
850443c15812032991c98b33b5424b17bcd55fe3575plougher			SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk);
851443c15812032991c98b33b5424b17bcd55fe3575plougher			memcpy(sBlk, &sblk, sizeof(squashfs_super_block));
852443c15812032991c98b33b5424b17bcd55fe3575plougher			swap = 1;
853443c15812032991c98b33b5424b17bcd55fe3575plougher		} else  {
854443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("Can't find a SQUASHFS superblock on %s\n", source);
855443c15812032991c98b33b5424b17bcd55fe3575plougher			goto failed_mount;
856443c15812032991c98b33b5424b17bcd55fe3575plougher		}
857443c15812032991c98b33b5424b17bcd55fe3575plougher	}
858443c15812032991c98b33b5424b17bcd55fe3575plougher
859443c15812032991c98b33b5424b17bcd55fe3575plougher	/* Check the MAJOR & MINOR versions */
860443c15812032991c98b33b5424b17bcd55fe3575plougher	if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) {
861443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("Major/Minor mismatch, filesystem on %s is (%d:%d)\n",
862443c15812032991c98b33b5424b17bcd55fe3575plougher				source, sBlk->s_major, sBlk->s_minor);
8639b5bf8c73c0eaf4f1ba0461615f4ed0d405a30ccplougher		ERROR("I only support Squashfs 3.0 filesystems!  Later releases will support older Squashfs filesystems\n");
864443c15812032991c98b33b5424b17bcd55fe3575plougher		goto failed_mount;
865443c15812032991c98b33b5424b17bcd55fe3575plougher	}
866443c15812032991c98b33b5424b17bcd55fe3575plougher
867443c15812032991c98b33b5424b17bcd55fe3575plougher#if __BYTE_ORDER == __BIG_ENDIAN
868443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("Found a valid %s endian SQUASHFS superblock on %s.\n", swap ? "little" : "big", source);
869443c15812032991c98b33b5424b17bcd55fe3575plougher#else
870443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("Found a valid %s endian SQUASHFS superblock on %s.\n", swap ? "big" : "little", source);
871443c15812032991c98b33b5424b17bcd55fe3575plougher#endif
872443c15812032991c98b33b5424b17bcd55fe3575plougher
873443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tInodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : "");
874443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tData is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : "");
875443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tFragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : "");
876443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tCheck data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not");
877443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tFragments are %s present in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not" : "");
878443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tAlways_use_fragments option is %s specified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not");
879443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tDuplicates are %s removed\n", SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not");
880443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk->bytes_used / 1024.0, sBlk->bytes_used / (1024.0 * 1024.0));
881443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tBlock size %d\n", sBlk->block_size);
882443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tNumber of fragments %d\n", sBlk->fragments);
883443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tNumber of inodes %d\n", sBlk->inodes);
884443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tNumber of uids %d\n", sBlk->no_uids);
885443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\tNumber of gids %d\n", sBlk->no_guids);
886fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("sBlk->inode_table_start 0x%llx\n", sBlk->inode_table_start);
887fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("sBlk->directory_table_start 0x%llx\n", sBlk->directory_table_start);
888fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("sBlk->uid_start 0x%llx\n", sBlk->uid_start);
889fe3ca0609d02d78bcd11637c1220b2ff428f466aplougher	TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk->fragment_table_start);
890443c15812032991c98b33b5424b17bcd55fe3575plougher	TRACE("\n");
891443c15812032991c98b33b5424b17bcd55fe3575plougher
892443c15812032991c98b33b5424b17bcd55fe3575plougher	return TRUE;
893443c15812032991c98b33b5424b17bcd55fe3575plougher
894443c15812032991c98b33b5424b17bcd55fe3575plougherfailed_mount:
895443c15812032991c98b33b5424b17bcd55fe3575plougher	return FALSE;
896443c15812032991c98b33b5424b17bcd55fe3575plougher}
897443c15812032991c98b33b5424b17bcd55fe3575plougher
898443c15812032991c98b33b5424b17bcd55fe3575plougher
899443c15812032991c98b33b5424b17bcd55fe3575plougher#define VERSION() \
900b54566f5c433764830c29c83151691d0034de094plougher	printf("unsquashfs version 1.1 (2006/07/09)\n");\
9019b5bf8c73c0eaf4f1ba0461615f4ed0d405a30ccplougher	printf("copyright (C) 2006 Phillip Lougher <phillip@lougher.org.uk>\n\n"); \
902443c15812032991c98b33b5424b17bcd55fe3575plougher    	printf("This program is free software; you can redistribute it and/or\n");\
903443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("modify it under the terms of the GNU General Public License\n");\
904443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("as published by the Free Software Foundation; either version 2,\n");\
905443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("or (at your option) any later version.\n\n");\
906443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("This program is distributed in the hope that it will be useful,\n");\
907443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\
908443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");\
909443c15812032991c98b33b5424b17bcd55fe3575plougher	printf("GNU General Public License for more details.\n");
910443c15812032991c98b33b5424b17bcd55fe3575plougherint main(int argc, char *argv[])
911443c15812032991c98b33b5424b17bcd55fe3575plougher{
912443c15812032991c98b33b5424b17bcd55fe3575plougher	squashfs_super_block sBlk;
913443c15812032991c98b33b5424b17bcd55fe3575plougher	char *dest = "squashfs-root";
914443c15812032991c98b33b5424b17bcd55fe3575plougher	int i, version = FALSE;
915b54566f5c433764830c29c83151691d0034de094plougher	char *target = "";
916443c15812032991c98b33b5424b17bcd55fe3575plougher
917443c15812032991c98b33b5424b17bcd55fe3575plougher	for(i = 1; i < argc; i++) {
918443c15812032991c98b33b5424b17bcd55fe3575plougher		if(*argv[i] != '-')
919443c15812032991c98b33b5424b17bcd55fe3575plougher			break;
920443c15812032991c98b33b5424b17bcd55fe3575plougher		if(strcmp(argv[i], "-version") == 0) {
921443c15812032991c98b33b5424b17bcd55fe3575plougher			VERSION();
922443c15812032991c98b33b5424b17bcd55fe3575plougher			version = TRUE;
923443c15812032991c98b33b5424b17bcd55fe3575plougher		} else if(strcmp(argv[i], "-info") == 0)
924443c15812032991c98b33b5424b17bcd55fe3575plougher			info = TRUE;
925443c15812032991c98b33b5424b17bcd55fe3575plougher		else if(strcmp(argv[i], "-ls") == 0)
926443c15812032991c98b33b5424b17bcd55fe3575plougher			lsonly = TRUE;
927443c15812032991c98b33b5424b17bcd55fe3575plougher		else if(strcmp(argv[i], "-dest") == 0) {
928443c15812032991c98b33b5424b17bcd55fe3575plougher			if(++i == argc)
929443c15812032991c98b33b5424b17bcd55fe3575plougher				goto options;
930443c15812032991c98b33b5424b17bcd55fe3575plougher			dest = argv[i];
931443c15812032991c98b33b5424b17bcd55fe3575plougher		}
932443c15812032991c98b33b5424b17bcd55fe3575plougher	}
933443c15812032991c98b33b5424b17bcd55fe3575plougher
934443c15812032991c98b33b5424b17bcd55fe3575plougher	if(i == argc) {
935443c15812032991c98b33b5424b17bcd55fe3575plougher		if(!version) {
936443c15812032991c98b33b5424b17bcd55fe3575plougheroptions:
937b54566f5c433764830c29c83151691d0034de094plougher			ERROR("SYNTAX: %s [-ls | -dest] filesystem [directory or filename to be extracted]\n", argv[0]);
938443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("\t-version\t\tprint version, licence and copyright information\n");
939443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("\t-info\t\t\tprint files as they are unsquashed\n");
940443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("\t-ls\t\t\tlist filesystem only\n");
941443c15812032991c98b33b5424b17bcd55fe3575plougher			ERROR("\t-dest <pathname>\tunsquash to <pathname>, default \"squashfs-root\"\n");
942443c15812032991c98b33b5424b17bcd55fe3575plougher		}
943443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
944443c15812032991c98b33b5424b17bcd55fe3575plougher	}
945443c15812032991c98b33b5424b17bcd55fe3575plougher
946b54566f5c433764830c29c83151691d0034de094plougher	if((i + 1) < argc)
947b54566f5c433764830c29c83151691d0034de094plougher		target = argv[i + 1];
948b54566f5c433764830c29c83151691d0034de094plougher
949443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fd = open(argv[i], O_RDONLY)) == -1) {
950443c15812032991c98b33b5424b17bcd55fe3575plougher		ERROR("Could not open %s, because %s\n", argv[i], strerror(errno));
951443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
952443c15812032991c98b33b5424b17bcd55fe3575plougher	}
953443c15812032991c98b33b5424b17bcd55fe3575plougher
954443c15812032991c98b33b5424b17bcd55fe3575plougher	if(read_super(&sBlk, argv[i]) == FALSE)
955443c15812032991c98b33b5424b17bcd55fe3575plougher		exit(1);
956443c15812032991c98b33b5424b17bcd55fe3575plougher
957443c15812032991c98b33b5424b17bcd55fe3575plougher	block_size = sBlk.block_size;
958443c15812032991c98b33b5424b17bcd55fe3575plougher	if((fragment_data = malloc(block_size)) == NULL)
959443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate fragment_data\n");
960443c15812032991c98b33b5424b17bcd55fe3575plougher
961443c15812032991c98b33b5424b17bcd55fe3575plougher	if((file_data = malloc(block_size)) == NULL)
962443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate file_data");
963443c15812032991c98b33b5424b17bcd55fe3575plougher
964443c15812032991c98b33b5424b17bcd55fe3575plougher	if((data = malloc(block_size)) == NULL)
965443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate datan\n");
966443c15812032991c98b33b5424b17bcd55fe3575plougher
967443c15812032991c98b33b5424b17bcd55fe3575plougher	if((created_inode = malloc(sBlk.inodes * sizeof(char *))) == NULL)
968443c15812032991c98b33b5424b17bcd55fe3575plougher		EXIT_UNSQUASH("failed to allocate created_inode\n");
969443c15812032991c98b33b5424b17bcd55fe3575plougher
970443c15812032991c98b33b5424b17bcd55fe3575plougher	memset(created_inode, 0, sBlk.inodes * sizeof(char *));
971443c15812032991c98b33b5424b17bcd55fe3575plougher
972443c15812032991c98b33b5424b17bcd55fe3575plougher	read_uids_guids(&sBlk);
973443c15812032991c98b33b5424b17bcd55fe3575plougher	read_fragment_table(&sBlk);
974443c15812032991c98b33b5424b17bcd55fe3575plougher	uncompress_inode_table(sBlk.inode_table_start, sBlk.directory_table_start, &sBlk);
975443c15812032991c98b33b5424b17bcd55fe3575plougher	uncompress_directory_table(sBlk.directory_table_start, sBlk.fragment_table_start, &sBlk);
976443c15812032991c98b33b5424b17bcd55fe3575plougher
977b54566f5c433764830c29c83151691d0034de094plougher	dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode), SQUASHFS_INODE_OFFSET(sBlk.root_inode), &sBlk, target);
978443c15812032991c98b33b5424b17bcd55fe3575plougher
979443c15812032991c98b33b5424b17bcd55fe3575plougher	if(!lsonly) {
980443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("\n");
981443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d files\n", file_count);
982443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d directories\n", dir_count);
983443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d symlinks\n", sym_count);
984443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d devices\n", dev_count);
985443c15812032991c98b33b5424b17bcd55fe3575plougher		printf("created %d fifos\n", fifo_count);
986443c15812032991c98b33b5424b17bcd55fe3575plougher	}
987443c15812032991c98b33b5424b17bcd55fe3575plougher
988443c15812032991c98b33b5424b17bcd55fe3575plougher}
989