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