1/* 2 * Unsquash 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 * unsquash.c 22 */ 23 24#define CONFIG_SQUASHFS_2_0_COMPATIBILITY 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 <zlib.h> 35#include <sys/mman.h> 36#include <utime.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 "sqlzma.h" 50#include "LzmaDec.h" 51 52#include <stdlib.h> 53 54#ifdef SQUASHFS_TRACE 55#define TRACE(s, args...) do { \ 56 printf("mksquashfs: "s, ## args); \ 57 } while(0) 58#else 59#define TRACE(s, args...) 60#endif 61 62#define ERROR(s, args...) do { \ 63 fprintf(stderr, s, ## args); \ 64 } while(0) 65 66#define EXIT_UNSQUASH(s, args...) do { \ 67 fprintf(stderr, "FATAL ERROR aborting: "s, ## args); \ 68 } while(0) 69 70struct hash_table_entry { 71 int start; 72 int bytes; 73 struct hash_table_entry *next; 74}; 75 76typedef struct squashfs_operations { 77 struct dir *(*squashfs_opendir)(unsigned int block_start, unsigned int offset); 78 char *(*read_fragment)(unsigned int fragment); 79 void (*read_fragment_table)(); 80 int (*create_inode)(char *pathname, unsigned int start_block, unsigned int offset); 81} squashfs_operations; 82 83squashfs_super_block sBlk; 84squashfs_operations s_ops; 85 86int bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0, 87 dev_count = 0, fifo_count = 0; 88char *inode_table = NULL, *directory_table = NULL; 89struct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536]; 90int fd; 91squashfs_fragment_entry *fragment_table; 92squashfs_fragment_entry_2 *fragment_table_2; 93unsigned int *uid_table, *guid_table; 94unsigned int cached_frag = SQUASHFS_INVALID_FRAG; 95char *fragment_data; 96char *file_data; 97char *data; 98unsigned int block_size; 99int lsonly = FALSE, info = FALSE, force = FALSE; 100char **created_inode; 101int root_process; 102 103#define CALCULATE_HASH(start) (start & 0xffff) 104 105int add_entry(struct hash_table_entry *hash_table[], int start, int bytes) 106{ 107 int hash = CALCULATE_HASH(start); 108 struct hash_table_entry *hash_table_entry; 109 110 if((hash_table_entry = malloc(sizeof(struct hash_table_entry))) == NULL) { 111 ERROR("add_hash: out of memory in malloc\n"); 112 return FALSE; 113 } 114 115 hash_table_entry->start = start; 116 hash_table_entry->bytes = bytes; 117 hash_table_entry->next = hash_table[hash]; 118 hash_table[hash] = hash_table_entry; 119 120 return TRUE; 121} 122 123 124int lookup_entry(struct hash_table_entry *hash_table[], int start) 125{ 126 int hash = CALCULATE_HASH(start); 127 struct hash_table_entry *hash_table_entry; 128 129 for(hash_table_entry = hash_table[hash]; hash_table_entry; 130 hash_table_entry = hash_table_entry->next) 131 if(hash_table_entry->start == start) 132 return hash_table_entry->bytes; 133 134 return -1; 135} 136 137 138int read_bytes(long long byte, int bytes, char *buff) 139{ 140 off_t off = byte; 141 142 TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes); 143 144 if(lseek(fd, off, SEEK_SET) == -1) { 145 ERROR("Lseek failed because %s\b", strerror(errno)); 146 return FALSE; 147 } 148 149 if(read(fd, buff, bytes) == -1) { 150 ERROR("Read on destination failed because %s\n", strerror(errno)); 151 return FALSE; 152 } 153 154 return TRUE; 155} 156 157 158int read_block(long long start, long long *next, char *block) 159{ 160 unsigned short c_byte; 161 int offset = 2; 162 163 if(swap) { 164 if(read_bytes(start, 2, block) == FALSE) 165 goto failed; 166 ((unsigned char *) &c_byte)[1] = block[0]; 167 ((unsigned char *) &c_byte)[0] = block[1]; 168 } else 169 if(read_bytes(start, 2, (char *)&c_byte) == FALSE) 170 goto failed; 171 172 TRACE("read_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ? "compressed" : "uncompressed"); 173 174 if(SQUASHFS_CHECK_DATA(sBlk.flags)) 175 offset = 3; 176 if(SQUASHFS_COMPRESSED(c_byte)) { 177 char buffer[SQUASHFS_METADATA_SIZE]; 178 int res; 179 unsigned long bytes = SQUASHFS_METADATA_SIZE; 180 181 c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); 182 if(read_bytes(start + offset, c_byte, buffer) == FALSE) 183 goto failed; 184 if (!is_lzma(buffer[0])) { 185 if((res = uncompress((unsigned char *) block, &bytes, 186 (const unsigned char *) buffer, c_byte)) != Z_OK) { 187 if(res == Z_MEM_ERROR) 188 ERROR("zlib::uncompress failed, not enough memory\n"); 189 else if(res == Z_BUF_ERROR) 190 ERROR("zlib::uncompress failed, not enough room in output buffer\n"); 191 else 192 ERROR("zlib::uncompress failed, unknown error %d\n", res); 193 goto failed; 194 } 195 } 196 else { 197 if((res = LzmaUncompress(block, &bytes, buffer, c_byte)) != SZ_OK) 198 ERROR("LzmaUncompress: error (%d)\n", res); 199 } 200 201 if(next) 202 *next = start + offset + c_byte; 203 return bytes; 204 } else { 205 c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); 206 if(read_bytes(start + offset, c_byte, block) == FALSE) 207 goto failed; 208 if(next) 209 *next = start + offset + c_byte; 210 return c_byte; 211 } 212 213failed: 214 return FALSE; 215} 216 217 218int read_data_block(long long start, unsigned int size, char *block) 219{ 220 int res; 221 unsigned long bytes = block_size; 222 int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size); 223 224 TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte), SQUASHFS_COMPRESSED_BLOCK(c_byte) ? "compressed" : "uncompressed"); 225 226 if(SQUASHFS_COMPRESSED_BLOCK(size)) { 227 if(read_bytes(start, c_byte, data) == FALSE) 228 return 0; 229 230 if (!is_lzma(data[0])) { 231 if((res = uncompress((unsigned char *) block, &bytes, 232 (const unsigned char *) data, c_byte)) != Z_OK) { 233 if(res == Z_MEM_ERROR) 234 ERROR("zlib::uncompress failed, not enough memory\n"); 235 else if(res == Z_BUF_ERROR) 236 ERROR("zlib::uncompress failed, not enough room in output buffer\n"); 237 else 238 ERROR("zlib::uncompress failed, unknown error %d\n", res); 239 return 0; 240 } 241 } 242 /* LZMA */ 243 else { 244 if((res = LzmaUncompress(block, &bytes, data, c_byte)) != SZ_OK) 245 ERROR("LzmaUncompress: error (%d)\n", res); 246 } 247 248 return bytes; 249 } else { 250 if(read_bytes(start, c_byte, block) == FALSE) 251 return 0; 252 253 return c_byte; 254 } 255} 256 257 258void uncompress_inode_table(long long start, long long end) 259{ 260 int size = 0, bytes = 0, res; 261 262 while(start < end) { 263 if((size - bytes < SQUASHFS_METADATA_SIZE) && 264 ((inode_table = realloc(inode_table, size += 265 SQUASHFS_METADATA_SIZE)) == NULL)) 266 EXIT_UNSQUASH("uncompress_inode_table: out of memory in realloc\n"); 267 TRACE("uncompress_inode_table: reading block 0x%llx\n", start); 268 add_entry(inode_table_hash, start, bytes); 269 if((res = read_block(start, &start, inode_table + bytes)) == 0) { 270 free(inode_table); 271 EXIT_UNSQUASH("uncompress_inode_table: failed to read block\n"); 272 } 273 bytes += res; 274 } 275} 276 277 278int set_attributes(char *pathname, unsigned int mode, unsigned int uid, 279unsigned int guid, unsigned int mtime, unsigned int set_mode) 280{ 281 struct utimbuf times = { (time_t) mtime, (time_t) mtime }; 282 283 if(utime(pathname, ×) == -1) { 284 ERROR("set_attributes: failed to set time on %s, because %s\n", pathname, strerror(errno)); 285 return FALSE; 286 } 287 288 if(root_process) { 289 uid_t uid_value = (uid_t) uid_table[uid]; 290 uid_t guid_value = guid == SQUASHFS_GUIDS ? uid_value : (uid_t) guid_table[guid]; 291 292 if(chown(pathname, uid_value, guid_value) == -1) { 293 ERROR("set_attributes: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno)); 294 return FALSE; 295 } 296 } else 297 mode &= ~07000; 298 299 if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) { 300 ERROR("set_attributes: failed to change mode %s, because %s\n", pathname, strerror(errno)); 301 return FALSE; 302 } 303 304 return TRUE; 305} 306 307 308void read_uids_guids() 309{ 310 if((uid_table = malloc((sBlk.no_uids + sBlk.no_guids) * sizeof(unsigned int))) == NULL) 311 EXIT_UNSQUASH("read_uids_guids: failed to allocate uid/gid table\n"); 312 313 guid_table = uid_table + sBlk.no_uids; 314 315 if(swap) { 316 unsigned int suid_table[sBlk.no_uids + sBlk.no_guids]; 317 318 if(read_bytes(sBlk.uid_start, (sBlk.no_uids + sBlk.no_guids) 319 * sizeof(unsigned int), (char *) suid_table) == 320 FALSE) 321 EXIT_UNSQUASH("read_uids_guids: failed to read uid/gid table\n"); 322 SQUASHFS_SWAP_INTS(uid_table, suid_table, sBlk.no_uids + sBlk.no_guids); 323 } else 324 if(read_bytes(sBlk.uid_start, (sBlk.no_uids + sBlk.no_guids) 325 * sizeof(unsigned int), (char *) uid_table) == 326 FALSE) 327 EXIT_UNSQUASH("read_uids_guids: failed to read uid/gid table\n"); 328} 329 330 331void read_fragment_table() 332{ 333 int i, indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk.fragments); 334 squashfs_fragment_index fragment_table_index[indexes]; 335 336 TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk.fragments, indexes, sBlk.fragment_table_start); 337 338 if(sBlk.fragments == 0) 339 return; 340 341 if((fragment_table = (squashfs_fragment_entry *) 342 malloc(sBlk.fragments * 343 sizeof(squashfs_fragment_entry))) == NULL) 344 EXIT_UNSQUASH("read_fragment_table: failed to allocate fragment table\n"); 345 346 if(swap) { 347 squashfs_fragment_index sfragment_table_index[indexes]; 348 349 read_bytes(sBlk.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk.fragments), (char *) sfragment_table_index); 350 SQUASHFS_SWAP_FRAGMENT_INDEXES(fragment_table_index, sfragment_table_index, indexes); 351 } else 352 read_bytes(sBlk.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk.fragments), (char *) fragment_table_index); 353 354 for(i = 0; i < indexes; i++) { 355 int length = read_block(fragment_table_index[i], NULL, 356 ((char *) fragment_table) + (i * SQUASHFS_METADATA_SIZE)); 357 TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); 358 } 359 360 if(swap) { 361 squashfs_fragment_entry sfragment; 362 for(i = 0; i < sBlk.fragments; i++) { 363 SQUASHFS_SWAP_FRAGMENT_ENTRY((&sfragment), (&fragment_table[i])); 364 memcpy((char *) &fragment_table[i], (char *) &sfragment, sizeof(squashfs_fragment_entry)); 365 } 366 } 367} 368 369 370void read_fragment_table_2() 371{ 372 int i, indexes = SQUASHFS_FRAGMENT_INDEXES_2(sBlk.fragments); 373 unsigned int fragment_table_index[indexes]; 374 375 TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk.fragments, indexes, sBlk.fragment_table_start); 376 377 if(sBlk.fragments == 0) 378 return; 379 380 if((fragment_table_2 = (squashfs_fragment_entry_2 *) 381 malloc(sBlk.fragments * 382 sizeof(squashfs_fragment_entry))) == NULL) 383 EXIT_UNSQUASH("read_fragment_table: failed to allocate fragment table\n"); 384 385 if(swap) { 386 unsigned int sfragment_table_index[indexes]; 387 388 read_bytes(sBlk.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sBlk.fragments), (char *) sfragment_table_index); 389 SQUASHFS_SWAP_FRAGMENT_INDEXES_2(fragment_table_index, sfragment_table_index, indexes); 390 } else 391 read_bytes(sBlk.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sBlk.fragments), (char *) fragment_table_index); 392 393 for(i = 0; i < indexes; i++) { 394 int length = read_block(fragment_table_index[i], NULL, 395 ((char *) fragment_table_2) + (i * SQUASHFS_METADATA_SIZE)); 396 TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); 397 } 398 399 if(swap) { 400 squashfs_fragment_entry_2 sfragment; 401 for(i = 0; i < sBlk.fragments; i++) { 402 SQUASHFS_SWAP_FRAGMENT_ENTRY_2((&sfragment), (&fragment_table_2[i])); 403 memcpy((char *) &fragment_table_2[i], (char *) &sfragment, sizeof(squashfs_fragment_entry_2)); 404 } 405 } 406} 407 408 409char *read_fragment(unsigned int fragment) 410{ 411 TRACE("read_fragment: reading fragment %d\n", fragment); 412 413 if(cached_frag == SQUASHFS_INVALID_FRAG || fragment != cached_frag) { 414 squashfs_fragment_entry *fragment_entry = &fragment_table[fragment]; 415 if(read_data_block(fragment_entry->start_block, fragment_entry->size, fragment_data) == 0) { 416 ERROR("read_fragment: failed to read fragment %d\n", fragment); 417 cached_frag = SQUASHFS_INVALID_FRAG; 418 return NULL; 419 } 420 cached_frag = fragment; 421 } 422 423 return fragment_data; 424} 425 426 427char *read_fragment_2(unsigned int fragment) 428{ 429 TRACE("read_fragment: reading fragment %d\n", fragment); 430 431 if(cached_frag == SQUASHFS_INVALID_FRAG || fragment != cached_frag) { 432 squashfs_fragment_entry_2 *fragment_entry = &fragment_table_2[fragment]; 433 if(read_data_block(fragment_entry->start_block, fragment_entry->size, fragment_data) == 0) { 434 ERROR("read_fragment: failed to read fragment %d\n", fragment); 435 cached_frag = SQUASHFS_INVALID_FRAG; 436 return NULL; 437 } 438 cached_frag = fragment; 439 } 440 441 return fragment_data; 442} 443 444 445int write_file(char *pathname, unsigned int fragment, unsigned int frag_bytes, 446unsigned int offset, unsigned int blocks, long long start, char *block_ptr, 447unsigned int mode) 448{ 449 unsigned int file_fd, bytes, i; 450 unsigned int *block_list; 451 452 TRACE("write_file: regular file, blocks %d\n", blocks); 453 454 if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) { 455 ERROR("write_file: unable to malloc block list\n"); 456 return FALSE; 457 } 458 459 if(swap) { 460 unsigned int sblock_list[blocks]; 461 memcpy(sblock_list, block_ptr, blocks * sizeof(unsigned int)); 462 SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks); 463 } else 464 memcpy(block_list, block_ptr, blocks * sizeof(unsigned int)); 465 466 if((file_fd = open(pathname, O_CREAT | O_WRONLY | (force ? O_TRUNC : 0), (mode_t) mode & 0777)) == -1) { 467 ERROR("write_file: failed to create file %s, because %s\n", pathname, 468 strerror(errno)); 469 free(block_list); 470 return FALSE; 471 } 472 473 for(i = 0; i < blocks; i++) { 474 if((bytes = read_data_block(start, block_list[i], file_data)) == 0) { 475 ERROR("write_file: failed to read data block 0x%llx\n", start); 476 goto failure; 477 } 478 479 if(write(file_fd, file_data, bytes) < bytes) { 480 ERROR("write_file: failed to write data block 0x%llx\n", start); 481 goto failure; 482 } 483 484 start += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]); 485 } 486 487 if(frag_bytes != 0) { 488 char *fragment_data = s_ops.read_fragment(fragment); 489 490 if(fragment_data == NULL) 491 goto failure; 492 493 if(write(file_fd, fragment_data + offset, frag_bytes) < frag_bytes) { 494 ERROR("write_file: failed to write fragment %d\n", fragment); 495 goto failure; 496 } 497 } 498 499 close(file_fd); 500 return TRUE; 501 502failure: 503 close(file_fd); 504 free(block_list); 505 return FALSE; 506} 507 508 509int create_inode(char *pathname, unsigned int start_block, unsigned int offset) 510{ 511 long long start = sBlk.inode_table_start + start_block; 512 squashfs_inode_header header; 513 char *block_ptr; 514 int bytes = lookup_entry(inode_table_hash, start), file_fd; 515 516 TRACE("create_inode: pathname %s, start 0x%llx, offset %d\n", pathname, start, offset); 517 518 if(bytes == -1) { 519 ERROR("create_inode: inode block 0x%llx out of range!\n", start); 520 return FALSE; 521 } 522 block_ptr = inode_table + bytes + offset; 523 524 if(swap) { 525 squashfs_base_inode_header sinode; 526 memcpy(&sinode, block_ptr, sizeof(header.base)); 527 SQUASHFS_SWAP_BASE_INODE_HEADER(&header.base, &sinode, sizeof(squashfs_base_inode_header)); 528 } else 529 memcpy(&header.base, block_ptr, sizeof(header.base)); 530 531 if(created_inode[header.base.inode_number - 1]) { 532 TRACE("create_inode: hard link\n"); 533 if(force) 534 unlink(pathname); 535 536 if(link(created_inode[header.base.inode_number - 1], pathname) == -1) { 537 ERROR("create_inode: failed to create hardlink, because %s\n", strerror(errno)); 538 return FALSE; 539 } 540 541 return TRUE; 542 } 543 544 switch(header.base.inode_type) { 545 case SQUASHFS_FILE_TYPE: { 546 unsigned int frag_bytes; 547 unsigned int blocks; 548 unsigned int offset; 549 long long start; 550 squashfs_reg_inode_header *inode = &header.reg; 551 552 if(swap) { 553 squashfs_reg_inode_header sinode; 554 memcpy(&sinode, block_ptr, sizeof(sinode)); 555 SQUASHFS_SWAP_REG_INODE_HEADER(inode, &sinode); 556 } else 557 memcpy(inode, block_ptr, sizeof(*inode)); 558 559 frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 560 0 : inode->file_size % sBlk.block_size; 561 offset = inode->offset; 562 blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? 563 (inode->file_size + sBlk.block_size - 1) >> 564 sBlk.block_log : inode->file_size >> 565 sBlk.block_log; 566 start = inode->start_block; 567 568 TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks); 569 570 if(write_file(pathname, inode->fragment, frag_bytes, 571 offset, blocks, start, block_ptr + 572 sizeof(*inode), inode->mode)) { 573 set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, force); 574 file_count ++; 575 } 576 break; 577 } 578 case SQUASHFS_LREG_TYPE: { 579 unsigned int frag_bytes; 580 unsigned int blocks; 581 unsigned int offset; 582 long long start; 583 squashfs_lreg_inode_header *inode = &header.lreg; 584 585 if(swap) { 586 squashfs_lreg_inode_header sinode; 587 memcpy(&sinode, block_ptr, sizeof(sinode)); 588 SQUASHFS_SWAP_LREG_INODE_HEADER(inode, &sinode); 589 } else 590 memcpy(inode, block_ptr, sizeof(*inode)); 591 592 frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 593 0 : inode->file_size % sBlk.block_size; 594 offset = inode->offset; 595 blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? 596 (inode->file_size + sBlk.block_size - 1) >> 597 sBlk.block_log : inode->file_size >> 598 sBlk.block_log; 599 start = inode->start_block; 600 601 TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks); 602 603 if(write_file(pathname, inode->fragment, frag_bytes, 604 offset, blocks, start, block_ptr + 605 sizeof(*inode), inode->mode)) { 606 set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, force); 607 file_count ++; 608 } 609 break; 610 } 611 case SQUASHFS_SYMLINK_TYPE: { 612 squashfs_symlink_inode_header *inodep = &header.symlink; 613 char name[65536]; 614 615 if(swap) { 616 squashfs_symlink_inode_header sinodep; 617 memcpy(&sinodep, block_ptr, sizeof(sinodep)); 618 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, &sinodep); 619 } else 620 memcpy(inodep, block_ptr, sizeof(*inodep)); 621 622 TRACE("create_inode: symlink, symlink_size %d\n", inodep->symlink_size); 623 624 strncpy(name, block_ptr + sizeof(squashfs_symlink_inode_header), inodep->symlink_size); 625 name[inodep->symlink_size] = '\0'; 626 627 if(force) 628 unlink(pathname); 629 630 if(symlink(name, pathname) == -1) { 631 ERROR("create_inode: failed to create symlink %s, because %s\n", pathname, 632 strerror(errno)); 633 break; 634 } 635 636 if(root_process) { 637 uid_t uid_value = (uid_t) uid_table[inodep->uid]; 638 uid_t guid_value = inodep->guid == 639 SQUASHFS_GUIDS ? uid_value : (uid_t) 640 guid_table[inodep->guid]; 641 642 if(lchown(pathname, uid_value, guid_value) == -1) 643 ERROR("create_inode: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno)); 644 } 645 646 sym_count ++; 647 break; 648 } 649 case SQUASHFS_BLKDEV_TYPE: 650 case SQUASHFS_CHRDEV_TYPE: { 651 squashfs_dev_inode_header *inodep = &header.dev; 652 653 if(swap) { 654 squashfs_dev_inode_header sinodep; 655 memcpy(&sinodep, block_ptr, sizeof(sinodep)); 656 SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, &sinodep); 657 } else 658 memcpy(inodep, block_ptr, sizeof(*inodep)); 659 660 TRACE("create_inode: dev, rdev 0x%x\n", inodep->rdev); 661 662 if(root_process) { 663 if(force) 664 unlink(pathname); 665 666 if(mknod(pathname, inodep->inode_type == 667 SQUASHFS_CHRDEV_TYPE ? S_IFCHR : 668 S_IFBLK, makedev((inodep->rdev >> 8) 669 & 0xff, inodep->rdev & 0xff)) == -1) { 670 ERROR("create_inode: failed to create %s device %s, because %s\n", 671 inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block", 672 pathname, strerror(errno)); 673 break; 674 } 675 set_attributes(pathname, inodep->mode, inodep->uid, inodep->guid, inodep->mtime, TRUE); 676 dev_count ++; 677 } else 678 ERROR("create_inode: could not create %s device %s, because you're not superuser! %s\n", 679 inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block", 680 pathname, strerror(errno)); 681 break; 682 } 683 case SQUASHFS_FIFO_TYPE: 684 TRACE("create_inode: fifo\n"); 685 686 if(force) 687 unlink(pathname); 688 689 if(mknod(pathname, S_IFIFO, 0) == -1) { 690 ERROR("create_inode: failed to create fifo %s, because %s\n", 691 pathname, strerror(errno)); 692 break; 693 } 694 set_attributes(pathname, header.base.mode, header.base.uid, header.base.guid, 695 header.base.mtime, TRUE); 696 fifo_count ++; 697 break; 698 case SQUASHFS_SOCKET_TYPE: 699 TRACE("create_inode: socket\n"); 700 ERROR("create_inode: socket %s ignored\n", pathname); 701 break; 702 default: 703 ERROR("Unknown inode type %d in create_inode_table!\n", header.base.inode_type); 704 return FALSE; 705 } 706 707 created_inode[header.base.inode_number - 1] = strdup(pathname); 708 709 return TRUE; 710} 711 712 713int create_inode_2(char *pathname, unsigned int start_block, unsigned int offset) 714{ 715 long long start = sBlk.inode_table_start + start_block; 716 squashfs_inode_header_2 header; 717 char *block_ptr; 718 int bytes = lookup_entry(inode_table_hash, start), file_fd; 719 720 TRACE("create_inode: pathname %s, start 0x%llx, offset %d\n", pathname, start, offset); 721 722 if(bytes == -1) { 723 ERROR("create_inode: inode block 0x%llx out of range!\n", start); 724 return FALSE; 725 } 726 block_ptr = inode_table + bytes + offset; 727 728 if(swap) { 729 squashfs_base_inode_header_2 sinode; 730 memcpy(&sinode, block_ptr, sizeof(header.base)); 731 SQUASHFS_SWAP_BASE_INODE_HEADER_2(&header.base, &sinode, sizeof(squashfs_base_inode_header_2)); 732 } else 733 memcpy(&header.base, block_ptr, sizeof(header.base)); 734 735 switch(header.base.inode_type) { 736 case SQUASHFS_FILE_TYPE: { 737 unsigned int frag_bytes; 738 unsigned int blocks; 739 unsigned int offset; 740 long long start; 741 squashfs_reg_inode_header_2 *inode = &header.reg; 742 743 if(swap) { 744 squashfs_reg_inode_header_2 sinode; 745 memcpy(&sinode, block_ptr, sizeof(sinode)); 746 SQUASHFS_SWAP_REG_INODE_HEADER_2(inode, &sinode); 747 } else 748 memcpy(inode, block_ptr, sizeof(*inode)); 749 750 frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 751 0 : inode->file_size % sBlk.block_size; 752 offset = inode->offset; 753 blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? 754 (inode->file_size + sBlk.block_size - 1) >> 755 sBlk.block_log : inode->file_size >> 756 sBlk.block_log; 757 start = inode->start_block; 758 759 TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks); 760 761 if(write_file(pathname, inode->fragment, frag_bytes, 762 offset, blocks, start, block_ptr + 763 sizeof(*inode), inode->mode)) { 764 set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, force); 765 file_count ++; 766 } 767 break; 768 } 769 case SQUASHFS_SYMLINK_TYPE: { 770 squashfs_symlink_inode_header_2 *inodep = &header.symlink; 771 char name[65536]; 772 773 if(swap) { 774 squashfs_symlink_inode_header_2 sinodep; 775 memcpy(&sinodep, block_ptr, sizeof(sinodep)); 776 SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, &sinodep); 777 } else 778 memcpy(inodep, block_ptr, sizeof(*inodep)); 779 780 TRACE("create_inode: symlink, symlink_size %d\n", inodep->symlink_size); 781 782 strncpy(name, block_ptr + sizeof(squashfs_symlink_inode_header_2), inodep->symlink_size); 783 name[inodep->symlink_size] = '\0'; 784 785 if(force) 786 unlink(pathname); 787 788 if(symlink(name, pathname) == -1) { 789 ERROR("create_inode: failed to create symlink %s, because %s\n", pathname, 790 strerror(errno)); 791 break; 792 } 793 794 if(root_process) { 795 uid_t uid_value = (uid_t) uid_table[inodep->uid]; 796 uid_t guid_value = inodep->guid == 797 SQUASHFS_GUIDS ? uid_value : (uid_t) 798 guid_table[inodep->guid]; 799 800 if(lchown(pathname, uid_value, guid_value) == -1) 801 ERROR("create_inode: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno)); 802 } 803 804 sym_count ++; 805 break; 806 } 807 case SQUASHFS_BLKDEV_TYPE: 808 case SQUASHFS_CHRDEV_TYPE: { 809 squashfs_dev_inode_header_2 *inodep = &header.dev; 810 811 if(swap) { 812 squashfs_dev_inode_header_2 sinodep; 813 memcpy(&sinodep, block_ptr, sizeof(sinodep)); 814 SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, &sinodep); 815 } else 816 memcpy(inodep, block_ptr, sizeof(*inodep)); 817 818 TRACE("create_inode: dev, rdev 0x%x\n", inodep->rdev); 819 820 if(root_process) { 821 if(force) 822 unlink(pathname); 823 824 if(mknod(pathname, inodep->inode_type == 825 SQUASHFS_CHRDEV_TYPE ? S_IFCHR : 826 S_IFBLK, makedev((inodep->rdev >> 8) 827 & 0xff, inodep->rdev & 0xff)) == -1) { 828 ERROR("create_inode: failed to create %s device %s, because %s\n", 829 inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block", 830 pathname, strerror(errno)); 831 break; 832 } 833 set_attributes(pathname, inodep->mode, inodep->uid, inodep->guid, sBlk.mkfs_time, TRUE); 834 dev_count ++; 835 } else 836 ERROR("create_inode: could not create %s device %s, because you're not superuser! %s\n", 837 inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block", 838 pathname, strerror(errno)); 839 break; 840 } 841 case SQUASHFS_FIFO_TYPE: 842 TRACE("create_inode: fifo\n"); 843 844 if(force) 845 unlink(pathname); 846 847 if(mknod(pathname, S_IFIFO, 0) == -1) { 848 ERROR("create_inode: failed to create fifo %s, because %s\n", 849 pathname, strerror(errno)); 850 break; 851 } 852 set_attributes(pathname, header.base.mode, header.base.uid, header.base.guid, 853 sBlk.mkfs_time, TRUE); 854 fifo_count ++; 855 break; 856 case SQUASHFS_SOCKET_TYPE: 857 TRACE("create_inode: socket\n"); 858 ERROR("create_inode: socket %s ignored\n", pathname); 859 break; 860 default: 861 ERROR("Unknown inode type %d in create_inode_table!\n", header.base.inode_type); 862 return FALSE; 863 } 864 865 return TRUE; 866} 867 868 869void uncompress_directory_table(long long start, long long end) 870{ 871 int bytes = 0, size = 0, res; 872 873 while(start < end) { 874 if(size - bytes < SQUASHFS_METADATA_SIZE && (directory_table = 875 realloc(directory_table, size += 876 SQUASHFS_METADATA_SIZE)) == NULL) 877 EXIT_UNSQUASH("uncompress_directory_table: out of memory in realloc\n"); 878 TRACE("uncompress_directory_table: reading block 0x%llx\n", start); 879 add_entry(directory_table_hash, start, bytes); 880 if((res = read_block(start, &start, directory_table + bytes)) == 0) 881 EXIT_UNSQUASH("uncompress_directory_table: failed to read block\n"); 882 bytes += res; 883 } 884} 885 886 887#define DIR_ENT_SIZE 16 888 889struct dir_ent { 890 char name[SQUASHFS_NAME_LEN + 1]; 891 unsigned int start_block; 892 unsigned int offset; 893 unsigned int type; 894}; 895 896struct dir { 897 int dir_count; 898 int cur_entry; 899 unsigned int mode; 900 unsigned int uid; 901 unsigned int guid; 902 unsigned int mtime; 903 struct dir_ent *dirs; 904}; 905 906 907struct dir *squashfs_opendir(unsigned int block_start, unsigned int offset) 908{ 909 squashfs_dir_header dirh; 910 char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; 911 squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; 912 long long start = sBlk.inode_table_start + block_start; 913 char *block_ptr; 914 int bytes = lookup_entry(inode_table_hash, start); 915 squashfs_inode_header header; 916 int dir_count, size; 917 struct dir_ent *new_dir; 918 struct dir *dir; 919 920 TRACE("squashfs_opendir: inode start block %d, offset %d\n", block_start, offset); 921 922 if(bytes == -1) { 923 ERROR("squashfs_opendir: inode block %d not found!\n", block_start); 924 return NULL; 925 } 926 block_ptr = inode_table + bytes + offset; 927 928 if(swap) { 929 squashfs_dir_inode_header sinode; 930 memcpy(&sinode, block_ptr, sizeof(header.dir)); 931 SQUASHFS_SWAP_DIR_INODE_HEADER(&header.dir, &sinode); 932 } else 933 memcpy(&header.dir, block_ptr, sizeof(header.dir)); 934 935 switch(header.dir.inode_type) { 936 case SQUASHFS_DIR_TYPE: 937 block_start = header.dir.start_block; 938 offset = header.dir.offset; 939 size = header.dir.file_size; 940 break; 941 case SQUASHFS_LDIR_TYPE: 942 if(swap) { 943 squashfs_ldir_inode_header sinode; 944 memcpy(&sinode, block_ptr, sizeof(header.ldir)); 945 SQUASHFS_SWAP_LDIR_INODE_HEADER(&header.ldir, &sinode); 946 } else 947 memcpy(&header.ldir, block_ptr, sizeof(header.ldir)); 948 block_start = header.ldir.start_block; 949 offset = header.ldir.offset; 950 size = header.ldir.file_size; 951 break; 952 default: 953 ERROR("squashfs_opendir: inode not a directory\n"); 954 return NULL; 955 } 956 957 start = sBlk.directory_table_start + block_start; 958 bytes = lookup_entry(directory_table_hash, start); 959 960 if(bytes == -1) { 961 ERROR("squashfs_opendir: directory block %d not found!\n", block_start); 962 return NULL; 963 } 964 bytes += offset; 965 size += bytes - 3; 966 967 if((dir = malloc(sizeof(struct dir))) == NULL) { 968 ERROR("squashfs_opendir: malloc failed!\n"); 969 return NULL; 970 } 971 972 dir->dir_count = 0; 973 dir->cur_entry = 0; 974 dir->mode = header.dir.mode; 975 dir->uid = header.dir.uid; 976 dir->guid = header.dir.guid; 977 dir->mtime = header.dir.mtime; 978 dir->dirs = NULL; 979 980 while(bytes < size) { 981 if(swap) { 982 squashfs_dir_header sdirh; 983 memcpy(&sdirh, directory_table + bytes, sizeof(sdirh)); 984 SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); 985 } else 986 memcpy(&dirh, directory_table + bytes, sizeof(dirh)); 987 988 dir_count = dirh.count + 1; 989 TRACE("squashfs_opendir: Read directory header @ byte position %d, %d directory entries\n", bytes, dir_count); 990 bytes += sizeof(dirh); 991 992 while(dir_count--) { 993 if(swap) { 994 squashfs_dir_entry sdire; 995 memcpy(&sdire, directory_table + bytes, sizeof(sdire)); 996 SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); 997 } else 998 memcpy(dire, directory_table + bytes, sizeof(dire)); 999 bytes += sizeof(*dire); 1000 1001 memcpy(dire->name, directory_table + bytes, dire->size + 1); 1002 dire->name[dire->size + 1] = '\0'; 1003 TRACE("squashfs_opendir: directory entry %s, inode %d:%d, type %d\n", dire->name, dirh.start_block, dire->offset, dire->type); 1004 if((dir->dir_count % DIR_ENT_SIZE) == 0) { 1005 if((new_dir = realloc(dir->dirs, (dir->dir_count + DIR_ENT_SIZE) * sizeof(struct dir_ent))) == NULL) { 1006 ERROR("squashfs_opendir: realloc failed!\n"); 1007 free(dir->dirs); 1008 free(dir); 1009 return NULL; 1010 } 1011 dir->dirs = new_dir; 1012 } 1013 strcpy(dir->dirs[dir->dir_count].name, dire->name); 1014 dir->dirs[dir->dir_count].start_block = dirh.start_block; 1015 dir->dirs[dir->dir_count].offset = dire->offset; 1016 dir->dirs[dir->dir_count].type = dire->type; 1017 dir->dir_count ++; 1018 bytes += dire->size + 1; 1019 } 1020 } 1021 1022 return dir; 1023} 1024 1025 1026struct dir *squashfs_opendir_2(unsigned int block_start, unsigned int offset) 1027{ 1028 squashfs_dir_header_2 dirh; 1029 char buffer[sizeof(squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1]; 1030 squashfs_dir_entry_2 *dire = (squashfs_dir_entry_2 *) buffer; 1031 long long start = sBlk.inode_table_start + block_start; 1032 char *block_ptr; 1033 int bytes = lookup_entry(inode_table_hash, start); 1034 squashfs_inode_header_2 header; 1035 int dir_count, size; 1036 struct dir_ent *new_dir; 1037 struct dir *dir; 1038 1039 TRACE("squashfs_opendir: inode start block %d, offset %d\n", block_start, offset); 1040 1041 if(bytes == -1) { 1042 ERROR("squashfs_opendir: inode block %d not found!\n", block_start); 1043 return NULL; 1044 } 1045 block_ptr = inode_table + bytes + offset; 1046 1047 if(swap) { 1048 squashfs_dir_inode_header_2 sinode; 1049 memcpy(&sinode, block_ptr, sizeof(header.dir)); 1050 SQUASHFS_SWAP_DIR_INODE_HEADER_2(&header.dir, &sinode); 1051 } else 1052 memcpy(&header.dir, block_ptr, sizeof(header.dir)); 1053 1054 switch(header.dir.inode_type) { 1055 case SQUASHFS_DIR_TYPE: 1056 block_start = header.dir.start_block; 1057 offset = header.dir.offset; 1058 size = header.dir.file_size; 1059 break; 1060 case SQUASHFS_LDIR_TYPE: 1061 if(swap) { 1062 squashfs_ldir_inode_header_2 sinode; 1063 memcpy(&sinode, block_ptr, sizeof(header.ldir)); 1064 SQUASHFS_SWAP_LDIR_INODE_HEADER_2(&header.ldir, &sinode); 1065 } else 1066 memcpy(&header.ldir, block_ptr, sizeof(header.ldir)); 1067 block_start = header.ldir.start_block; 1068 offset = header.ldir.offset; 1069 size = header.ldir.file_size; 1070 break; 1071 default: 1072 ERROR("squashfs_opendir: inode not a directory\n"); 1073 return NULL; 1074 } 1075 1076 start = sBlk.directory_table_start + block_start; 1077 bytes = lookup_entry(directory_table_hash, start); 1078 1079 if(bytes == -1) { 1080 ERROR("squashfs_opendir: directory block %d not found!\n", block_start); 1081 return NULL; 1082 } 1083 bytes += offset; 1084 size += bytes; 1085 1086 if((dir = malloc(sizeof(struct dir))) == NULL) { 1087 ERROR("squashfs_opendir: malloc failed!\n"); 1088 return NULL; 1089 } 1090 1091 dir->dir_count = 0; 1092 dir->cur_entry = 0; 1093 dir->mode = header.dir.mode; 1094 dir->uid = header.dir.uid; 1095 dir->guid = header.dir.guid; 1096 dir->mtime = header.dir.mtime; 1097 dir->dirs = NULL; 1098 1099 while(bytes < size) { 1100 if(swap) { 1101 squashfs_dir_header_2 sdirh; 1102 memcpy(&sdirh, directory_table + bytes, sizeof(sdirh)); 1103 SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); 1104 } else 1105 memcpy(&dirh, directory_table + bytes, sizeof(dirh)); 1106 1107 dir_count = dirh.count + 1; 1108 TRACE("squashfs_opendir: Read directory header @ byte position %d, %d directory entries\n", bytes, dir_count); 1109 bytes += sizeof(dirh); 1110 1111 while(dir_count--) { 1112 if(swap) { 1113 squashfs_dir_entry_2 sdire; 1114 memcpy(&sdire, directory_table + bytes, sizeof(sdire)); 1115 SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); 1116 } else 1117 memcpy(dire, directory_table + bytes, sizeof(dire)); 1118 bytes += sizeof(*dire); 1119 1120 memcpy(dire->name, directory_table + bytes, dire->size + 1); 1121 dire->name[dire->size + 1] = '\0'; 1122 TRACE("squashfs_opendir: directory entry %s, inode %d:%d, type %d\n", dire->name, dirh.start_block, dire->offset, dire->type); 1123 if((dir->dir_count % DIR_ENT_SIZE) == 0) { 1124 if((new_dir = realloc(dir->dirs, (dir->dir_count + DIR_ENT_SIZE) * sizeof(struct dir_ent))) == NULL) { 1125 ERROR("squashfs_opendir: realloc failed!\n"); 1126 free(dir->dirs); 1127 free(dir); 1128 return NULL; 1129 } 1130 dir->dirs = new_dir; 1131 } 1132 strcpy(dir->dirs[dir->dir_count].name, dire->name); 1133 dir->dirs[dir->dir_count].start_block = dirh.start_block; 1134 dir->dirs[dir->dir_count].offset = dire->offset; 1135 dir->dirs[dir->dir_count].type = dire->type; 1136 dir->dir_count ++; 1137 bytes += dire->size + 1; 1138 } 1139 } 1140 1141 return dir; 1142} 1143 1144 1145int squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block, 1146unsigned int *offset, unsigned int *type) 1147{ 1148 if(dir->cur_entry == dir->dir_count) 1149 return FALSE; 1150 1151 *name = dir->dirs[dir->cur_entry].name; 1152 *start_block = dir->dirs[dir->cur_entry].start_block; 1153 *offset = dir->dirs[dir->cur_entry].offset; 1154 *type = dir->dirs[dir->cur_entry].type; 1155 dir->cur_entry ++; 1156 1157 return TRUE; 1158} 1159 1160 1161void squashfs_closedir(struct dir *dir) 1162{ 1163 free(dir->dirs); 1164 free(dir); 1165} 1166 1167 1168char *get_component(char *target, char *targname) 1169{ 1170 while(*target == '/') 1171 *target ++; 1172 1173 while(*target != '/' && *target!= '\0') 1174 *targname ++ = *target ++; 1175 1176 *targname = '\0'; 1177 1178 return target; 1179} 1180 1181 1182int matches(char *targname, char *name) 1183{ 1184 if(*targname == '\0' || strcmp(targname, name) == 0) 1185 return TRUE; 1186 1187 return FALSE; 1188} 1189 1190 1191int dir_scan(char *parent_name, unsigned int start_block, unsigned int offset, char *target) 1192{ 1193 struct dir *dir = s_ops.squashfs_opendir(start_block, offset); 1194 unsigned int type; 1195 char *name, pathname[1024]; 1196 char targname[1024]; 1197 1198 target = get_component(target, targname); 1199 1200 if(dir == NULL) { 1201 ERROR("dir_scan: Failed to read directory %s (%x:%x)\n", parent_name, start_block, offset); 1202 return FALSE; 1203 } 1204 1205 if(!lsonly && mkdir(parent_name, (mode_t) dir->mode) == -1 && (!force || errno != EEXIST)) { 1206 ERROR("dir_scan: failed to open directory %s, because %s\n", parent_name, strerror(errno)); 1207 return FALSE; 1208 } 1209 1210 while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) { 1211 TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type); 1212 1213 1214 if(!matches(targname, name)) 1215 continue; 1216 1217 strcat(strcat(strcpy(pathname, parent_name), "/"), name); 1218 1219 if(lsonly || info) 1220 printf("%s\n", pathname); 1221 1222 if(type == SQUASHFS_DIR_TYPE) 1223 dir_scan(pathname, start_block, offset, target); 1224 else 1225 if(!lsonly) 1226 s_ops.create_inode(pathname, start_block, offset); 1227 } 1228 1229 !lsonly && set_attributes(parent_name, dir->mode, dir->uid, dir->guid, dir->mtime, force); 1230 1231 squashfs_closedir(dir); 1232 dir_count ++; 1233 1234 return TRUE; 1235} 1236 1237 1238int read_super(char *source) 1239{ 1240 squashfs_super_block sblk; 1241 1242 read_bytes(SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk); 1243 1244 /* Check it is a SQUASHFS superblock */ 1245 swap = 0; 1246 switch (sBlk.s_magic) { 1247 case SQUASHFS_MAGIC: 1248 case SQUASHFS_MAGIC_LZMA: 1249 break; 1250 case SQUASHFS_MAGIC_SWAP: 1251 case SQUASHFS_MAGIC_LZMA_SWAP: 1252 ERROR("Reading a different endian SQUASHFS filesystem on %s\n", source); 1253 SQUASHFS_SWAP_SUPER_BLOCK(&sblk, &sBlk); 1254 memcpy(&sBlk, &sblk, sizeof(squashfs_super_block)); 1255 swap = 1; 1256 default: 1257 ERROR("Can't find a SQUASHFS superblock on %s\n", source); 1258 goto failed_mount; 1259 } 1260 1261 /* Check the MAJOR & MINOR versions */ 1262 if(sBlk.s_major == 2) { 1263 sBlk.bytes_used = sBlk.bytes_used_2; 1264 sBlk.uid_start = sBlk.uid_start_2; 1265 sBlk.guid_start = sBlk.guid_start_2; 1266 sBlk.inode_table_start = sBlk.inode_table_start_2; 1267 sBlk.directory_table_start = sBlk.directory_table_start_2; 1268 sBlk.fragment_table_start = sBlk.fragment_table_start_2; 1269 1270 s_ops.squashfs_opendir = squashfs_opendir_2; 1271 s_ops.read_fragment = read_fragment_2; 1272 s_ops.read_fragment_table = read_fragment_table_2; 1273 s_ops.create_inode = create_inode_2; 1274 } else if(sBlk.s_major == 3 && sBlk.s_minor == 0) { 1275 s_ops.squashfs_opendir = squashfs_opendir; 1276 s_ops.read_fragment = read_fragment; 1277 s_ops.read_fragment_table = read_fragment_table; 1278 s_ops.create_inode = create_inode; 1279 } else { 1280 ERROR("Major/Minor mismatch, filesystem on %s is (%d:%d)\n", 1281 source, sBlk.s_major, sBlk.s_minor); 1282 ERROR("I support Squashfs 2.x and 3.0 filesystems!\n"); 1283 goto failed_mount; 1284 } 1285 1286#if __BYTE_ORDER == __BIG_ENDIAN 1287 TRACE("Found a valid %s endian SQUASHFS %d:%d superblock on %s.\n", swap ? "little" : "big", sBlk.s_major, sBlk.s_minor, source); 1288#else 1289 TRACE("Found a valid %s endian SQUASHFS %d:%d superblock on %s.\n", swap ? "big" : "little", sBlk.s_major, sBlk.s_minor, source); 1290#endif 1291 1292 TRACE("\tInodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags) ? "un" : ""); 1293 TRACE("\tData is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags) ? "un" : ""); 1294 TRACE("\tFragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags) ? "un" : ""); 1295 TRACE("\tCheck data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk.flags) ? "" : "not"); 1296 TRACE("\tFragments are %s present in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk.flags) ? "not" : ""); 1297 TRACE("\tAlways_use_fragments option is %s specified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags) ? "" : "not"); 1298 TRACE("\tDuplicates are %s removed\n", SQUASHFS_DUPLICATES(sBlk.flags) ? "" : "not"); 1299 TRACE("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk.bytes_used / 1024.0, sBlk.bytes_used / (1024.0 * 1024.0)); 1300 TRACE("\tBlock size %d\n", sBlk.block_size); 1301 TRACE("\tNumber of fragments %d\n", sBlk.fragments); 1302 TRACE("\tNumber of inodes %d\n", sBlk.inodes); 1303 TRACE("\tNumber of uids %d\n", sBlk.no_uids); 1304 TRACE("\tNumber of gids %d\n", sBlk.no_guids); 1305 TRACE("sBlk.inode_table_start 0x%llx\n", sBlk.inode_table_start); 1306 TRACE("sBlk.directory_table_start 0x%llx\n", sBlk.directory_table_start); 1307 TRACE("sBlk.uid_start 0x%llx\n", sBlk.uid_start); 1308 TRACE("sBlk.fragment_table_start 0x%llx\n\n", sBlk.fragment_table_start); 1309 1310 return TRUE; 1311 1312failed_mount: 1313 return FALSE; 1314} 1315 1316 1317#define VERSION() \ 1318 printf("unsquashfs version 1.3 (2007/01/02)\n");\ 1319 printf("copyright (C) 2007 Phillip Lougher <phillip@lougher.org.uk>\n\n"); \ 1320 printf("This program is free software; you can redistribute it and/or\n");\ 1321 printf("modify it under the terms of the GNU General Public License\n");\ 1322 printf("as published by the Free Software Foundation; either version 2,\n");\ 1323 printf("or (at your option) any later version.\n\n");\ 1324 printf("This program is distributed in the hope that it will be useful,\n");\ 1325 printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\ 1326 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");\ 1327 printf("GNU General Public License for more details.\n"); 1328int main(int argc, char *argv[]) 1329{ 1330 char *dest = "squashfs-root"; 1331 int i, version = FALSE; 1332 char *target = ""; 1333 1334 if((root_process = (geteuid() == 0))) 1335 umask(0); 1336 1337 for(i = 1; i < argc; i++) { 1338 if(*argv[i] != '-') 1339 break; 1340 if(strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { 1341 VERSION(); 1342 version = TRUE; 1343 } else if(strcmp(argv[i], "-info") == 0 || strcmp(argv[i], "-i") == 0) 1344 info = TRUE; 1345 else if(strcmp(argv[i], "-ls") == 0 || strcmp(argv[i], "-l") == 0) 1346 lsonly = TRUE; 1347 else if(strcmp(argv[i], "-dest") == 0 || strcmp(argv[i], "-d") == 0) { 1348 if(++i == argc) 1349 goto options; 1350 dest = argv[i]; 1351 } else if(strcmp(argv[i], "-force") == 0 || strcmp(argv[i], "-f") == 0) 1352 force = TRUE; 1353 } 1354 1355 if(i == argc) { 1356 if(!version) { 1357options: 1358 ERROR("SYNTAX: %s [options] filesystem [directory or file to extract]\n", argv[0]); 1359 ERROR("\t-v[ersion]\t\tprint version, licence and copyright information\n"); 1360 ERROR("\t-i[nfo]\t\t\tprint files as they are unsquashed\n"); 1361 ERROR("\t-l[s]\t\t\tlist filesystem only\n"); 1362 ERROR("\t-d[est] <pathname>\tunsquash to <pathname>, default \"squashfs-root\"\n"); 1363 ERROR("\t-f[orce]\t\tif file already exists then overwrite\n"); 1364 } 1365 exit(1); 1366 } 1367 1368 if((i + 1) < argc) 1369 target = argv[i + 1]; 1370 1371 if((fd = open(argv[i], O_RDONLY)) == -1) { 1372 ERROR("Could not open %s, because %s\n", argv[i], strerror(errno)); 1373 exit(1); 1374 } 1375 1376 if(read_super(argv[i]) == FALSE) 1377 exit(1); 1378 1379 block_size = sBlk.block_size; 1380 if((fragment_data = malloc(block_size)) == NULL) 1381 EXIT_UNSQUASH("failed to allocate fragment_data\n"); 1382 1383 if((file_data = malloc(block_size)) == NULL) 1384 EXIT_UNSQUASH("failed to allocate file_data"); 1385 1386 if((data = malloc(block_size)) == NULL) 1387 EXIT_UNSQUASH("failed to allocate datan\n"); 1388 1389 if((created_inode = malloc(sBlk.inodes * sizeof(char *))) == NULL) 1390 EXIT_UNSQUASH("failed to allocate created_inode\n"); 1391 1392 memset(created_inode, 0, sBlk.inodes * sizeof(char *)); 1393 1394 read_uids_guids(); 1395 s_ops.read_fragment_table(); 1396 uncompress_inode_table(sBlk.inode_table_start, sBlk.directory_table_start); 1397 uncompress_directory_table(sBlk.directory_table_start, sBlk.fragment_table_start); 1398 1399 dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode), SQUASHFS_INODE_OFFSET(sBlk.root_inode), target); 1400 1401 if(!lsonly) { 1402 printf("\n"); 1403 printf("created %d files\n", file_count); 1404 printf("created %d directories\n", dir_count); 1405 printf("created %d symlinks\n", sym_count); 1406 printf("created %d devices\n", dev_count); 1407 printf("created %d fifos\n", fifo_count); 1408 } 1409 return 0; 1410} 1411