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