1/*
2 * Read a squashfs filesystem.  This is a highly compressed read only
3 * filesystem.
4 *
5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
6 * 2012, 2013, 2014
7 * Phillip Lougher <phillip@squashfs.org.uk>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2,
12 * or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 * read_fs.c
24 */
25
26#define TRUE 1
27#define FALSE 0
28#include <stdio.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <fcntl.h>
32#include <errno.h>
33#include <string.h>
34#include <sys/mman.h>
35#include <limits.h>
36#include <dirent.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 <stdlib.h>
47
48#include "squashfs_fs.h"
49#include "squashfs_swap.h"
50#include "compressor.h"
51#include "xattr.h"
52#include "error.h"
53#include "mksquashfs.h"
54
55int read_block(int fd, long long start, long long *next, int expected,
56								void *block)
57{
58	unsigned short c_byte;
59	int res, compressed;
60	int outlen = expected ? expected : SQUASHFS_METADATA_SIZE;
61
62	/* Read block size */
63	res = read_fs_bytes(fd, start, 2, &c_byte);
64	if(res == 0)
65		return 0;
66
67	SQUASHFS_INSWAP_SHORTS(&c_byte, 1);
68	compressed = SQUASHFS_COMPRESSED(c_byte);
69	c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
70
71	/*
72	 * The block size should not be larger than
73	 * the uncompressed size (or max uncompressed size if
74	 * expected is 0)
75	 */
76	if (c_byte > outlen)
77		return 0;
78
79	if(compressed) {
80		char buffer[c_byte];
81		int error;
82
83		res = read_fs_bytes(fd, start + 2, c_byte, buffer);
84		if(res == 0)
85			return 0;
86
87		res = compressor_uncompress(comp, block, buffer, c_byte,
88			outlen, &error);
89		if(res == -1) {
90			ERROR("%s uncompress failed with error code %d\n",
91				comp->name, error);
92			return 0;
93		}
94	} else {
95		res = read_fs_bytes(fd, start + 2, c_byte, block);
96		if(res == 0)
97			return 0;
98		res = c_byte;
99	}
100
101	if(next)
102		*next = start + 2 + c_byte;
103
104	/*
105	 * if expected, then check the (uncompressed) return data
106	 * is of the expected size
107	 */
108	if(expected && expected != res)
109		return 0;
110	else
111		return res;
112}
113
114
115#define NO_BYTES(SIZE) \
116	(bytes - (cur_ptr - *inode_table) < (SIZE))
117
118#define NO_INODE_BYTES(INODE) NO_BYTES(sizeof(struct INODE))
119
120int scan_inode_table(int fd, long long start, long long end,
121	long long root_inode_start, int root_inode_offset,
122	struct squashfs_super_block *sBlk, union squashfs_inode_header
123	*dir_inode, unsigned char **inode_table, unsigned int *root_inode_block,
124	unsigned int *root_inode_size, long long *uncompressed_file,
125	unsigned int *uncompressed_directory, int *file_count, int *sym_count,
126	int *dev_count, int *dir_count, int *fifo_count, int *sock_count,
127	unsigned int *id_table)
128{
129	unsigned char *cur_ptr;
130	int byte, files = 0;
131	unsigned int directory_start_block, bytes = 0, size = 0;
132	struct squashfs_base_inode_header base;
133
134	TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start "
135		"0x%llx\n", start, end, root_inode_start);
136
137	*root_inode_block = UINT_MAX;
138	while(start < end) {
139		if(start == root_inode_start) {
140			TRACE("scan_inode_table: read compressed block 0x%llx "
141				"containing root inode\n", start);
142			*root_inode_block = bytes;
143		}
144		if(size - bytes < SQUASHFS_METADATA_SIZE) {
145			*inode_table = realloc(*inode_table, size
146				+= SQUASHFS_METADATA_SIZE);
147			if(*inode_table == NULL)
148				MEM_ERROR();
149		}
150		TRACE("scan_inode_table: reading block 0x%llx\n", start);
151		byte = read_block(fd, start, &start, 0, *inode_table + bytes);
152		if(byte == 0)
153			goto corrupted;
154
155		bytes += byte;
156
157		/* If this is not the last metadata block in the inode table
158		 * then it should be SQUASHFS_METADATA_SIZE in size.
159		 * Note, we can't use expected in read_block() above for this
160		 * because we don't know if this is the last block until
161		 * after reading.
162		 */
163		if(start != end && byte != SQUASHFS_METADATA_SIZE)
164			goto corrupted;
165	}
166
167	/*
168	 * We expect to have found the metadata block containing the
169	 * root inode in the above inode_table metadata block scan.  If it
170	 * hasn't been found then the filesystem is corrupted
171	 */
172	if(*root_inode_block == UINT_MAX)
173		goto corrupted;
174
175	/*
176	 * The number of bytes available after the root inode medata block
177	 * should be at least the root inode offset + the size of a
178	 * regular directory inode, if not the filesystem is corrupted
179	 *
180	 *	+-----------------------+-----------------------+
181	 *	| 			|        directory	|
182	 *	|			|          inode	|
183	 *	+-----------------------+-----------------------+
184	 *	^			^			^
185	 *	*root_inode_block	root_inode_offset	bytes
186	 */
187	if((bytes - *root_inode_block) < (root_inode_offset +
188			sizeof(struct squashfs_dir_inode_header)))
189		goto corrupted;
190
191	/*
192	 * Read last inode entry which is the root directory inode, and obtain
193	 * the last directory start block index.  This is used when calculating
194	 * the total uncompressed directory size.  The directory bytes in the
195	 * last * block will be counted as normal.
196	 *
197	 * Note, the previous check ensures the following calculation won't
198	 * underflow, and we won't access beyond the buffer
199	 */
200	*root_inode_size = bytes - (*root_inode_block + root_inode_offset);
201	bytes = *root_inode_block + root_inode_offset;
202	SQUASHFS_SWAP_DIR_INODE_HEADER(*inode_table + bytes, &dir_inode->dir);
203
204	if(dir_inode->base.inode_type == SQUASHFS_DIR_TYPE)
205		directory_start_block = dir_inode->dir.start_block;
206	else if(dir_inode->base.inode_type == SQUASHFS_LDIR_TYPE) {
207		if(*root_inode_size < sizeof(struct squashfs_ldir_inode_header))
208			/* corrupted filesystem */
209			goto corrupted;
210		SQUASHFS_SWAP_LDIR_INODE_HEADER(*inode_table + bytes,
211			&dir_inode->ldir);
212		directory_start_block = dir_inode->ldir.start_block;
213	} else
214		/* bad type, corrupted filesystem */
215		goto corrupted;
216
217	get_uid(id_table[dir_inode->base.uid]);
218	get_guid(id_table[dir_inode->base.guid]);
219
220	/* allocate fragment to file mapping table */
221	file_mapping = calloc(sBlk->fragments, sizeof(struct append_file *));
222	if(file_mapping == NULL)
223		MEM_ERROR();
224
225	for(cur_ptr = *inode_table; cur_ptr < *inode_table + bytes; files ++) {
226		if(NO_INODE_BYTES(squashfs_base_inode_header))
227			/* corrupted filesystem */
228			goto corrupted;
229
230		SQUASHFS_SWAP_BASE_INODE_HEADER(cur_ptr, &base);
231
232		TRACE("scan_inode_table: processing inode @ byte position "
233			"0x%x, type 0x%x\n",
234			(unsigned int) (cur_ptr - *inode_table),
235			base.inode_type);
236
237		get_uid(id_table[base.uid]);
238		get_guid(id_table[base.guid]);
239
240		switch(base.inode_type) {
241		case SQUASHFS_FILE_TYPE: {
242			struct squashfs_reg_inode_header inode;
243			int frag_bytes, blocks, i;
244			long long start, file_bytes = 0;
245			unsigned int *block_list;
246
247			if(NO_INODE_BYTES(squashfs_reg_inode_header))
248				/* corrupted filesystem */
249				goto corrupted;
250
251			SQUASHFS_SWAP_REG_INODE_HEADER(cur_ptr, &inode);
252
253			frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
254				0 : inode.file_size % sBlk->block_size;
255			blocks = inode.fragment == SQUASHFS_INVALID_FRAG ?
256				(inode.file_size + sBlk->block_size - 1) >>
257				sBlk->block_log : inode.file_size >>
258				sBlk->block_log;
259			start = inode.start_block;
260
261			TRACE("scan_inode_table: regular file, file_size %d, "
262				"blocks %d\n", inode.file_size, blocks);
263
264			if(NO_BYTES(blocks * sizeof(unsigned int)))
265				/* corrupted filesystem */
266				goto corrupted;
267
268			block_list = malloc(blocks * sizeof(unsigned int));
269			if(block_list == NULL)
270				MEM_ERROR();
271
272			cur_ptr += sizeof(inode);
273			SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
274
275			*uncompressed_file += inode.file_size;
276			(*file_count) ++;
277
278			for(i = 0; i < blocks; i++)
279				file_bytes +=
280					SQUASHFS_COMPRESSED_SIZE_BLOCK
281								(block_list[i]);
282
283			if(inode.fragment != SQUASHFS_INVALID_FRAG &&
284					inode.fragment >= sBlk->fragments) {
285				free(block_list);
286				goto corrupted;
287			}
288
289			add_file(start, inode.file_size, file_bytes,
290				block_list, blocks, inode.fragment,
291				inode.offset, frag_bytes);
292
293			cur_ptr += blocks * sizeof(unsigned int);
294			break;
295		}
296		case SQUASHFS_LREG_TYPE: {
297			struct squashfs_lreg_inode_header inode;
298			int frag_bytes, blocks, i;
299			long long start, file_bytes = 0;
300			unsigned int *block_list;
301
302			if(NO_INODE_BYTES(squashfs_lreg_inode_header))
303				/* corrupted filesystem */
304				goto corrupted;
305
306			SQUASHFS_SWAP_LREG_INODE_HEADER(cur_ptr, &inode);
307
308			frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
309				0 : inode.file_size % sBlk->block_size;
310			blocks = inode.fragment == SQUASHFS_INVALID_FRAG ?
311				(inode.file_size + sBlk->block_size - 1) >>
312				sBlk->block_log : inode.file_size >>
313				sBlk->block_log;
314			start = inode.start_block;
315
316			TRACE("scan_inode_table: extended regular "
317				"file, file_size %lld, blocks %d\n",
318				inode.file_size, blocks);
319
320			if(NO_BYTES(blocks * sizeof(unsigned int)))
321				/* corrupted filesystem */
322				goto corrupted;
323
324			block_list = malloc(blocks * sizeof(unsigned int));
325			if(block_list == NULL)
326				MEM_ERROR();
327
328			cur_ptr += sizeof(inode);
329			SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
330
331			*uncompressed_file += inode.file_size;
332			(*file_count) ++;
333
334			for(i = 0; i < blocks; i++)
335				file_bytes +=
336					SQUASHFS_COMPRESSED_SIZE_BLOCK
337								(block_list[i]);
338
339			if(inode.fragment != SQUASHFS_INVALID_FRAG &&
340					inode.fragment >= sBlk->fragments) {
341				free(block_list);
342				goto corrupted;
343			}
344
345			add_file(start, inode.file_size, file_bytes,
346				block_list, blocks, inode.fragment,
347				inode.offset, frag_bytes);
348
349			cur_ptr += blocks * sizeof(unsigned int);
350			break;
351		}
352		case SQUASHFS_SYMLINK_TYPE:
353		case SQUASHFS_LSYMLINK_TYPE: {
354			struct squashfs_symlink_inode_header inode;
355
356			if(NO_INODE_BYTES(squashfs_symlink_inode_header))
357				/* corrupted filesystem */
358				goto corrupted;
359
360			SQUASHFS_SWAP_SYMLINK_INODE_HEADER(cur_ptr, &inode);
361
362			(*sym_count) ++;
363
364			if (inode.inode_type == SQUASHFS_LSYMLINK_TYPE) {
365				if(NO_BYTES(inode.symlink_size +
366							sizeof(unsigned int)))
367					/* corrupted filesystem */
368					goto corrupted;
369				cur_ptr += sizeof(inode) + inode.symlink_size +
370							sizeof(unsigned int);
371			} else {
372				if(NO_BYTES(inode.symlink_size))
373					/* corrupted filesystem */
374					goto corrupted;
375				cur_ptr += sizeof(inode) + inode.symlink_size;
376			}
377			break;
378		}
379		case SQUASHFS_DIR_TYPE: {
380			struct squashfs_dir_inode_header dir_inode;
381
382			if(NO_INODE_BYTES(squashfs_dir_inode_header))
383				/* corrupted filesystem */
384				goto corrupted;
385
386			SQUASHFS_SWAP_DIR_INODE_HEADER(cur_ptr, &dir_inode);
387
388			if(dir_inode.start_block < directory_start_block)
389				*uncompressed_directory += dir_inode.file_size;
390
391			(*dir_count) ++;
392			cur_ptr += sizeof(struct squashfs_dir_inode_header);
393			break;
394		}
395		case SQUASHFS_LDIR_TYPE: {
396			struct squashfs_ldir_inode_header dir_inode;
397			int i;
398
399			if(NO_INODE_BYTES(squashfs_ldir_inode_header))
400				/* corrupted filesystem */
401				goto corrupted;
402
403			SQUASHFS_SWAP_LDIR_INODE_HEADER(cur_ptr, &dir_inode);
404
405			if(dir_inode.start_block < directory_start_block)
406				*uncompressed_directory += dir_inode.file_size;
407
408			(*dir_count) ++;
409			cur_ptr += sizeof(struct squashfs_ldir_inode_header);
410
411			for(i = 0; i < dir_inode.i_count; i++) {
412				struct squashfs_dir_index index;
413
414				if(NO_BYTES(sizeof(index)))
415					/* corrupted filesystem */
416					goto corrupted;
417
418				SQUASHFS_SWAP_DIR_INDEX(cur_ptr, &index);
419
420				if(NO_BYTES(index.size + 1))
421					/* corrupted filesystem */
422					goto corrupted;
423
424				cur_ptr += sizeof(index) + index.size + 1;
425			}
426			break;
427		}
428	 	case SQUASHFS_BLKDEV_TYPE:
429	 	case SQUASHFS_CHRDEV_TYPE:
430			if(NO_INODE_BYTES(squashfs_dev_inode_header))
431				/* corrupted filesystem */
432				goto corrupted;
433
434			(*dev_count) ++;
435			cur_ptr += sizeof(struct squashfs_dev_inode_header);
436			break;
437	 	case SQUASHFS_LBLKDEV_TYPE:
438	 	case SQUASHFS_LCHRDEV_TYPE:
439			if(NO_INODE_BYTES(squashfs_ldev_inode_header))
440				/* corrupted filesystem */
441				goto corrupted;
442
443			(*dev_count) ++;
444			cur_ptr += sizeof(struct squashfs_ldev_inode_header);
445			break;
446		case SQUASHFS_FIFO_TYPE:
447			if(NO_INODE_BYTES(squashfs_ipc_inode_header))
448				/* corrupted filesystem */
449				goto corrupted;
450
451			(*fifo_count) ++;
452			cur_ptr += sizeof(struct squashfs_ipc_inode_header);
453			break;
454		case SQUASHFS_LFIFO_TYPE:
455			if(NO_INODE_BYTES(squashfs_lipc_inode_header))
456				/* corrupted filesystem */
457				goto corrupted;
458
459			(*fifo_count) ++;
460			cur_ptr += sizeof(struct squashfs_lipc_inode_header);
461			break;
462		case SQUASHFS_SOCKET_TYPE:
463			if(NO_INODE_BYTES(squashfs_ipc_inode_header))
464				/* corrupted filesystem */
465				goto corrupted;
466
467			(*sock_count) ++;
468			cur_ptr += sizeof(struct squashfs_ipc_inode_header);
469			break;
470		case SQUASHFS_LSOCKET_TYPE:
471			if(NO_INODE_BYTES(squashfs_lipc_inode_header))
472				/* corrupted filesystem */
473				goto corrupted;
474
475			(*sock_count) ++;
476			cur_ptr += sizeof(struct squashfs_lipc_inode_header);
477			break;
478	 	default:
479			ERROR("Unknown inode type %d in scan_inode_table!\n",
480					base.inode_type);
481			goto corrupted;
482		}
483	}
484
485	printf("Read existing filesystem, %d inodes scanned\n", files);
486	return TRUE;
487
488corrupted:
489	ERROR("scan_inode_table: filesystem corruption detected in "
490		"scanning metadata\n");
491	free(*inode_table);
492	return FALSE;
493}
494
495
496struct compressor *read_super(int fd, struct squashfs_super_block *sBlk, char *source)
497{
498	int res, bytes = 0;
499	char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned));
500
501	res = read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
502		sBlk);
503	if(res == 0) {
504		ERROR("Can't find a SQUASHFS superblock on %s\n",
505				source);
506		ERROR("Wrong filesystem or filesystem is corrupted!\n");
507		goto failed_mount;
508	}
509
510	SQUASHFS_INSWAP_SUPER_BLOCK(sBlk);
511
512	if(sBlk->s_magic != SQUASHFS_MAGIC) {
513		if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP)
514			ERROR("Pre 4.0 big-endian filesystem on %s, appending"
515				" to this is unsupported\n", source);
516		else {
517			ERROR("Can't find a SQUASHFS superblock on %s\n",
518				source);
519			ERROR("Wrong filesystem or filesystem is corrupted!\n");
520		}
521		goto failed_mount;
522	}
523
524	/* Check the MAJOR & MINOR versions */
525	if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) {
526		if(sBlk->s_major < 4)
527			ERROR("Filesystem on %s is a SQUASHFS %d.%d filesystem."
528				"  Appending\nto SQUASHFS %d.%d filesystems is "
529				"not supported.  Please convert it to a "
530				"SQUASHFS 4 filesystem\n", source,
531				sBlk->s_major,
532				sBlk->s_minor, sBlk->s_major, sBlk->s_minor);
533		else
534			ERROR("Filesystem on %s is %d.%d, which is a later "
535				"filesystem version than I support\n",
536				source, sBlk->s_major, sBlk->s_minor);
537		goto failed_mount;
538	}
539
540	/* Check the compression type */
541	comp = lookup_compressor_id(sBlk->compression);
542	if(!comp->supported) {
543		ERROR("Filesystem on %s uses %s compression, this is "
544			"unsupported by this version\n", source, comp->name);
545		ERROR("Compressors available:\n");
546		display_compressors("", "");
547		goto failed_mount;
548	}
549
550	/*
551	 * Read extended superblock information from disk.
552	 *
553	 * Read compressor specific options from disk if present, and pass
554	 * to compressor to set compressor options.
555	 *
556	 * Note, if there's no compressor options present, the compressor
557	 * is still called to set the default options (the defaults may have
558	 * been changed by the user specifying options on the command
559	 * line which need to be over-ridden).
560	 *
561	 * Compressor_extract_options is also used to ensure that
562	 * we know how decompress a filesystem compressed with these
563	 * compression options.
564	 */
565	if(SQUASHFS_COMP_OPTS(sBlk->flags)) {
566		bytes = read_block(fd, sizeof(*sBlk), NULL, 0, buffer);
567
568		if(bytes == 0) {
569			ERROR("Failed to read compressor options from append "
570				"filesystem\n");
571			ERROR("Filesystem corrupted?\n");
572			goto failed_mount;
573		}
574	}
575
576	res = compressor_extract_options(comp, sBlk->block_size, buffer, bytes);
577	if(res == -1) {
578		ERROR("Compressor failed to set compressor options\n");
579		goto failed_mount;
580	}
581
582	printf("Found a valid %sSQUASHFS superblock on %s.\n",
583		SQUASHFS_EXPORTABLE(sBlk->flags) ? "exportable " : "", source);
584	printf("\tCompression used %s\n", comp->name);
585	printf("\tInodes are %scompressed\n",
586		SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : "");
587	printf("\tData is %scompressed\n",
588		SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : "");
589	printf("\tFragments are %scompressed\n",
590		SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : "");
591	printf("\tXattrs are %scompressed\n",
592		SQUASHFS_UNCOMPRESSED_XATTRS(sBlk->flags) ? "un" : "");
593	printf("\tFragments are %spresent in the filesystem\n",
594		SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not " : "");
595	printf("\tAlways-use-fragments option is %sspecified\n",
596		SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not ");
597	printf("\tDuplicates are %sremoved\n",
598		SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not ");
599	printf("\tXattrs are %sstored\n",
600		SQUASHFS_NO_XATTRS(sBlk->flags) ? "not " : "");
601	printf("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n",
602		sBlk->bytes_used / 1024.0, sBlk->bytes_used
603		/ (1024.0 * 1024.0));
604	printf("\tBlock size %d\n", sBlk->block_size);
605	printf("\tNumber of fragments %d\n", sBlk->fragments);
606	printf("\tNumber of inodes %d\n", sBlk->inodes);
607	printf("\tNumber of ids %d\n", sBlk->no_ids);
608	TRACE("sBlk->inode_table_start %llx\n", sBlk->inode_table_start);
609	TRACE("sBlk->directory_table_start %llx\n",
610		sBlk->directory_table_start);
611	TRACE("sBlk->id_table_start %llx\n", sBlk->id_table_start);
612	TRACE("sBlk->fragment_table_start %llx\n", sBlk->fragment_table_start);
613	TRACE("sBlk->lookup_table_start %llx\n", sBlk->lookup_table_start);
614	TRACE("sBlk->xattr_id_table_start %llx\n", sBlk->xattr_id_table_start);
615	printf("\n");
616
617	return comp;
618
619failed_mount:
620	return NULL;
621}
622
623
624unsigned char *squashfs_readdir(int fd, int root_entries,
625	unsigned int directory_start_block, int offset, int size,
626	unsigned int *last_directory_block, struct squashfs_super_block *sBlk,
627	void (push_directory_entry)(char *, squashfs_inode, int, int))
628{
629	struct squashfs_dir_header dirh;
630	char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]
631		__attribute__ ((aligned));
632	struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
633	unsigned char *directory_table = NULL;
634	int byte, bytes = 0, dir_count;
635	long long start = sBlk->directory_table_start + directory_start_block,
636		last_start_block = start;
637
638	size += offset;
639	directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) &
640		~(SQUASHFS_METADATA_SIZE - 1));
641	if(directory_table == NULL)
642		MEM_ERROR();
643
644	while(bytes < size) {
645		int expected = (size - bytes) >= SQUASHFS_METADATA_SIZE ?
646			SQUASHFS_METADATA_SIZE : 0;
647
648		TRACE("squashfs_readdir: reading block 0x%llx, bytes read so "
649			"far %d\n", start, bytes);
650
651		last_start_block = start;
652		byte = read_block(fd, start, &start, expected, directory_table + bytes);
653		if(byte == 0) {
654			ERROR("Failed to read directory\n");
655			ERROR("Filesystem corrupted?\n");
656			free(directory_table);
657			return NULL;
658		}
659		bytes += byte;
660	}
661
662	if(!root_entries)
663		goto all_done;
664
665	bytes = offset;
666 	while(bytes < size) {
667		SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh);
668
669		dir_count = dirh.count + 1;
670		TRACE("squashfs_readdir: Read directory header @ byte position "
671			"0x%x, 0x%x directory entries\n", bytes, dir_count);
672		bytes += sizeof(dirh);
673
674		while(dir_count--) {
675			SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire);
676			bytes += sizeof(*dire);
677
678			memcpy(dire->name, directory_table + bytes,
679				dire->size + 1);
680			dire->name[dire->size + 1] = '\0';
681			TRACE("squashfs_readdir: pushing directory entry %s, "
682				"inode %x:%x, type 0x%x\n", dire->name,
683				dirh.start_block, dire->offset, dire->type);
684			push_directory_entry(dire->name,
685				SQUASHFS_MKINODE(dirh.start_block,
686				dire->offset), dirh.inode_number +
687				dire->inode_number, dire->type);
688			bytes += dire->size + 1;
689		}
690	}
691
692all_done:
693	*last_directory_block = (unsigned int) last_start_block -
694		sBlk->directory_table_start;
695	return directory_table;
696}
697
698
699unsigned int *read_id_table(int fd, struct squashfs_super_block *sBlk)
700{
701	int indexes = SQUASHFS_ID_BLOCKS(sBlk->no_ids);
702	long long index[indexes];
703	int bytes = SQUASHFS_ID_BYTES(sBlk->no_ids);
704	unsigned int *id_table;
705	int res, i;
706
707	id_table = malloc(bytes);
708	if(id_table == NULL)
709		MEM_ERROR();
710
711	res = read_fs_bytes(fd, sBlk->id_table_start,
712		SQUASHFS_ID_BLOCK_BYTES(sBlk->no_ids), index);
713	if(res == 0) {
714		ERROR("Failed to read id table index\n");
715		ERROR("Filesystem corrupted?\n");
716		free(id_table);
717		return NULL;
718	}
719
720	SQUASHFS_INSWAP_ID_BLOCKS(index, indexes);
721
722	for(i = 0; i < indexes; i++) {
723		int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
724					bytes & (SQUASHFS_METADATA_SIZE - 1);
725		int length = read_block(fd, index[i], NULL, expected,
726			((unsigned char *) id_table) +
727			(i * SQUASHFS_METADATA_SIZE));
728		TRACE("Read id table block %d, from 0x%llx, length %d\n", i,
729			index[i], length);
730		if(length == 0) {
731			ERROR("Failed to read id table block %d, from 0x%llx, "
732				"length %d\n", i, index[i], length);
733			ERROR("Filesystem corrupted?\n");
734			free(id_table);
735			return NULL;
736		}
737	}
738
739	SQUASHFS_INSWAP_INTS(id_table, sBlk->no_ids);
740
741	for(i = 0; i < sBlk->no_ids; i++) {
742		TRACE("Adding id %d to id tables\n", id_table[i]);
743		create_id(id_table[i]);
744	}
745
746	return id_table;
747}
748
749
750int read_fragment_table(int fd, struct squashfs_super_block *sBlk,
751	struct squashfs_fragment_entry **fragment_table)
752{
753	int res, i;
754	int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk->fragments);
755	int indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments);
756	long long fragment_table_index[indexes];
757
758	TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
759		"from 0x%llx\n", sBlk->fragments, indexes,
760		sBlk->fragment_table_start);
761
762	if(sBlk->fragments == 0)
763		return 1;
764
765	*fragment_table = malloc(bytes);
766	if(*fragment_table == NULL)
767		MEM_ERROR();
768
769	res = read_fs_bytes(fd, sBlk->fragment_table_start,
770		SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments),
771		fragment_table_index);
772	if(res == 0) {
773		ERROR("Failed to read fragment table index\n");
774		ERROR("Filesystem corrupted?\n");
775		free(*fragment_table);
776		return 0;
777	}
778
779	SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index, indexes);
780
781	for(i = 0; i < indexes; i++) {
782		int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
783					bytes & (SQUASHFS_METADATA_SIZE - 1);
784		int length = read_block(fd, fragment_table_index[i], NULL,
785			expected, ((unsigned char *) *fragment_table) +
786			(i * SQUASHFS_METADATA_SIZE));
787		TRACE("Read fragment table block %d, from 0x%llx, length %d\n",
788			i, fragment_table_index[i], length);
789		if(length == 0) {
790			ERROR("Failed to read fragment table block %d, from "
791				"0x%llx, length %d\n", i,
792				fragment_table_index[i], length);
793			ERROR("Filesystem corrupted?\n");
794			free(*fragment_table);
795			return 0;
796		}
797	}
798
799	for(i = 0; i < sBlk->fragments; i++)
800		SQUASHFS_INSWAP_FRAGMENT_ENTRY(&(*fragment_table)[i]);
801
802	return 1;
803}
804
805
806int read_inode_lookup_table(int fd, struct squashfs_super_block *sBlk,
807	squashfs_inode **inode_lookup_table)
808{
809	int lookup_bytes = SQUASHFS_LOOKUP_BYTES(sBlk->inodes);
810	int indexes = SQUASHFS_LOOKUP_BLOCKS(sBlk->inodes);
811	long long index[indexes];
812	int res, i;
813
814	if(sBlk->lookup_table_start == SQUASHFS_INVALID_BLK)
815		return 1;
816
817	*inode_lookup_table = malloc(lookup_bytes);
818	if(*inode_lookup_table == NULL)
819		MEM_ERROR();
820
821	res = read_fs_bytes(fd, sBlk->lookup_table_start,
822		SQUASHFS_LOOKUP_BLOCK_BYTES(sBlk->inodes), index);
823	if(res == 0) {
824		ERROR("Failed to read inode lookup table index\n");
825		ERROR("Filesystem corrupted?\n");
826		free(*inode_lookup_table);
827		return 0;
828	}
829
830	SQUASHFS_INSWAP_LONG_LONGS(index, indexes);
831
832	for(i = 0; i <  indexes; i++) {
833		int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
834				lookup_bytes & (SQUASHFS_METADATA_SIZE - 1);
835		int length = read_block(fd, index[i], NULL, expected,
836			((unsigned char *) *inode_lookup_table) +
837			(i * SQUASHFS_METADATA_SIZE));
838		TRACE("Read inode lookup table block %d, from 0x%llx, length "
839			"%d\n", i, index[i], length);
840		if(length == 0) {
841			ERROR("Failed to read inode lookup table block %d, "
842				"from 0x%llx, length %d\n", i, index[i],
843				length);
844			ERROR("Filesystem corrupted?\n");
845			free(*inode_lookup_table);
846			return 0;
847		}
848	}
849
850	SQUASHFS_INSWAP_LONG_LONGS(*inode_lookup_table, sBlk->inodes);
851
852	return 1;
853}
854
855
856long long read_filesystem(char *root_name, int fd, struct squashfs_super_block *sBlk,
857	char **cinode_table, char **data_cache, char **cdirectory_table,
858	char **directory_data_cache, unsigned int *last_directory_block,
859	unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size,
860	unsigned int *root_inode_size, unsigned int *inode_dir_start_block,
861	int *file_count, int *sym_count, int *dev_count, int *dir_count,
862	int *fifo_count, int *sock_count, long long *uncompressed_file,
863	unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
864	unsigned int *inode_dir_inode_number,
865	unsigned int *inode_dir_parent_inode,
866	void (push_directory_entry)(char *, squashfs_inode, int, int),
867	struct squashfs_fragment_entry **fragment_table,
868	squashfs_inode **inode_lookup_table)
869{
870	unsigned char *inode_table = NULL, *directory_table = NULL;
871	long long start = sBlk->inode_table_start;
872	long long end = sBlk->directory_table_start;
873	long long root_inode_start = start +
874		SQUASHFS_INODE_BLK(sBlk->root_inode);
875	unsigned int root_inode_offset =
876		SQUASHFS_INODE_OFFSET(sBlk->root_inode);
877	unsigned int root_inode_block;
878	union squashfs_inode_header inode;
879	unsigned int *id_table = NULL;
880	int res;
881
882	printf("Scanning existing filesystem...\n");
883
884	if(get_xattrs(fd, sBlk) == 0)
885		goto error;
886
887	if(read_fragment_table(fd, sBlk, fragment_table) == 0)
888		goto error;
889
890	if(read_inode_lookup_table(fd, sBlk, inode_lookup_table) == 0)
891		goto error;
892
893	id_table = read_id_table(fd, sBlk);
894	if(id_table == NULL)
895		goto error;
896
897	res = scan_inode_table(fd, start, end, root_inode_start,
898		root_inode_offset, sBlk, &inode, &inode_table,
899		&root_inode_block, root_inode_size, uncompressed_file,
900		uncompressed_directory, file_count, sym_count, dev_count,
901		dir_count, fifo_count, sock_count, id_table);
902	if(res == 0)
903		goto error;
904
905	*uncompressed_inode = root_inode_block;
906
907	if(inode.base.inode_type == SQUASHFS_DIR_TYPE ||
908			inode.base.inode_type == SQUASHFS_LDIR_TYPE) {
909		if(inode.base.inode_type == SQUASHFS_DIR_TYPE) {
910			*inode_dir_start_block = inode.dir.start_block;
911			*inode_dir_offset = inode.dir.offset;
912			*inode_dir_file_size = inode.dir.file_size - 3;
913			*inode_dir_inode_number = inode.dir.inode_number;
914			*inode_dir_parent_inode = inode.dir.parent_inode;
915		} else {
916			*inode_dir_start_block = inode.ldir.start_block;
917			*inode_dir_offset = inode.ldir.offset;
918			*inode_dir_file_size = inode.ldir.file_size - 3;
919			*inode_dir_inode_number = inode.ldir.inode_number;
920			*inode_dir_parent_inode = inode.ldir.parent_inode;
921		}
922
923		directory_table = squashfs_readdir(fd, !root_name,
924			*inode_dir_start_block, *inode_dir_offset,
925			*inode_dir_file_size, last_directory_block, sBlk,
926			push_directory_entry);
927		if(directory_table == NULL)
928			goto error;
929
930		root_inode_start -= start;
931		*cinode_table = malloc(root_inode_start);
932		if(*cinode_table == NULL)
933			MEM_ERROR();
934
935	       	res = read_fs_bytes(fd, start, root_inode_start, *cinode_table);
936		if(res == 0) {
937			ERROR("Failed to read inode table\n");
938			ERROR("Filesystem corrupted?\n");
939			goto error;
940		}
941
942		*cdirectory_table = malloc(*last_directory_block);
943		if(*cdirectory_table == NULL)
944			MEM_ERROR();
945
946		res = read_fs_bytes(fd, sBlk->directory_table_start,
947			*last_directory_block, *cdirectory_table);
948		if(res == 0) {
949			ERROR("Failed to read directory table\n");
950			ERROR("Filesystem corrupted?\n");
951			goto error;
952		}
953
954		*data_cache = malloc(root_inode_offset + *root_inode_size);
955		if(*data_cache == NULL)
956			MEM_ERROR();
957
958		memcpy(*data_cache, inode_table + root_inode_block,
959			root_inode_offset + *root_inode_size);
960
961		*directory_data_cache = malloc(*inode_dir_offset +
962			*inode_dir_file_size);
963		if(*directory_data_cache == NULL)
964			MEM_ERROR();
965
966		memcpy(*directory_data_cache, directory_table,
967			*inode_dir_offset + *inode_dir_file_size);
968
969		free(id_table);
970		free(inode_table);
971		free(directory_table);
972		return sBlk->inode_table_start;
973	}
974
975error:
976	free(id_table);
977	free(inode_table);
978	free(directory_table);
979	return 0;
980}
981