Home | History | Annotate | Download | only in squashfs-tools
      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 (at) 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 
     55 int 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 
    120 int 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 
    488 corrupted:
    489 	ERROR("scan_inode_table: filesystem corruption detected in "
    490 		"scanning metadata\n");
    491 	free(*inode_table);
    492 	return FALSE;
    493 }
    494 
    495 
    496 struct 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 
    619 failed_mount:
    620 	return NULL;
    621 }
    622 
    623 
    624 unsigned 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 
    692 all_done:
    693 	*last_directory_block = (unsigned int) last_start_block -
    694 		sBlk->directory_table_start;
    695 	return directory_table;
    696 }
    697 
    698 
    699 unsigned 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 
    750 int 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 
    806 int 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 
    856 long 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 
    975 error:
    976 	free(id_table);
    977 	free(inode_table);
    978 	free(directory_table);
    979 	return 0;
    980 }
    981