1/*
2 * Read a squashfs filesystem.  This is a highly compressed read only filesystem.
3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
5 * Phillip Lougher <phillip@lougher.org.uk>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * read_fs.c
22 */
23
24extern void read_bytes(int, long long, int, char *);
25extern int add_file(long long, long long, long long, unsigned int *, int, unsigned int, int, int);
26
27#define TRUE 1
28#define FALSE 0
29#include <stdio.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <fcntl.h>
33#include <errno.h>
34#include <string.h>
35#include <zlib.h>
36#include <sys/mman.h>
37
38#ifndef linux
39#define __BYTE_ORDER BYTE_ORDER
40#define __BIG_ENDIAN BIG_ENDIAN
41#define __LITTLE_ENDIAN LITTLE_ENDIAN
42#else
43#include <endian.h>
44#endif
45
46#include <linux/squashfs_fs.h>
47#include "read_fs.h"
48#include "global.h"
49#include "LzmaDec.h"
50#include "sqlzma.h"
51#include <stdlib.h>
52
53#ifdef SQUASHFS_TRACE
54#define TRACE(s, args...)		do { \
55						printf("mksquashfs: "s, ## args); \
56					} while(0)
57#else
58#define TRACE(s, args...)
59#endif
60
61#define ERROR(s, args...)		do { \
62						fprintf(stderr, s, ## args); \
63					} while(0)
64
65int swap;
66extern int lzma;
67
68int read_block(int fd, long long start, long long *next, unsigned char *block, squashfs_super_block *sBlk)
69{
70	unsigned short c_byte;
71	int offset = 2;
72
73	if(swap) {
74		read_bytes(fd, start, 2, (char *) block);
75		((unsigned char *) &c_byte)[1] = block[0];
76		((unsigned char *) &c_byte)[0] = block[1];
77	} else
78		read_bytes(fd, start, 2, (char *)&c_byte);
79
80	if(SQUASHFS_CHECK_DATA(sBlk->flags))
81		offset = 3;
82	if(SQUASHFS_COMPRESSED(c_byte)) {
83		char buffer[SQUASHFS_METADATA_SIZE];
84		int res;
85		unsigned long bytes = SQUASHFS_METADATA_SIZE;
86
87		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
88		read_bytes(fd, start + offset, c_byte, buffer);
89
90		if(!lzma) {
91			if((res = uncompress(block, &bytes, (const unsigned char *) buffer, c_byte)) != Z_OK) {
92				if(res == Z_MEM_ERROR)
93					ERROR("zlib::uncompress failed, not enough memory\n");
94				else if(res == Z_BUF_ERROR)
95					ERROR("zlib::uncompress failed, not enough room in output buffer\n");
96				else
97					ERROR("zlib::uncompress failed, unknown error %d\n", res);
98				return 0;
99			}
100		}
101		/* lzma */
102		else {
103			if((res = LzmaUncompress(block, &bytes, buffer, c_byte)) != SZ_OK)
104				ERROR("LzmaUncompress: error (%d)\n", res);
105		}
106		if(next)
107			*next = start + offset + c_byte;
108		return bytes;
109	} else {
110		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
111		read_bytes(fd, start + offset, c_byte, (char *) block);
112		if(next)
113			*next = start + offset + c_byte;
114		return c_byte;
115	}
116}
117
118
119int scan_inode_table(int fd, long long start, long long end, long long root_inode_start, int root_inode_offset,
120		squashfs_super_block *sBlk,
121		squashfs_inode_header *dir_inode, unsigned char **inode_table, unsigned int *root_inode_block,
122		unsigned int *root_inode_size, long long *uncompressed_file, unsigned int *uncompressed_directory,
123		int *file_count, int *sym_count, int *dev_count, int *dir_count, int *fifo_count, int *sock_count)
124{
125	unsigned char *cur_ptr;
126	int byte, bytes = 0, size = 0, files = 0;
127	squashfs_reg_inode_header inode;
128	unsigned int directory_start_block;
129
130	TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start 0x%llx\n", start, end, root_inode_start);
131	while(start < end) {
132		if(start == root_inode_start) {
133			TRACE("scan_inode_table: read compressed block 0x%llx containing root inode\n", start);
134			*root_inode_block = bytes;
135		}
136		if((size - bytes < SQUASHFS_METADATA_SIZE) &&
137				((*inode_table = realloc(*inode_table, size += SQUASHFS_METADATA_SIZE)) == NULL))
138			return FALSE;
139		TRACE("scan_inode_table: reading block 0x%llx\n", start);
140		if((byte = read_block(fd, start, &start, *inode_table + bytes, sBlk)) == 0) {
141			free(*inode_table);
142			return FALSE;
143		}
144		bytes += byte;
145	}
146
147	/*
148	 * Read last inode entry which is the root directory inode, and obtain the last
149	 * directory start block index.  This is used when calculating the total uncompressed
150	 * directory size.  The directory bytes in the last block will be counted as normal.
151	 *
152	 * The root inode is ignored in the inode scan.  This ensures there is
153	 * always enough bytes left to read a regular file inode entry
154	 */
155	*root_inode_size = bytes - (*root_inode_block + root_inode_offset);
156	bytes = *root_inode_block + root_inode_offset;
157	if(swap) {
158		squashfs_base_inode_header sinode;
159		memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->base));
160		SQUASHFS_SWAP_BASE_INODE_HEADER(&dir_inode->base, &sinode, sizeof(squashfs_base_inode_header));
161	} else
162		memcpy(&dir_inode->base, *inode_table + bytes, sizeof(dir_inode->base));
163	if(dir_inode->base.inode_type == SQUASHFS_DIR_TYPE) {
164		if(swap) {
165			squashfs_dir_inode_header sinode;
166			memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->dir));
167			SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode->dir, &sinode);
168		} else
169			memcpy(&dir_inode->dir, *inode_table + bytes, sizeof(dir_inode->dir));
170		directory_start_block = dir_inode->dir.start_block;
171	} else {
172		if(swap) {
173			squashfs_ldir_inode_header sinode;
174			memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->ldir));
175			SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode->ldir, &sinode);
176		} else
177			memcpy(&dir_inode->ldir, *inode_table + bytes, sizeof(dir_inode->ldir));
178		directory_start_block = dir_inode->ldir.start_block;
179	}
180
181	for(cur_ptr = *inode_table; cur_ptr < *inode_table + bytes; files ++) {
182		if(swap) {
183			squashfs_reg_inode_header sinode;
184			memcpy(&sinode, cur_ptr, sizeof(inode));
185			SQUASHFS_SWAP_REG_INODE_HEADER(&inode, &sinode);
186		} else
187			memcpy(&inode, cur_ptr, sizeof(inode));
188
189		TRACE("scan_inode_table: processing inode @ byte position 0x%x, type 0x%x\n", cur_ptr - *inode_table,
190				inode.inode_type);
191		switch(inode.inode_type) {
192			case SQUASHFS_FILE_TYPE: {
193				int frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ? 0 : inode.file_size % sBlk->block_size;
194				int blocks = inode.fragment == SQUASHFS_INVALID_FRAG ? (inode.file_size
195					+ sBlk->block_size - 1) >> sBlk->block_log : inode.file_size >>
196					sBlk->block_log;
197				long long file_bytes = 0;
198				int i;
199				long long start = inode.start_block;
200				unsigned int *block_list;
201
202				TRACE("scan_inode_table: regular file, file_size %lld, blocks %d\n", inode.file_size, blocks);
203
204				if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) {
205					ERROR("Out of memory in block list malloc\n");
206					goto failed;
207				}
208
209				cur_ptr += sizeof(inode);
210				if(swap) {
211					unsigned int sblock_list[blocks];
212					memcpy(sblock_list, cur_ptr, blocks * sizeof(unsigned int));
213					SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks);
214				} else
215					memcpy(block_list, cur_ptr, blocks * sizeof(unsigned int));
216
217				*uncompressed_file += inode.file_size;
218				(*file_count) ++;
219
220				for(i = 0; i < blocks; i++)
221					file_bytes += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
222
223	                        add_file(start, inode.file_size, file_bytes, block_list, blocks, inode.fragment, inode.offset, frag_bytes);
224				cur_ptr += blocks * sizeof(unsigned int);
225				break;
226			}
227			case SQUASHFS_LREG_TYPE: {
228				squashfs_lreg_inode_header inode;
229				int frag_bytes;
230				int blocks;
231				long long file_bytes = 0;
232				int i;
233				long long start;
234				unsigned int *block_list;
235
236				if(swap) {
237					squashfs_lreg_inode_header sinodep;
238					memcpy(&sinodep, cur_ptr, sizeof(sinodep));
239					SQUASHFS_SWAP_LREG_INODE_HEADER(&inode, &sinodep);
240				} else
241					memcpy(&inode, cur_ptr, sizeof(inode));
242
243				TRACE("scan_inode_table: extended regular file, file_size %lld, blocks %d\n", inode.file_size, blocks);
244
245				cur_ptr += sizeof(inode);
246				frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ? 0 : inode.file_size % sBlk->block_size;
247				blocks = inode.fragment == SQUASHFS_INVALID_FRAG ? (inode.file_size
248					+ sBlk->block_size - 1) >> sBlk->block_log : inode.file_size >>
249					sBlk->block_log;
250				start = inode.start_block;
251
252				if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) {
253					ERROR("Out of memory in block list malloc\n");
254					goto failed;
255				}
256
257				if(swap) {
258					unsigned int sblock_list[blocks];
259					memcpy(sblock_list, cur_ptr, blocks * sizeof(unsigned int));
260					SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks);
261				} else
262					memcpy(block_list, cur_ptr, blocks * sizeof(unsigned int));
263
264				*uncompressed_file += inode.file_size;
265				(*file_count) ++;
266
267				for(i = 0; i < blocks; i++)
268					file_bytes += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]);
269
270	                        add_file(start, inode.file_size, file_bytes, block_list, blocks, inode.fragment, inode.offset, frag_bytes);
271				cur_ptr += blocks * sizeof(unsigned int);
272				break;
273			}
274			case SQUASHFS_SYMLINK_TYPE: {
275				squashfs_symlink_inode_header inodep;
276
277				if(swap) {
278					squashfs_symlink_inode_header sinodep;
279					memcpy(&sinodep, cur_ptr, sizeof(sinodep));
280					SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inodep, &sinodep);
281				} else
282					memcpy(&inodep, cur_ptr, sizeof(inodep));
283				(*sym_count) ++;
284				cur_ptr += sizeof(inodep) + inodep.symlink_size;
285				break;
286			}
287			case SQUASHFS_DIR_TYPE: {
288				squashfs_dir_inode_header dir_inode;
289
290				if(swap) {
291					squashfs_dir_inode_header sinode;
292					memcpy(&sinode, cur_ptr, sizeof(dir_inode));
293					SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode, &sinode);
294				} else
295					memcpy(&dir_inode, cur_ptr, sizeof(dir_inode));
296				if(dir_inode.start_block < directory_start_block)
297					*uncompressed_directory += dir_inode.file_size;
298				(*dir_count) ++;
299				cur_ptr += sizeof(squashfs_dir_inode_header);
300				break;
301			}
302			case SQUASHFS_LDIR_TYPE: {
303				squashfs_ldir_inode_header dir_inode;
304				int i;
305
306				if(swap) {
307					squashfs_ldir_inode_header sinode;
308					memcpy(&sinode, cur_ptr, sizeof(dir_inode));
309					SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode, &sinode);
310				} else
311					memcpy(&dir_inode, cur_ptr, sizeof(dir_inode));
312				if(dir_inode.start_block < directory_start_block)
313					*uncompressed_directory += dir_inode.file_size;
314				(*dir_count) ++;
315				cur_ptr += sizeof(squashfs_ldir_inode_header);
316				for(i = 0; i < dir_inode.i_count; i++) {
317					squashfs_dir_index index;
318					if(swap) {
319						squashfs_dir_index sindex;
320						memcpy(&sindex, cur_ptr, sizeof(squashfs_dir_index));
321						SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
322					} else
323						memcpy(&index, cur_ptr, sizeof(squashfs_dir_index));
324					cur_ptr += sizeof(squashfs_dir_index) + index.size + 1;
325				}
326				break;
327			}
328		 	case SQUASHFS_BLKDEV_TYPE:
329		 	case SQUASHFS_CHRDEV_TYPE:
330				(*dev_count) ++;
331				cur_ptr += sizeof(squashfs_dev_inode_header);
332				break;
333
334			case SQUASHFS_FIFO_TYPE:
335				(*fifo_count) ++;
336				cur_ptr += sizeof(squashfs_ipc_inode_header);
337				break;
338			case SQUASHFS_SOCKET_TYPE:
339				(*sock_count) ++;
340				cur_ptr += sizeof(squashfs_ipc_inode_header);
341				break;
342		 	default:
343				ERROR("Unknown inode type %d in scan_inode_table!\n", inode.inode_type);
344				goto failed;
345		}
346	}
347
348	return files;
349
350
351failed:
352	free(*inode_table);
353	return FALSE;
354}
355
356
357int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source)
358{
359	squashfs_super_block sblk;
360
361	read_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block), (char *) sBlk);
362
363	/* Check it is a SQUASHFS superblock */
364	swap = 0;
365	switch (sBlk->s_magic) {
366	case SQUASHFS_MAGIC_LZMA:
367		if (!lzma)
368			goto bad;
369		break;
370	case SQUASHFS_MAGIC:
371		break;
372	case SQUASHFS_MAGIC_SWAP:
373	case SQUASHFS_MAGIC_LZMA_SWAP:
374		ERROR("Reading a different endian SQUASHFS filesystem on %s - ignoring -le/-be options\n", source);
375		SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk);
376		memcpy(sBlk, &sblk, sizeof(squashfs_super_block));
377		swap = 1;
378		break;
379	bad:
380	default:
381		ERROR("Can't find a SQUASHFS superblock on %s\n", source);
382		goto failed_mount;
383 	}
384
385	/* Check the MAJOR & MINOR versions */
386	if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) {
387		if(sBlk->s_major < 3)
388			ERROR("Filesystem on %s is a SQUASHFS %d.%d filesystem.  Appending\nto SQUASHFS %d.%d filesystems is not supported.  Please convert it to a SQUASHFS 3.0 filesystem\n", source, sBlk->s_major, sBlk->s_minor, sBlk->s_major, sBlk->s_minor);
389		else
390			ERROR("Major/Minor mismatch, filesystem on %s is %d.%d, I support 3.0\n",
391				source, sBlk->s_major, sBlk->s_minor);
392		goto failed_mount;
393	}
394
395#if __BYTE_ORDER == __BIG_ENDIAN
396	*be = !swap;
397#else
398	*be = swap;
399#endif
400
401	printf("Found a valid %s%s SQUASHFS superblock on %s.\n", SQUASHFS_EXPORTABLE(sBlk->flags) ? "exportable " : "", *be ? "big endian" : "little endian", source);
402	printf("\tInodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : "");
403	printf("\tData is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : "");
404	printf("\tFragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : "");
405	printf("\tCheck data is %spresent in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not ");
406	printf("\tFragments are %spresent in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not " : "");
407	printf("\tAlways_use_fragments option is %sspecified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not ");
408	printf("\tDuplicates are %sremoved\n", SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not ");
409	printf("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk->bytes_used / 1024.0, sBlk->bytes_used / (1024.0 * 1024.0));
410	printf("\tBlock size %d\n", sBlk->block_size);
411	printf("\tNumber of fragments %d\n", sBlk->fragments);
412	printf("\tNumber of inodes %d\n", sBlk->inodes);
413	printf("\tNumber of uids %d\n", sBlk->no_uids);
414	printf("\tNumber of gids %d\n", sBlk->no_guids);
415	TRACE("sBlk->inode_table_start %llx\n", sBlk->inode_table_start);
416	TRACE("sBlk->directory_table_start %llx\n", sBlk->directory_table_start);
417	TRACE("sBlk->uid_start %llx\n", sBlk->uid_start);
418	TRACE("sBlk->fragment_table_start %llx\n", sBlk->fragment_table_start);
419	TRACE("sBlk->lookup_table_start %xllx\n", sBlk->lookup_table_start);
420	printf("\n");
421
422	return TRUE;
423
424failed_mount:
425	return FALSE;
426}
427
428
429unsigned char *squashfs_readdir(int fd, int root_entries, unsigned int directory_start_block, int offset, int size,
430		unsigned int *last_directory_block, squashfs_super_block *sBlk, void (push_directory_entry)(char *, squashfs_inode, int, int))
431{
432	squashfs_dir_header dirh;
433	char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
434	squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer;
435	unsigned char *directory_table = NULL;
436	int byte, bytes = 0, dir_count;
437	long long start = sBlk->directory_table_start + directory_start_block, last_start_block = -1;
438
439	size += offset;
440	if((directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) & ~(SQUASHFS_METADATA_SIZE - 1))) == NULL)
441		return NULL;
442	while(bytes < size) {
443		TRACE("squashfs_readdir: reading block 0x%llx, bytes read so far %d\n", start, bytes);
444		last_start_block = start;
445		if((byte = read_block(fd, start, &start, directory_table + bytes, sBlk)) == 0) {
446			free(directory_table);
447			return NULL;
448		}
449		bytes += byte;
450	}
451
452	if(!root_entries)
453		goto all_done;
454
455	bytes = offset;
456 	while(bytes < size) {
457		if(swap) {
458			squashfs_dir_header sdirh;
459			memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
460			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
461		} else
462			memcpy(&dirh, directory_table + bytes, sizeof(dirh));
463
464		dir_count = dirh.count + 1;
465		TRACE("squashfs_readdir: Read directory header @ byte position 0x%x, 0x%x directory entries\n", bytes, dir_count);
466		bytes += sizeof(dirh);
467
468		while(dir_count--) {
469			if(swap) {
470				squashfs_dir_entry sdire;
471				memcpy(&sdire, directory_table + bytes, sizeof(sdire));
472				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
473			} else
474				memcpy(dire, directory_table + bytes, sizeof(*dire));
475			bytes += sizeof(*dire);
476
477			memcpy(dire->name, directory_table + bytes, dire->size + 1);
478			dire->name[dire->size + 1] = '\0';
479			TRACE("squashfs_readdir: pushing directory entry %s, inode %x:%x, type 0x%x\n", dire->name, dirh.start_block, dire->offset, dire->type);
480			push_directory_entry(dire->name, SQUASHFS_MKINODE(dirh.start_block, dire->offset), dirh.inode_number + dire->inode_number, dire->type);
481			bytes += dire->size + 1;
482		}
483	}
484
485all_done:
486	*last_directory_block = (unsigned int) last_start_block - sBlk->directory_table_start;
487	return directory_table;
488}
489
490
491int read_fragment_table(int fd, squashfs_super_block *sBlk, squashfs_fragment_entry **fragment_table)
492{
493	int i, indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments);
494	squashfs_fragment_index fragment_table_index[indexes];
495
496	TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk->fragments, indexes, sBlk->fragment_table_start);
497	if(sBlk->fragments == 0)
498		return 1;
499
500	if((*fragment_table = (squashfs_fragment_entry *) malloc(sBlk->fragments * sizeof(squashfs_fragment_entry))) == NULL) {
501		ERROR("Failed to allocate fragment table\n");
502		return 0;
503	}
504
505	if(swap) {
506		squashfs_fragment_index sfragment_table_index[indexes];
507
508		read_bytes(fd, sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) sfragment_table_index);
509		SQUASHFS_SWAP_FRAGMENT_INDEXES(fragment_table_index, sfragment_table_index, indexes);
510	} else
511		read_bytes(fd, sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) fragment_table_index);
512
513	for(i = 0; i < indexes; i++) {
514		int length = read_block(fd, fragment_table_index[i], NULL, ((unsigned char *) *fragment_table) + (i * SQUASHFS_METADATA_SIZE), sBlk);
515		TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length);
516	}
517
518	if(swap) {
519		squashfs_fragment_entry sfragment;
520		for(i = 0; i < sBlk->fragments; i++) {
521			SQUASHFS_SWAP_FRAGMENT_ENTRY((&sfragment), (&(*fragment_table)[i]));
522			memcpy((char *) &(*fragment_table)[i], (char *) &sfragment, sizeof(squashfs_fragment_entry));
523		}
524	}
525
526	return 1;
527}
528
529
530int read_inode_lookup_table(int fd, squashfs_super_block *sBlk, squashfs_inode **inode_lookup_table)
531{
532	int lookup_bytes = SQUASHFS_LOOKUP_BYTES(sBlk->inodes);
533	int indexes = SQUASHFS_LOOKUP_BLOCKS(sBlk->inodes);
534	long long index[indexes];
535	int i;
536
537	if(sBlk->lookup_table_start == SQUASHFS_INVALID_BLK)
538		return 1;
539
540	if((*inode_lookup_table = malloc(lookup_bytes)) == NULL) {
541		ERROR("Failed to allocate inode lookup table\n");
542		return 0;
543	}
544
545	if(swap) {
546		long long sindex[indexes];
547
548		read_bytes(fd, sBlk->lookup_table_start, SQUASHFS_LOOKUP_BLOCK_BYTES(sBlk->inodes), (char *) sindex);
549		SQUASHFS_SWAP_FRAGMENT_INDEXES(index, sindex, indexes);
550	} else
551		read_bytes(fd, sBlk->lookup_table_start, SQUASHFS_LOOKUP_BLOCK_BYTES(sBlk->inodes), (char *) index);
552
553	for(i = 0; i <  indexes; i++) {
554		int length = read_block(fd, index[i], NULL, ((unsigned char *) *inode_lookup_table) + (i * SQUASHFS_METADATA_SIZE), sBlk);
555		TRACE("Read inode lookup table block %d, from 0x%llx, length %d\n", i, index[i], length);
556	}
557
558	if(swap) {
559		squashfs_inode_t sinode;
560		for(i = 0; i < sBlk->inodes; i++) {
561			SQUASHFS_SWAP_INODE_T((&sinode), (&(*inode_lookup_table)[i]));
562			memcpy((char *) &(*inode_lookup_table)[i], (char *) &sinode, sizeof(squashfs_inode_t));
563		}
564	}
565
566	return 1;
567}
568
569
570long long read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **cinode_table,
571		char **data_cache, char **cdirectory_table, char **directory_data_cache,
572		unsigned int *last_directory_block, unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size,
573		unsigned int *root_inode_size, unsigned int *inode_dir_start_block, int *file_count, int *sym_count,
574		int *dev_count, int *dir_count, int *fifo_count, int *sock_count, squashfs_uid *uids,
575		unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count,
576		long long *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
577		unsigned int *inode_dir_inode_number, unsigned int *inode_dir_parent_inode,
578		void (push_directory_entry)(char *, squashfs_inode, int, int), squashfs_fragment_entry **fragment_table,
579		squashfs_inode **inode_lookup_table)
580{
581	unsigned char *inode_table = NULL, *directory_table;
582	long long start = sBlk->inode_table_start, end = sBlk->directory_table_start, root_inode_start = start +
583		SQUASHFS_INODE_BLK(sBlk->root_inode);
584	unsigned int root_inode_offset = SQUASHFS_INODE_OFFSET(sBlk->root_inode), root_inode_block, files;
585	squashfs_inode_header inode;
586
587	printf("Scanning existing filesystem...\n");
588
589	if(read_fragment_table(fd, sBlk, fragment_table) == 0)
590		goto error;
591
592	if(read_inode_lookup_table(fd, sBlk, inode_lookup_table) == 0)
593		goto error;
594
595	if((files = scan_inode_table(fd, start, end, root_inode_start, root_inode_offset, sBlk, &inode, &inode_table,
596			&root_inode_block, root_inode_size, uncompressed_file, uncompressed_directory, file_count, sym_count,
597			dev_count, dir_count, fifo_count, sock_count)) == 0) {
598		ERROR("read_filesystem: inode table read failed\n");
599		goto error;
600	}
601
602	*uncompressed_inode = root_inode_block;
603
604	printf("Read existing filesystem, %d inodes scanned\n", files);
605
606	if(inode.base.inode_type == SQUASHFS_DIR_TYPE || inode.base.inode_type == SQUASHFS_LDIR_TYPE) {
607		if(inode.base.inode_type == SQUASHFS_DIR_TYPE) {
608			*inode_dir_start_block = inode.dir.start_block;
609			*inode_dir_offset = inode.dir.offset;
610			*inode_dir_file_size = inode.dir.file_size - 3;
611			*inode_dir_inode_number = inode.dir.inode_number;
612			*inode_dir_parent_inode = inode.dir.parent_inode;
613		} else {
614			*inode_dir_start_block = inode.ldir.start_block;
615			*inode_dir_offset = inode.ldir.offset;
616			*inode_dir_file_size = inode.ldir.file_size - 3;
617			*inode_dir_inode_number = inode.ldir.inode_number;
618			*inode_dir_parent_inode = inode.ldir.parent_inode;
619		}
620
621		if((directory_table = squashfs_readdir(fd, !root_name, *inode_dir_start_block, *inode_dir_offset,
622				*inode_dir_file_size, last_directory_block, sBlk, push_directory_entry)) == NULL) {
623			ERROR("read_filesystem: Could not read root directory\n");
624			goto error;
625		}
626
627		root_inode_start -= start;
628		if((*cinode_table = (char *) malloc(root_inode_start)) == NULL) {
629			ERROR("read_filesystem: failed to alloc space for existing filesystem inode table\n");
630			goto error;
631		}
632	       	read_bytes(fd, start, root_inode_start, *cinode_table);
633
634		if((*cdirectory_table = (char *) malloc(*last_directory_block)) == NULL) {
635			ERROR("read_filesystem: failed to alloc space for existing filesystem directory table\n");
636			goto error;
637		}
638		read_bytes(fd, sBlk->directory_table_start, *last_directory_block, *cdirectory_table);
639
640		if((*data_cache = (char *) malloc(root_inode_offset + *root_inode_size)) == NULL) {
641			ERROR("read_filesystem: failed to alloc inode cache\n");
642			goto error;
643		}
644		memcpy(*data_cache, inode_table + root_inode_block, root_inode_offset + *root_inode_size);
645
646		if((*directory_data_cache = (char *) malloc(*inode_dir_offset + *inode_dir_file_size)) == NULL) {
647			ERROR("read_filesystem: failed to alloc directory cache\n");
648			goto error;
649		}
650		memcpy(*directory_data_cache, directory_table, *inode_dir_offset + *inode_dir_file_size);
651
652		if(!swap)
653			read_bytes(fd, sBlk->uid_start, sBlk->no_uids * sizeof(squashfs_uid), (char *) uids);
654		else {
655			squashfs_uid uids_copy[sBlk->no_uids];
656
657			read_bytes(fd, sBlk->uid_start, sBlk->no_uids * sizeof(squashfs_uid), (char *) uids_copy);
658			SQUASHFS_SWAP_DATA(uids, uids_copy, sBlk->no_uids, sizeof(squashfs_uid) * 8);
659		}
660
661		if(!swap)
662			read_bytes(fd, sBlk->guid_start, sBlk->no_guids * sizeof(squashfs_uid), (char *) guids);
663		else {
664			squashfs_uid guids_copy[sBlk->no_guids];
665
666			read_bytes(fd, sBlk->guid_start, sBlk->no_guids * sizeof(squashfs_uid), (char *) guids_copy);
667			SQUASHFS_SWAP_DATA(guids, guids_copy, sBlk->no_guids, sizeof(squashfs_uid) * 8);
668		}
669		*uid_count = sBlk->no_uids;
670		*guid_count = sBlk->no_guids;
671
672		free(inode_table);
673		free(directory_table);
674		return sBlk->inode_table_start;
675	}
676
677error:
678	return 0;
679}
680