1/* 2 * Unsquash 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, 2011, 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 * unsquashfs.c 24 */ 25 26#include "unsquashfs.h" 27#include "squashfs_swap.h" 28#include "squashfs_compat.h" 29#include "compressor.h" 30#include "xattr.h" 31#include "unsquashfs_info.h" 32#include "stdarg.h" 33 34#ifndef linux 35#include <sys/sysctl.h> 36#else 37#include <sys/sysinfo.h> 38#endif 39 40#include <sys/types.h> 41#include <sys/time.h> 42#include <sys/resource.h> 43#include <limits.h> 44#include <ctype.h> 45 46struct cache *fragment_cache, *data_cache; 47struct queue *to_reader, *to_inflate, *to_writer, *from_writer; 48pthread_t *thread, *inflator_thread; 49pthread_mutex_t fragment_mutex; 50 51/* user options that control parallelisation */ 52int processors = -1; 53 54struct super_block sBlk; 55squashfs_operations s_ops; 56struct compressor *comp; 57 58int bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0, 59 dev_count = 0, fifo_count = 0; 60char *inode_table = NULL, *directory_table = NULL; 61struct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536]; 62int fd; 63unsigned int *uid_table, *guid_table; 64unsigned int cached_frag = SQUASHFS_INVALID_FRAG; 65char *fragment_data; 66char *file_data; 67char *data; 68unsigned int block_size; 69unsigned int block_log; 70int lsonly = FALSE, info = FALSE, force = FALSE, short_ls = TRUE; 71int use_regex = FALSE; 72char **created_inode; 73int root_process; 74int columns; 75int rotate = 0; 76pthread_mutex_t screen_mutex; 77int progress = TRUE, progress_enabled = FALSE; 78unsigned int total_blocks = 0, total_files = 0, total_inodes = 0; 79unsigned int cur_blocks = 0; 80int inode_number = 1; 81int no_xattrs = XATTR_DEF; 82int user_xattrs = FALSE; 83 84int lookup_type[] = { 85 0, 86 S_IFDIR, 87 S_IFREG, 88 S_IFLNK, 89 S_IFBLK, 90 S_IFCHR, 91 S_IFIFO, 92 S_IFSOCK, 93 S_IFDIR, 94 S_IFREG, 95 S_IFLNK, 96 S_IFBLK, 97 S_IFCHR, 98 S_IFIFO, 99 S_IFSOCK 100}; 101 102struct test table[] = { 103 { S_IFMT, S_IFSOCK, 0, 's' }, 104 { S_IFMT, S_IFLNK, 0, 'l' }, 105 { S_IFMT, S_IFBLK, 0, 'b' }, 106 { S_IFMT, S_IFDIR, 0, 'd' }, 107 { S_IFMT, S_IFCHR, 0, 'c' }, 108 { S_IFMT, S_IFIFO, 0, 'p' }, 109 { S_IRUSR, S_IRUSR, 1, 'r' }, 110 { S_IWUSR, S_IWUSR, 2, 'w' }, 111 { S_IRGRP, S_IRGRP, 4, 'r' }, 112 { S_IWGRP, S_IWGRP, 5, 'w' }, 113 { S_IROTH, S_IROTH, 7, 'r' }, 114 { S_IWOTH, S_IWOTH, 8, 'w' }, 115 { S_IXUSR | S_ISUID, S_IXUSR | S_ISUID, 3, 's' }, 116 { S_IXUSR | S_ISUID, S_ISUID, 3, 'S' }, 117 { S_IXUSR | S_ISUID, S_IXUSR, 3, 'x' }, 118 { S_IXGRP | S_ISGID, S_IXGRP | S_ISGID, 6, 's' }, 119 { S_IXGRP | S_ISGID, S_ISGID, 6, 'S' }, 120 { S_IXGRP | S_ISGID, S_IXGRP, 6, 'x' }, 121 { S_IXOTH | S_ISVTX, S_IXOTH | S_ISVTX, 9, 't' }, 122 { S_IXOTH | S_ISVTX, S_ISVTX, 9, 'T' }, 123 { S_IXOTH | S_ISVTX, S_IXOTH, 9, 'x' }, 124 { 0, 0, 0, 0} 125}; 126 127void progress_bar(long long current, long long max, int columns); 128 129#define MAX_LINE 16384 130 131void prep_exit() 132{ 133} 134 135 136void sigwinch_handler() 137{ 138 struct winsize winsize; 139 140 if(ioctl(1, TIOCGWINSZ, &winsize) == -1) { 141 if(isatty(STDOUT_FILENO)) 142 ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 " 143 "columns\n"); 144 columns = 80; 145 } else 146 columns = winsize.ws_col; 147} 148 149 150void sigalrm_handler() 151{ 152 rotate = (rotate + 1) % 4; 153} 154 155 156int add_overflow(int a, int b) 157{ 158 return (INT_MAX - a) < b; 159} 160 161 162int shift_overflow(int a, int shift) 163{ 164 return (INT_MAX >> shift) < a; 165} 166 167 168int multiply_overflow(int a, int multiplier) 169{ 170 return (INT_MAX / multiplier) < a; 171} 172 173 174struct queue *queue_init(int size) 175{ 176 struct queue *queue = malloc(sizeof(struct queue)); 177 178 if(queue == NULL) 179 EXIT_UNSQUASH("Out of memory in queue_init\n"); 180 181 if(add_overflow(size, 1) || 182 multiply_overflow(size + 1, sizeof(void *))) 183 EXIT_UNSQUASH("Size too large in queue_init\n"); 184 185 queue->data = malloc(sizeof(void *) * (size + 1)); 186 if(queue->data == NULL) 187 EXIT_UNSQUASH("Out of memory in queue_init\n"); 188 189 queue->size = size + 1; 190 queue->readp = queue->writep = 0; 191 pthread_mutex_init(&queue->mutex, NULL); 192 pthread_cond_init(&queue->empty, NULL); 193 pthread_cond_init(&queue->full, NULL); 194 195 return queue; 196} 197 198 199void queue_put(struct queue *queue, void *data) 200{ 201 int nextp; 202 203 pthread_mutex_lock(&queue->mutex); 204 205 while((nextp = (queue->writep + 1) % queue->size) == queue->readp) 206 pthread_cond_wait(&queue->full, &queue->mutex); 207 208 queue->data[queue->writep] = data; 209 queue->writep = nextp; 210 pthread_cond_signal(&queue->empty); 211 pthread_mutex_unlock(&queue->mutex); 212} 213 214 215void *queue_get(struct queue *queue) 216{ 217 void *data; 218 pthread_mutex_lock(&queue->mutex); 219 220 while(queue->readp == queue->writep) 221 pthread_cond_wait(&queue->empty, &queue->mutex); 222 223 data = queue->data[queue->readp]; 224 queue->readp = (queue->readp + 1) % queue->size; 225 pthread_cond_signal(&queue->full); 226 pthread_mutex_unlock(&queue->mutex); 227 228 return data; 229} 230 231 232void dump_queue(struct queue *queue) 233{ 234 pthread_mutex_lock(&queue->mutex); 235 236 printf("Max size %d, size %d%s\n", queue->size - 1, 237 queue->readp <= queue->writep ? queue->writep - queue->readp : 238 queue->size - queue->readp + queue->writep, 239 queue->readp == queue->writep ? " (EMPTY)" : 240 ((queue->writep + 1) % queue->size) == queue->readp ? 241 " (FULL)" : ""); 242 243 pthread_mutex_unlock(&queue->mutex); 244} 245 246 247/* Called with the cache mutex held */ 248void insert_hash_table(struct cache *cache, struct cache_entry *entry) 249{ 250 int hash = CALCULATE_HASH(entry->block); 251 252 entry->hash_next = cache->hash_table[hash]; 253 cache->hash_table[hash] = entry; 254 entry->hash_prev = NULL; 255 if(entry->hash_next) 256 entry->hash_next->hash_prev = entry; 257} 258 259 260/* Called with the cache mutex held */ 261void remove_hash_table(struct cache *cache, struct cache_entry *entry) 262{ 263 if(entry->hash_prev) 264 entry->hash_prev->hash_next = entry->hash_next; 265 else 266 cache->hash_table[CALCULATE_HASH(entry->block)] = 267 entry->hash_next; 268 if(entry->hash_next) 269 entry->hash_next->hash_prev = entry->hash_prev; 270 271 entry->hash_prev = entry->hash_next = NULL; 272} 273 274 275/* Called with the cache mutex held */ 276void insert_free_list(struct cache *cache, struct cache_entry *entry) 277{ 278 if(cache->free_list) { 279 entry->free_next = cache->free_list; 280 entry->free_prev = cache->free_list->free_prev; 281 cache->free_list->free_prev->free_next = entry; 282 cache->free_list->free_prev = entry; 283 } else { 284 cache->free_list = entry; 285 entry->free_prev = entry->free_next = entry; 286 } 287} 288 289 290/* Called with the cache mutex held */ 291void remove_free_list(struct cache *cache, struct cache_entry *entry) 292{ 293 if(entry->free_prev == NULL || entry->free_next == NULL) 294 /* not in free list */ 295 return; 296 else if(entry->free_prev == entry && entry->free_next == entry) { 297 /* only this entry in the free list */ 298 cache->free_list = NULL; 299 } else { 300 /* more than one entry in the free list */ 301 entry->free_next->free_prev = entry->free_prev; 302 entry->free_prev->free_next = entry->free_next; 303 if(cache->free_list == entry) 304 cache->free_list = entry->free_next; 305 } 306 307 entry->free_prev = entry->free_next = NULL; 308} 309 310 311struct cache *cache_init(int buffer_size, int max_buffers) 312{ 313 struct cache *cache = malloc(sizeof(struct cache)); 314 315 if(cache == NULL) 316 EXIT_UNSQUASH("Out of memory in cache_init\n"); 317 318 cache->max_buffers = max_buffers; 319 cache->buffer_size = buffer_size; 320 cache->count = 0; 321 cache->used = 0; 322 cache->free_list = NULL; 323 memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536); 324 cache->wait_free = FALSE; 325 cache->wait_pending = FALSE; 326 pthread_mutex_init(&cache->mutex, NULL); 327 pthread_cond_init(&cache->wait_for_free, NULL); 328 pthread_cond_init(&cache->wait_for_pending, NULL); 329 330 return cache; 331} 332 333 334struct cache_entry *cache_get(struct cache *cache, long long block, int size) 335{ 336 /* 337 * Get a block out of the cache. If the block isn't in the cache 338 * it is added and queued to the reader() and inflate() threads for 339 * reading off disk and decompression. The cache grows until max_blocks 340 * is reached, once this occurs existing discarded blocks on the free 341 * list are reused 342 */ 343 int hash = CALCULATE_HASH(block); 344 struct cache_entry *entry; 345 346 pthread_mutex_lock(&cache->mutex); 347 348 for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next) 349 if(entry->block == block) 350 break; 351 352 if(entry) { 353 /* 354 * found the block in the cache. If the block is currently unused 355 * remove it from the free list and increment cache used count. 356 */ 357 if(entry->used == 0) { 358 cache->used ++; 359 remove_free_list(cache, entry); 360 } 361 entry->used ++; 362 pthread_mutex_unlock(&cache->mutex); 363 } else { 364 /* 365 * not in the cache 366 * 367 * first try to allocate new block 368 */ 369 if(cache->count < cache->max_buffers) { 370 entry = malloc(sizeof(struct cache_entry)); 371 if(entry == NULL) 372 EXIT_UNSQUASH("Out of memory in cache_get\n"); 373 entry->data = malloc(cache->buffer_size); 374 if(entry->data == NULL) 375 EXIT_UNSQUASH("Out of memory in cache_get\n"); 376 entry->cache = cache; 377 entry->free_prev = entry->free_next = NULL; 378 cache->count ++; 379 } else { 380 /* 381 * try to get from free list 382 */ 383 while(cache->free_list == NULL) { 384 cache->wait_free = TRUE; 385 pthread_cond_wait(&cache->wait_for_free, 386 &cache->mutex); 387 } 388 entry = cache->free_list; 389 remove_free_list(cache, entry); 390 remove_hash_table(cache, entry); 391 } 392 393 /* 394 * Initialise block and insert into the hash table. 395 * Increment used which tracks how many buffers in the 396 * cache are actively in use (the other blocks, count - used, 397 * are in the cache and available for lookup, but can also be 398 * re-used). 399 */ 400 entry->block = block; 401 entry->size = size; 402 entry->used = 1; 403 entry->error = FALSE; 404 entry->pending = TRUE; 405 insert_hash_table(cache, entry); 406 cache->used ++; 407 408 /* 409 * queue to read thread to read and ultimately (via the 410 * decompress threads) decompress the buffer 411 */ 412 pthread_mutex_unlock(&cache->mutex); 413 queue_put(to_reader, entry); 414 } 415 416 return entry; 417} 418 419 420void cache_block_ready(struct cache_entry *entry, int error) 421{ 422 /* 423 * mark cache entry as being complete, reading and (if necessary) 424 * decompression has taken place, and the buffer is valid for use. 425 * If an error occurs reading or decompressing, the buffer also 426 * becomes ready but with an error... 427 */ 428 pthread_mutex_lock(&entry->cache->mutex); 429 entry->pending = FALSE; 430 entry->error = error; 431 432 /* 433 * if the wait_pending flag is set, one or more threads may be waiting 434 * on this buffer 435 */ 436 if(entry->cache->wait_pending) { 437 entry->cache->wait_pending = FALSE; 438 pthread_cond_broadcast(&entry->cache->wait_for_pending); 439 } 440 441 pthread_mutex_unlock(&entry->cache->mutex); 442} 443 444 445void cache_block_wait(struct cache_entry *entry) 446{ 447 /* 448 * wait for this cache entry to become ready, when reading and (if 449 * necessary) decompression has taken place 450 */ 451 pthread_mutex_lock(&entry->cache->mutex); 452 453 while(entry->pending) { 454 entry->cache->wait_pending = TRUE; 455 pthread_cond_wait(&entry->cache->wait_for_pending, 456 &entry->cache->mutex); 457 } 458 459 pthread_mutex_unlock(&entry->cache->mutex); 460} 461 462 463void cache_block_put(struct cache_entry *entry) 464{ 465 /* 466 * finished with this cache entry, once the usage count reaches zero it 467 * can be reused and is put onto the free list. As it remains 468 * accessible via the hash table it can be found getting a new lease of 469 * life before it is reused. 470 */ 471 pthread_mutex_lock(&entry->cache->mutex); 472 473 entry->used --; 474 if(entry->used == 0) { 475 insert_free_list(entry->cache, entry); 476 entry->cache->used --; 477 478 /* 479 * if the wait_free flag is set, one or more threads may be 480 * waiting on this buffer 481 */ 482 if(entry->cache->wait_free) { 483 entry->cache->wait_free = FALSE; 484 pthread_cond_broadcast(&entry->cache->wait_for_free); 485 } 486 } 487 488 pthread_mutex_unlock(&entry->cache->mutex); 489} 490 491 492void dump_cache(struct cache *cache) 493{ 494 pthread_mutex_lock(&cache->mutex); 495 496 printf("Max buffers %d, Current size %d, Used %d, %s\n", 497 cache->max_buffers, cache->count, cache->used, 498 cache->free_list ? "Free buffers" : "No free buffers"); 499 500 pthread_mutex_unlock(&cache->mutex); 501} 502 503 504char *modestr(char *str, int mode) 505{ 506 int i; 507 508 strcpy(str, "----------"); 509 510 for(i = 0; table[i].mask != 0; i++) { 511 if((mode & table[i].mask) == table[i].value) 512 str[table[i].position] = table[i].mode; 513 } 514 515 return str; 516} 517 518 519#define TOTALCHARS 25 520int print_filename(char *pathname, struct inode *inode) 521{ 522 char str[11], dummy[12], dummy2[12]; /* overflow safe */ 523 char *userstr, *groupstr; 524 int padchars; 525 struct passwd *user; 526 struct group *group; 527 struct tm *t; 528 529 if(short_ls) { 530 printf("%s\n", pathname); 531 return 1; 532 } 533 534 user = getpwuid(inode->uid); 535 if(user == NULL) { 536 int res = snprintf(dummy, 12, "%d", inode->uid); 537 if(res < 0) 538 EXIT_UNSQUASH("snprintf failed in print_filename()\n"); 539 else if(res >= 12) 540 /* unsigned int shouldn't ever need more than 11 bytes 541 * (including terminating '\0') to print in base 10 */ 542 userstr = "*"; 543 else 544 userstr = dummy; 545 } else 546 userstr = user->pw_name; 547 548 group = getgrgid(inode->gid); 549 if(group == NULL) { 550 int res = snprintf(dummy2, 12, "%d", inode->gid); 551 if(res < 0) 552 EXIT_UNSQUASH("snprintf failed in print_filename()\n"); 553 else if(res >= 12) 554 /* unsigned int shouldn't ever need more than 11 bytes 555 * (including terminating '\0') to print in base 10 */ 556 groupstr = "*"; 557 else 558 groupstr = dummy2; 559 } else 560 groupstr = group->gr_name; 561 562 printf("%s %s/%s ", modestr(str, inode->mode), userstr, groupstr); 563 564 switch(inode->mode & S_IFMT) { 565 case S_IFREG: 566 case S_IFDIR: 567 case S_IFSOCK: 568 case S_IFIFO: 569 case S_IFLNK: 570 padchars = TOTALCHARS - strlen(userstr) - 571 strlen(groupstr); 572 573 printf("%*lld ", padchars > 0 ? padchars : 0, 574 inode->data); 575 break; 576 case S_IFCHR: 577 case S_IFBLK: 578 padchars = TOTALCHARS - strlen(userstr) - 579 strlen(groupstr) - 7; 580 581 printf("%*s%3d,%3d ", padchars > 0 ? padchars : 0, " ", 582 (int) inode->data >> 8, (int) inode->data & 583 0xff); 584 break; 585 } 586 587 t = localtime(&inode->time); 588 589 printf("%d-%02d-%02d %02d:%02d %s", t->tm_year + 1900, t->tm_mon + 1, 590 t->tm_mday, t->tm_hour, t->tm_min, pathname); 591 if((inode->mode & S_IFMT) == S_IFLNK) 592 printf(" -> %s", inode->symlink); 593 printf("\n"); 594 595 return 1; 596} 597 598 599void add_entry(struct hash_table_entry *hash_table[], long long start, 600 int bytes) 601{ 602 int hash = CALCULATE_HASH(start); 603 struct hash_table_entry *hash_table_entry; 604 605 hash_table_entry = malloc(sizeof(struct hash_table_entry)); 606 if(hash_table_entry == NULL) 607 EXIT_UNSQUASH("Out of memory in add_entry\n"); 608 609 hash_table_entry->start = start; 610 hash_table_entry->bytes = bytes; 611 hash_table_entry->next = hash_table[hash]; 612 hash_table[hash] = hash_table_entry; 613} 614 615 616int lookup_entry(struct hash_table_entry *hash_table[], long long start) 617{ 618 int hash = CALCULATE_HASH(start); 619 struct hash_table_entry *hash_table_entry; 620 621 for(hash_table_entry = hash_table[hash]; hash_table_entry; 622 hash_table_entry = hash_table_entry->next) 623 624 if(hash_table_entry->start == start) 625 return hash_table_entry->bytes; 626 627 return -1; 628} 629 630 631int read_fs_bytes(int fd, long long byte, int bytes, void *buff) 632{ 633 off_t off = byte; 634 int res, count; 635 636 TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, 637 bytes); 638 639 if(lseek(fd, off, SEEK_SET) == -1) { 640 ERROR("Lseek failed because %s\n", strerror(errno)); 641 return FALSE; 642 } 643 644 for(count = 0; count < bytes; count += res) { 645 res = read(fd, buff + count, bytes - count); 646 if(res < 1) { 647 if(res == 0) { 648 ERROR("Read on filesystem failed because " 649 "EOF\n"); 650 return FALSE; 651 } else if(errno != EINTR) { 652 ERROR("Read on filesystem failed because %s\n", 653 strerror(errno)); 654 return FALSE; 655 } else 656 res = 0; 657 } 658 } 659 660 return TRUE; 661} 662 663 664int read_block(int fd, long long start, long long *next, int expected, 665 void *block) 666{ 667 unsigned short c_byte; 668 int offset = 2, res, compressed; 669 int outlen = expected ? expected : SQUASHFS_METADATA_SIZE; 670 671 if(swap) { 672 if(read_fs_bytes(fd, start, 2, &c_byte) == FALSE) 673 goto failed; 674 c_byte = (c_byte >> 8) | ((c_byte & 0xff) << 8); 675 } else 676 if(read_fs_bytes(fd, start, 2, &c_byte) == FALSE) 677 goto failed; 678 679 TRACE("read_block: block @0x%llx, %d %s bytes\n", start, 680 SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ? 681 "compressed" : "uncompressed"); 682 683 if(SQUASHFS_CHECK_DATA(sBlk.s.flags)) 684 offset = 3; 685 686 compressed = SQUASHFS_COMPRESSED(c_byte); 687 c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); 688 689 /* 690 * The block size should not be larger than 691 * the uncompressed size (or max uncompressed size if 692 * expected is 0) 693 */ 694 if(c_byte > outlen) 695 return 0; 696 697 if(compressed) { 698 char buffer[c_byte]; 699 int error; 700 701 res = read_fs_bytes(fd, start + offset, c_byte, buffer); 702 if(res == FALSE) 703 goto failed; 704 705 res = compressor_uncompress(comp, block, buffer, c_byte, 706 outlen, &error); 707 708 if(res == -1) { 709 ERROR("%s uncompress failed with error code %d\n", 710 comp->name, error); 711 goto failed; 712 } 713 } else { 714 res = read_fs_bytes(fd, start + offset, c_byte, block); 715 if(res == FALSE) 716 goto failed; 717 res = c_byte; 718 } 719 720 if(next) 721 *next = start + offset + c_byte; 722 723 /* 724 * if expected, then check the (uncompressed) return data 725 * is of the expected size 726 */ 727 if(expected && expected != res) 728 return 0; 729 else 730 return res; 731 732failed: 733 ERROR("read_block: failed to read block @0x%llx\n", start); 734 return FALSE; 735} 736 737 738int read_data_block(long long start, unsigned int size, char *block) 739{ 740 int error, res; 741 int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size); 742 743 TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start, 744 c_byte, SQUASHFS_COMPRESSED_BLOCK(size) ? "compressed" : 745 "uncompressed"); 746 747 if(SQUASHFS_COMPRESSED_BLOCK(size)) { 748 if(read_fs_bytes(fd, start, c_byte, data) == FALSE) 749 goto failed; 750 751 res = compressor_uncompress(comp, block, data, c_byte, 752 block_size, &error); 753 754 if(res == -1) { 755 ERROR("%s uncompress failed with error code %d\n", 756 comp->name, error); 757 goto failed; 758 } 759 760 return res; 761 } else { 762 if(read_fs_bytes(fd, start, c_byte, block) == FALSE) 763 goto failed; 764 765 return c_byte; 766 } 767 768failed: 769 ERROR("read_data_block: failed to read block @0x%llx, size %d\n", start, 770 c_byte); 771 return FALSE; 772} 773 774 775int read_inode_table(long long start, long long end) 776{ 777 int size = 0, bytes = 0, res; 778 779 TRACE("read_inode_table: start %lld, end %lld\n", start, end); 780 781 while(start < end) { 782 if(size - bytes < SQUASHFS_METADATA_SIZE) { 783 inode_table = realloc(inode_table, size += 784 SQUASHFS_METADATA_SIZE); 785 if(inode_table == NULL) { 786 ERROR("Out of memory in read_inode_table"); 787 goto failed; 788 } 789 } 790 791 add_entry(inode_table_hash, start, bytes); 792 793 res = read_block(fd, start, &start, 0, inode_table + bytes); 794 if(res == 0) { 795 ERROR("read_inode_table: failed to read block\n"); 796 goto failed; 797 } 798 bytes += res; 799 800 /* 801 * If this is not the last metadata block in the inode table 802 * then it should be SQUASHFS_METADATA_SIZE in size. 803 * Note, we can't use expected in read_block() above for this 804 * because we don't know if this is the last block until 805 * after reading. 806 */ 807 if(start != end && res != SQUASHFS_METADATA_SIZE) { 808 ERROR("read_inode_table: metadata block should be %d " 809 "bytes in length, it is %d bytes\n", 810 SQUASHFS_METADATA_SIZE, res); 811 812 goto failed; 813 } 814 } 815 816 return TRUE; 817 818failed: 819 free(inode_table); 820 return FALSE; 821} 822 823 824int set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time, 825 unsigned int xattr, unsigned int set_mode) 826{ 827 struct utimbuf times = { time, time }; 828 829 if(utime(pathname, ×) == -1) { 830 ERROR("set_attributes: failed to set time on %s, because %s\n", 831 pathname, strerror(errno)); 832 return FALSE; 833 } 834 835 if(root_process) { 836 if(chown(pathname, uid, guid) == -1) { 837 ERROR("set_attributes: failed to change uid and gids " 838 "on %s, because %s\n", pathname, 839 strerror(errno)); 840 return FALSE; 841 } 842 } else 843 mode &= ~07000; 844 845 if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) { 846 ERROR("set_attributes: failed to change mode %s, because %s\n", 847 pathname, strerror(errno)); 848 return FALSE; 849 } 850 851 write_xattr(pathname, xattr); 852 853 return TRUE; 854} 855 856 857int write_bytes(int fd, char *buff, int bytes) 858{ 859 int res, count; 860 861 for(count = 0; count < bytes; count += res) { 862 res = write(fd, buff + count, bytes - count); 863 if(res == -1) { 864 if(errno != EINTR) { 865 ERROR("Write on output file failed because " 866 "%s\n", strerror(errno)); 867 return -1; 868 } 869 res = 0; 870 } 871 } 872 873 return 0; 874} 875 876 877int lseek_broken = FALSE; 878char *zero_data = NULL; 879 880int write_block(int file_fd, char *buffer, int size, long long hole, int sparse) 881{ 882 off_t off = hole; 883 884 if(hole) { 885 if(sparse && lseek_broken == FALSE) { 886 int error = lseek(file_fd, off, SEEK_CUR); 887 if(error == -1) 888 /* failed to seek beyond end of file */ 889 lseek_broken = TRUE; 890 } 891 892 if((sparse == FALSE || lseek_broken) && zero_data == NULL) { 893 if((zero_data = malloc(block_size)) == NULL) 894 EXIT_UNSQUASH("write_block: failed to alloc " 895 "zero data block\n"); 896 memset(zero_data, 0, block_size); 897 } 898 899 if(sparse == FALSE || lseek_broken) { 900 int blocks = (hole + block_size -1) / block_size; 901 int avail_bytes, i; 902 for(i = 0; i < blocks; i++, hole -= avail_bytes) { 903 avail_bytes = hole > block_size ? block_size : 904 hole; 905 if(write_bytes(file_fd, zero_data, avail_bytes) 906 == -1) 907 goto failure; 908 } 909 } 910 } 911 912 if(write_bytes(file_fd, buffer, size) == -1) 913 goto failure; 914 915 return TRUE; 916 917failure: 918 return FALSE; 919} 920 921 922pthread_mutex_t open_mutex = PTHREAD_MUTEX_INITIALIZER; 923pthread_cond_t open_empty = PTHREAD_COND_INITIALIZER; 924int open_unlimited, open_count; 925#define OPEN_FILE_MARGIN 10 926 927 928void open_init(int count) 929{ 930 open_count = count; 931 open_unlimited = count == -1; 932} 933 934 935int open_wait(char *pathname, int flags, mode_t mode) 936{ 937 if (!open_unlimited) { 938 pthread_mutex_lock(&open_mutex); 939 while (open_count == 0) 940 pthread_cond_wait(&open_empty, &open_mutex); 941 open_count --; 942 pthread_mutex_unlock(&open_mutex); 943 } 944 945 return open(pathname, flags, mode); 946} 947 948 949void close_wake(int fd) 950{ 951 close(fd); 952 953 if (!open_unlimited) { 954 pthread_mutex_lock(&open_mutex); 955 open_count ++; 956 pthread_cond_signal(&open_empty); 957 pthread_mutex_unlock(&open_mutex); 958 } 959} 960 961 962void queue_file(char *pathname, int file_fd, struct inode *inode) 963{ 964 struct squashfs_file *file = malloc(sizeof(struct squashfs_file)); 965 if(file == NULL) 966 EXIT_UNSQUASH("queue_file: unable to malloc file\n"); 967 968 file->fd = file_fd; 969 file->file_size = inode->data; 970 file->mode = inode->mode; 971 file->gid = inode->gid; 972 file->uid = inode->uid; 973 file->time = inode->time; 974 file->pathname = strdup(pathname); 975 file->blocks = inode->blocks + (inode->frag_bytes > 0); 976 file->sparse = inode->sparse; 977 file->xattr = inode->xattr; 978 queue_put(to_writer, file); 979} 980 981 982void queue_dir(char *pathname, struct dir *dir) 983{ 984 struct squashfs_file *file = malloc(sizeof(struct squashfs_file)); 985 if(file == NULL) 986 EXIT_UNSQUASH("queue_dir: unable to malloc file\n"); 987 988 file->fd = -1; 989 file->mode = dir->mode; 990 file->gid = dir->guid; 991 file->uid = dir->uid; 992 file->time = dir->mtime; 993 file->pathname = strdup(pathname); 994 file->xattr = dir->xattr; 995 queue_put(to_writer, file); 996} 997 998 999int write_file(struct inode *inode, char *pathname) 1000{ 1001 unsigned int file_fd, i; 1002 unsigned int *block_list; 1003 int file_end = inode->data / block_size; 1004 long long start = inode->start; 1005 1006 TRACE("write_file: regular file, blocks %d\n", inode->blocks); 1007 1008 file_fd = open_wait(pathname, O_CREAT | O_WRONLY | 1009 (force ? O_TRUNC : 0), (mode_t) inode->mode & 0777); 1010 if(file_fd == -1) { 1011 ERROR("write_file: failed to create file %s, because %s\n", 1012 pathname, strerror(errno)); 1013 return FALSE; 1014 } 1015 1016 block_list = malloc(inode->blocks * sizeof(unsigned int)); 1017 if(block_list == NULL) 1018 EXIT_UNSQUASH("write_file: unable to malloc block list\n"); 1019 1020 s_ops.read_block_list(block_list, inode->block_ptr, inode->blocks); 1021 1022 /* 1023 * the writer thread is queued a squashfs_file structure describing the 1024 * file. If the file has one or more blocks or a fragment they are 1025 * queued separately (references to blocks in the cache). 1026 */ 1027 queue_file(pathname, file_fd, inode); 1028 1029 for(i = 0; i < inode->blocks; i++) { 1030 int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]); 1031 struct file_entry *block = malloc(sizeof(struct file_entry)); 1032 1033 if(block == NULL) 1034 EXIT_UNSQUASH("write_file: unable to malloc file\n"); 1035 block->offset = 0; 1036 block->size = i == file_end ? inode->data & (block_size - 1) : 1037 block_size; 1038 if(block_list[i] == 0) /* sparse block */ 1039 block->buffer = NULL; 1040 else { 1041 block->buffer = cache_get(data_cache, start, 1042 block_list[i]); 1043 start += c_byte; 1044 } 1045 queue_put(to_writer, block); 1046 } 1047 1048 if(inode->frag_bytes) { 1049 int size; 1050 long long start; 1051 struct file_entry *block = malloc(sizeof(struct file_entry)); 1052 1053 if(block == NULL) 1054 EXIT_UNSQUASH("write_file: unable to malloc file\n"); 1055 s_ops.read_fragment(inode->fragment, &start, &size); 1056 block->buffer = cache_get(fragment_cache, start, size); 1057 block->offset = inode->offset; 1058 block->size = inode->frag_bytes; 1059 queue_put(to_writer, block); 1060 } 1061 1062 free(block_list); 1063 return TRUE; 1064} 1065 1066 1067int create_inode(char *pathname, struct inode *i) 1068{ 1069 TRACE("create_inode: pathname %s\n", pathname); 1070 1071 if(created_inode[i->inode_number - 1]) { 1072 TRACE("create_inode: hard link\n"); 1073 if(force) 1074 unlink(pathname); 1075 1076 if(link(created_inode[i->inode_number - 1], pathname) == -1) { 1077 ERROR("create_inode: failed to create hardlink, " 1078 "because %s\n", strerror(errno)); 1079 return FALSE; 1080 } 1081 1082 return TRUE; 1083 } 1084 1085 switch(i->type) { 1086 case SQUASHFS_FILE_TYPE: 1087 case SQUASHFS_LREG_TYPE: 1088 TRACE("create_inode: regular file, file_size %lld, " 1089 "blocks %d\n", i->data, i->blocks); 1090 1091 if(write_file(i, pathname)) 1092 file_count ++; 1093 break; 1094 case SQUASHFS_SYMLINK_TYPE: 1095 case SQUASHFS_LSYMLINK_TYPE: 1096 TRACE("create_inode: symlink, symlink_size %lld\n", 1097 i->data); 1098 1099 if(force) 1100 unlink(pathname); 1101 1102 if(symlink(i->symlink, pathname) == -1) { 1103 ERROR("create_inode: failed to create symlink " 1104 "%s, because %s\n", pathname, 1105 strerror(errno)); 1106 break; 1107 } 1108 1109 write_xattr(pathname, i->xattr); 1110 1111 if(root_process) { 1112 if(lchown(pathname, i->uid, i->gid) == -1) 1113 ERROR("create_inode: failed to change " 1114 "uid and gids on %s, because " 1115 "%s\n", pathname, 1116 strerror(errno)); 1117 } 1118 1119 sym_count ++; 1120 break; 1121 case SQUASHFS_BLKDEV_TYPE: 1122 case SQUASHFS_CHRDEV_TYPE: 1123 case SQUASHFS_LBLKDEV_TYPE: 1124 case SQUASHFS_LCHRDEV_TYPE: { 1125 int chrdev = i->type == SQUASHFS_CHRDEV_TYPE; 1126 TRACE("create_inode: dev, rdev 0x%llx\n", i->data); 1127 1128 if(root_process) { 1129 if(force) 1130 unlink(pathname); 1131 1132 if(mknod(pathname, chrdev ? S_IFCHR : S_IFBLK, 1133 makedev((i->data >> 8) & 0xff, 1134 i->data & 0xff)) == -1) { 1135 ERROR("create_inode: failed to create " 1136 "%s device %s, because %s\n", 1137 chrdev ? "character" : "block", 1138 pathname, strerror(errno)); 1139 break; 1140 } 1141 set_attributes(pathname, i->mode, i->uid, 1142 i->gid, i->time, i->xattr, TRUE); 1143 dev_count ++; 1144 } else 1145 ERROR("create_inode: could not create %s " 1146 "device %s, because you're not " 1147 "superuser!\n", chrdev ? "character" : 1148 "block", pathname); 1149 break; 1150 } 1151 case SQUASHFS_FIFO_TYPE: 1152 case SQUASHFS_LFIFO_TYPE: 1153 TRACE("create_inode: fifo\n"); 1154 1155 if(force) 1156 unlink(pathname); 1157 1158 if(mknod(pathname, S_IFIFO, 0) == -1) { 1159 ERROR("create_inode: failed to create fifo %s, " 1160 "because %s\n", pathname, 1161 strerror(errno)); 1162 break; 1163 } 1164 set_attributes(pathname, i->mode, i->uid, i->gid, 1165 i->time, i->xattr, TRUE); 1166 fifo_count ++; 1167 break; 1168 case SQUASHFS_SOCKET_TYPE: 1169 case SQUASHFS_LSOCKET_TYPE: 1170 TRACE("create_inode: socket\n"); 1171 ERROR("create_inode: socket %s ignored\n", pathname); 1172 break; 1173 default: 1174 ERROR("Unknown inode type %d in create_inode_table!\n", 1175 i->type); 1176 return FALSE; 1177 } 1178 1179 created_inode[i->inode_number - 1] = strdup(pathname); 1180 1181 return TRUE; 1182} 1183 1184 1185int read_directory_table(long long start, long long end) 1186{ 1187 int bytes = 0, size = 0, res; 1188 1189 TRACE("read_directory_table: start %lld, end %lld\n", start, end); 1190 1191 while(start < end) { 1192 if(size - bytes < SQUASHFS_METADATA_SIZE) { 1193 directory_table = realloc(directory_table, size += 1194 SQUASHFS_METADATA_SIZE); 1195 if(directory_table == NULL) { 1196 ERROR("Out of memory in " 1197 "read_directory_table\n"); 1198 goto failed; 1199 } 1200 } 1201 1202 add_entry(directory_table_hash, start, bytes); 1203 1204 res = read_block(fd, start, &start, 0, directory_table + bytes); 1205 if(res == 0) { 1206 ERROR("read_directory_table: failed to read block\n"); 1207 goto failed; 1208 } 1209 1210 bytes += res; 1211 1212 /* 1213 * If this is not the last metadata block in the directory table 1214 * then it should be SQUASHFS_METADATA_SIZE in size. 1215 * Note, we can't use expected in read_block() above for this 1216 * because we don't know if this is the last block until 1217 * after reading. 1218 */ 1219 if(start != end && res != SQUASHFS_METADATA_SIZE) { 1220 ERROR("read_directory_table: metadata block " 1221 "should be %d bytes in length, it is %d " 1222 "bytes\n", SQUASHFS_METADATA_SIZE, res); 1223 goto failed; 1224 } 1225 } 1226 1227 return TRUE; 1228 1229failed: 1230 free(directory_table); 1231 return FALSE; 1232} 1233 1234 1235int squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block, 1236unsigned int *offset, unsigned int *type) 1237{ 1238 if(dir->cur_entry == dir->dir_count) 1239 return FALSE; 1240 1241 *name = dir->dirs[dir->cur_entry].name; 1242 *start_block = dir->dirs[dir->cur_entry].start_block; 1243 *offset = dir->dirs[dir->cur_entry].offset; 1244 *type = dir->dirs[dir->cur_entry].type; 1245 dir->cur_entry ++; 1246 1247 return TRUE; 1248} 1249 1250 1251void squashfs_closedir(struct dir *dir) 1252{ 1253 free(dir->dirs); 1254 free(dir); 1255} 1256 1257 1258char *get_component(char *target, char **targname) 1259{ 1260 char *start; 1261 1262 while(*target == '/') 1263 target ++; 1264 1265 start = target; 1266 while(*target != '/' && *target != '\0') 1267 target ++; 1268 1269 *targname = strndup(start, target - start); 1270 1271 while(*target == '/') 1272 target ++; 1273 1274 return target; 1275} 1276 1277 1278void free_path(struct pathname *paths) 1279{ 1280 int i; 1281 1282 for(i = 0; i < paths->names; i++) { 1283 if(paths->name[i].paths) 1284 free_path(paths->name[i].paths); 1285 free(paths->name[i].name); 1286 if(paths->name[i].preg) { 1287 regfree(paths->name[i].preg); 1288 free(paths->name[i].preg); 1289 } 1290 } 1291 1292 free(paths); 1293} 1294 1295 1296struct pathname *add_path(struct pathname *paths, char *target, char *alltarget) 1297{ 1298 char *targname; 1299 int i, error; 1300 1301 TRACE("add_path: adding \"%s\" extract file\n", target); 1302 1303 target = get_component(target, &targname); 1304 1305 if(paths == NULL) { 1306 paths = malloc(sizeof(struct pathname)); 1307 if(paths == NULL) 1308 EXIT_UNSQUASH("failed to allocate paths\n"); 1309 1310 paths->names = 0; 1311 paths->name = NULL; 1312 } 1313 1314 for(i = 0; i < paths->names; i++) 1315 if(strcmp(paths->name[i].name, targname) == 0) 1316 break; 1317 1318 if(i == paths->names) { 1319 /* 1320 * allocate new name entry 1321 */ 1322 paths->names ++; 1323 paths->name = realloc(paths->name, (i + 1) * 1324 sizeof(struct path_entry)); 1325 if(paths->name == NULL) 1326 EXIT_UNSQUASH("Out of memory in add_path\n"); 1327 paths->name[i].name = targname; 1328 paths->name[i].paths = NULL; 1329 if(use_regex) { 1330 paths->name[i].preg = malloc(sizeof(regex_t)); 1331 if(paths->name[i].preg == NULL) 1332 EXIT_UNSQUASH("Out of memory in add_path\n"); 1333 error = regcomp(paths->name[i].preg, targname, 1334 REG_EXTENDED|REG_NOSUB); 1335 if(error) { 1336 char str[1024]; /* overflow safe */ 1337 1338 regerror(error, paths->name[i].preg, str, 1024); 1339 EXIT_UNSQUASH("invalid regex %s in export %s, " 1340 "because %s\n", targname, alltarget, 1341 str); 1342 } 1343 } else 1344 paths->name[i].preg = NULL; 1345 1346 if(target[0] == '\0') 1347 /* 1348 * at leaf pathname component 1349 */ 1350 paths->name[i].paths = NULL; 1351 else 1352 /* 1353 * recurse adding child components 1354 */ 1355 paths->name[i].paths = add_path(NULL, target, alltarget); 1356 } else { 1357 /* 1358 * existing matching entry 1359 */ 1360 free(targname); 1361 1362 if(paths->name[i].paths == NULL) { 1363 /* 1364 * No sub-directory which means this is the leaf 1365 * component of a pre-existing extract which subsumes 1366 * the extract currently being added, in which case stop 1367 * adding components 1368 */ 1369 } else if(target[0] == '\0') { 1370 /* 1371 * at leaf pathname component and child components exist 1372 * from more specific extracts, delete as they're 1373 * subsumed by this extract 1374 */ 1375 free_path(paths->name[i].paths); 1376 paths->name[i].paths = NULL; 1377 } else 1378 /* 1379 * recurse adding child components 1380 */ 1381 add_path(paths->name[i].paths, target, alltarget); 1382 } 1383 1384 return paths; 1385} 1386 1387 1388struct pathnames *init_subdir() 1389{ 1390 struct pathnames *new = malloc(sizeof(struct pathnames)); 1391 if(new == NULL) 1392 EXIT_UNSQUASH("Out of memory in init_subdir\n"); 1393 new->count = 0; 1394 return new; 1395} 1396 1397 1398struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path) 1399{ 1400 if(paths->count % PATHS_ALLOC_SIZE == 0) { 1401 paths = realloc(paths, sizeof(struct pathnames *) + 1402 (paths->count + PATHS_ALLOC_SIZE) * 1403 sizeof(struct pathname *)); 1404 if(paths == NULL) 1405 EXIT_UNSQUASH("Out of memory in add_subdir\n"); 1406 } 1407 1408 paths->path[paths->count++] = path; 1409 return paths; 1410} 1411 1412 1413void free_subdir(struct pathnames *paths) 1414{ 1415 free(paths); 1416} 1417 1418 1419int matches(struct pathnames *paths, char *name, struct pathnames **new) 1420{ 1421 int i, n; 1422 1423 if(paths == NULL) { 1424 *new = NULL; 1425 return TRUE; 1426 } 1427 1428 *new = init_subdir(); 1429 1430 for(n = 0; n < paths->count; n++) { 1431 struct pathname *path = paths->path[n]; 1432 for(i = 0; i < path->names; i++) { 1433 int match = use_regex ? 1434 regexec(path->name[i].preg, name, (size_t) 0, 1435 NULL, 0) == 0 : fnmatch(path->name[i].name, 1436 name, FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 1437 0; 1438 if(match && path->name[i].paths == NULL) 1439 /* 1440 * match on a leaf component, any subdirectories 1441 * will implicitly match, therefore return an 1442 * empty new search set 1443 */ 1444 goto empty_set; 1445 1446 if(match) 1447 /* 1448 * match on a non-leaf component, add any 1449 * subdirectories to the new set of 1450 * subdirectories to scan for this name 1451 */ 1452 *new = add_subdir(*new, path->name[i].paths); 1453 } 1454 } 1455 1456 if((*new)->count == 0) { 1457 /* 1458 * no matching names found, delete empty search set, and return 1459 * FALSE 1460 */ 1461 free_subdir(*new); 1462 *new = NULL; 1463 return FALSE; 1464 } 1465 1466 /* 1467 * one or more matches with sub-directories found (no leaf matches), 1468 * return new search set and return TRUE 1469 */ 1470 return TRUE; 1471 1472empty_set: 1473 /* 1474 * found matching leaf exclude, return empty search set and return TRUE 1475 */ 1476 free_subdir(*new); 1477 *new = NULL; 1478 return TRUE; 1479} 1480 1481 1482void pre_scan(char *parent_name, unsigned int start_block, unsigned int offset, 1483 struct pathnames *paths) 1484{ 1485 unsigned int type; 1486 char *name; 1487 struct pathnames *new; 1488 struct inode *i; 1489 struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i); 1490 1491 if(dir == NULL) 1492 return; 1493 1494 while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) { 1495 struct inode *i; 1496 char *pathname; 1497 int res; 1498 1499 TRACE("pre_scan: name %s, start_block %d, offset %d, type %d\n", 1500 name, start_block, offset, type); 1501 1502 if(!matches(paths, name, &new)) 1503 continue; 1504 1505 res = asprintf(&pathname, "%s/%s", parent_name, name); 1506 if(res == -1) 1507 EXIT_UNSQUASH("asprintf failed in dir_scan\n"); 1508 1509 if(type == SQUASHFS_DIR_TYPE) 1510 pre_scan(parent_name, start_block, offset, new); 1511 else if(new == NULL) { 1512 if(type == SQUASHFS_FILE_TYPE || 1513 type == SQUASHFS_LREG_TYPE) { 1514 i = s_ops.read_inode(start_block, offset); 1515 if(created_inode[i->inode_number - 1] == NULL) { 1516 created_inode[i->inode_number - 1] = 1517 (char *) i; 1518 total_blocks += (i->data + 1519 (block_size - 1)) >> block_log; 1520 } 1521 total_files ++; 1522 } 1523 total_inodes ++; 1524 } 1525 1526 free_subdir(new); 1527 free(pathname); 1528 } 1529 1530 squashfs_closedir(dir); 1531} 1532 1533 1534void dir_scan(char *parent_name, unsigned int start_block, unsigned int offset, 1535 struct pathnames *paths) 1536{ 1537 unsigned int type; 1538 char *name; 1539 struct pathnames *new; 1540 struct inode *i; 1541 struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i); 1542 1543 if(dir == NULL) { 1544 ERROR("dir_scan: failed to read directory %s, skipping\n", 1545 parent_name); 1546 return; 1547 } 1548 1549 if(lsonly || info) 1550 print_filename(parent_name, i); 1551 1552 if(!lsonly) { 1553 /* 1554 * Make directory with default User rwx permissions rather than 1555 * the permissions from the filesystem, as these may not have 1556 * write/execute permission. These are fixed up later in 1557 * set_attributes(). 1558 */ 1559 int res = mkdir(parent_name, S_IRUSR|S_IWUSR|S_IXUSR); 1560 if(res == -1) { 1561 /* 1562 * Skip directory if mkdir fails, unless we're 1563 * forcing and the error is -EEXIST 1564 */ 1565 if(!force || errno != EEXIST) { 1566 ERROR("dir_scan: failed to make directory %s, " 1567 "because %s\n", parent_name, 1568 strerror(errno)); 1569 squashfs_closedir(dir); 1570 return; 1571 } 1572 1573 /* 1574 * Try to change permissions of existing directory so 1575 * that we can write to it 1576 */ 1577 res = chmod(parent_name, S_IRUSR|S_IWUSR|S_IXUSR); 1578 if (res == -1) 1579 ERROR("dir_scan: failed to change permissions " 1580 "for directory %s, because %s\n", 1581 parent_name, strerror(errno)); 1582 } 1583 } 1584 1585 while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) { 1586 char *pathname; 1587 int res; 1588 1589 TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n", 1590 name, start_block, offset, type); 1591 1592 1593 if(!matches(paths, name, &new)) 1594 continue; 1595 1596 res = asprintf(&pathname, "%s/%s", parent_name, name); 1597 if(res == -1) 1598 EXIT_UNSQUASH("asprintf failed in dir_scan\n"); 1599 1600 if(type == SQUASHFS_DIR_TYPE) { 1601 dir_scan(pathname, start_block, offset, new); 1602 free(pathname); 1603 } else if(new == NULL) { 1604 update_info(pathname); 1605 1606 i = s_ops.read_inode(start_block, offset); 1607 1608 if(lsonly || info) 1609 print_filename(pathname, i); 1610 1611 if(!lsonly) 1612 create_inode(pathname, i); 1613 1614 if(i->type == SQUASHFS_SYMLINK_TYPE || 1615 i->type == SQUASHFS_LSYMLINK_TYPE) 1616 free(i->symlink); 1617 } else 1618 free(pathname); 1619 1620 free_subdir(new); 1621 } 1622 1623 if(!lsonly) 1624 queue_dir(parent_name, dir); 1625 1626 squashfs_closedir(dir); 1627 dir_count ++; 1628} 1629 1630 1631void squashfs_stat(char *source) 1632{ 1633 time_t mkfs_time = (time_t) sBlk.s.mkfs_time; 1634 char *mkfs_str = ctime(&mkfs_time); 1635 1636#if __BYTE_ORDER == __BIG_ENDIAN 1637 printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n", 1638 sBlk.s.s_major == 4 ? "" : swap ? "little endian " : 1639 "big endian ", sBlk.s.s_major, sBlk.s.s_minor, source); 1640#else 1641 printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n", 1642 sBlk.s.s_major == 4 ? "" : swap ? "big endian " : 1643 "little endian ", sBlk.s.s_major, sBlk.s.s_minor, source); 1644#endif 1645 1646 printf("Creation or last append time %s", mkfs_str ? mkfs_str : 1647 "failed to get time\n"); 1648 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", 1649 sBlk.s.bytes_used / 1024.0, sBlk.s.bytes_used / 1650 (1024.0 * 1024.0)); 1651 1652 if(sBlk.s.s_major == 4) { 1653 printf("Compression %s\n", comp->name); 1654 1655 if(SQUASHFS_COMP_OPTS(sBlk.s.flags)) { 1656 char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned)); 1657 int bytes; 1658 1659 bytes = read_block(fd, sizeof(sBlk.s), NULL, 0, buffer); 1660 if(bytes == 0) { 1661 ERROR("Failed to read compressor options\n"); 1662 return; 1663 } 1664 1665 compressor_display_options(comp, buffer, bytes); 1666 } 1667 } 1668 1669 printf("Block size %d\n", sBlk.s.block_size); 1670 printf("Filesystem is %sexportable via NFS\n", 1671 SQUASHFS_EXPORTABLE(sBlk.s.flags) ? "" : "not "); 1672 printf("Inodes are %scompressed\n", 1673 SQUASHFS_UNCOMPRESSED_INODES(sBlk.s.flags) ? "un" : ""); 1674 printf("Data is %scompressed\n", 1675 SQUASHFS_UNCOMPRESSED_DATA(sBlk.s.flags) ? "un" : ""); 1676 1677 if(sBlk.s.s_major > 1) { 1678 if(SQUASHFS_NO_FRAGMENTS(sBlk.s.flags)) 1679 printf("Fragments are not stored\n"); 1680 else { 1681 printf("Fragments are %scompressed\n", 1682 SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.s.flags) ? 1683 "un" : ""); 1684 printf("Always-use-fragments option is %sspecified\n", 1685 SQUASHFS_ALWAYS_FRAGMENTS(sBlk.s.flags) ? "" : 1686 "not "); 1687 } 1688 } 1689 1690 if(sBlk.s.s_major == 4) { 1691 if(SQUASHFS_NO_XATTRS(sBlk.s.flags)) 1692 printf("Xattrs are not stored\n"); 1693 else 1694 printf("Xattrs are %scompressed\n", 1695 SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.s.flags) ? 1696 "un" : ""); 1697 } 1698 1699 if(sBlk.s.s_major < 4) 1700 printf("Check data is %spresent in the filesystem\n", 1701 SQUASHFS_CHECK_DATA(sBlk.s.flags) ? "" : 1702 "not "); 1703 1704 if(sBlk.s.s_major > 1) 1705 printf("Duplicates are %sremoved\n", 1706 SQUASHFS_DUPLICATES(sBlk.s.flags) ? "" : "not "); 1707 else 1708 printf("Duplicates are removed\n"); 1709 1710 if(sBlk.s.s_major > 1) 1711 printf("Number of fragments %d\n", sBlk.s.fragments); 1712 1713 printf("Number of inodes %d\n", sBlk.s.inodes); 1714 1715 if(sBlk.s.s_major == 4) 1716 printf("Number of ids %d\n", sBlk.s.no_ids); 1717 else { 1718 printf("Number of uids %d\n", sBlk.no_uids); 1719 printf("Number of gids %d\n", sBlk.no_guids); 1720 } 1721 1722 TRACE("sBlk.s.inode_table_start 0x%llx\n", sBlk.s.inode_table_start); 1723 TRACE("sBlk.s.directory_table_start 0x%llx\n", 1724 sBlk.s.directory_table_start); 1725 1726 if(sBlk.s.s_major > 1) 1727 TRACE("sBlk.s.fragment_table_start 0x%llx\n\n", 1728 sBlk.s.fragment_table_start); 1729 1730 if(sBlk.s.s_major > 2) 1731 TRACE("sBlk.s.lookup_table_start 0x%llx\n\n", 1732 sBlk.s.lookup_table_start); 1733 1734 if(sBlk.s.s_major == 4) { 1735 TRACE("sBlk.s.id_table_start 0x%llx\n", sBlk.s.id_table_start); 1736 TRACE("sBlk.s.xattr_id_table_start 0x%llx\n", 1737 sBlk.s.xattr_id_table_start); 1738 } else { 1739 TRACE("sBlk.uid_start 0x%llx\n", sBlk.uid_start); 1740 TRACE("sBlk.guid_start 0x%llx\n", sBlk.guid_start); 1741 } 1742} 1743 1744 1745int check_compression(struct compressor *comp) 1746{ 1747 int res, bytes = 0; 1748 char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned)); 1749 1750 if(!comp->supported) { 1751 ERROR("Filesystem uses %s compression, this is " 1752 "unsupported by this version\n", comp->name); 1753 ERROR("Decompressors available:\n"); 1754 display_compressors("", ""); 1755 return 0; 1756 } 1757 1758 /* 1759 * Read compression options from disk if present, and pass to 1760 * the compressor to ensure we know how to decompress a filesystem 1761 * compressed with these compression options. 1762 * 1763 * Note, even if there is no compression options we still call the 1764 * compressor because some compression options may be mandatory 1765 * for some compressors. 1766 */ 1767 if(SQUASHFS_COMP_OPTS(sBlk.s.flags)) { 1768 bytes = read_block(fd, sizeof(sBlk.s), NULL, 0, buffer); 1769 if(bytes == 0) { 1770 ERROR("Failed to read compressor options\n"); 1771 return 0; 1772 } 1773 } 1774 1775 res = compressor_check_options(comp, sBlk.s.block_size, buffer, bytes); 1776 1777 return res != -1; 1778} 1779 1780 1781int read_super(char *source) 1782{ 1783 squashfs_super_block_3 sBlk_3; 1784 struct squashfs_super_block sBlk_4; 1785 1786 /* 1787 * Try to read a Squashfs 4 superblock 1788 */ 1789 read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block), 1790 &sBlk_4); 1791 swap = sBlk_4.s_magic != SQUASHFS_MAGIC; 1792 SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4); 1793 1794 if(sBlk_4.s_magic == SQUASHFS_MAGIC && sBlk_4.s_major == 4 && 1795 sBlk_4.s_minor == 0) { 1796 s_ops.squashfs_opendir = squashfs_opendir_4; 1797 s_ops.read_fragment = read_fragment_4; 1798 s_ops.read_fragment_table = read_fragment_table_4; 1799 s_ops.read_block_list = read_block_list_2; 1800 s_ops.read_inode = read_inode_4; 1801 s_ops.read_uids_guids = read_uids_guids_4; 1802 memcpy(&sBlk, &sBlk_4, sizeof(sBlk_4)); 1803 1804 /* 1805 * Check the compression type 1806 */ 1807 comp = lookup_compressor_id(sBlk.s.compression); 1808 return TRUE; 1809 } 1810 1811 /* 1812 * Not a Squashfs 4 superblock, try to read a squashfs 3 superblock 1813 * (compatible with 1 and 2 filesystems) 1814 */ 1815 read_fs_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block_3), 1816 &sBlk_3); 1817 1818 /* 1819 * Check it is a SQUASHFS superblock 1820 */ 1821 swap = 0; 1822 if(sBlk_3.s_magic != SQUASHFS_MAGIC) { 1823 if(sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP) { 1824 squashfs_super_block_3 sblk; 1825 ERROR("Reading a different endian SQUASHFS filesystem " 1826 "on %s\n", source); 1827 SQUASHFS_SWAP_SUPER_BLOCK_3(&sblk, &sBlk_3); 1828 memcpy(&sBlk_3, &sblk, sizeof(squashfs_super_block_3)); 1829 swap = 1; 1830 } else { 1831 ERROR("Can't find a SQUASHFS superblock on %s\n", 1832 source); 1833 goto failed_mount; 1834 } 1835 } 1836 1837 sBlk.s.s_magic = sBlk_3.s_magic; 1838 sBlk.s.inodes = sBlk_3.inodes; 1839 sBlk.s.mkfs_time = sBlk_3.mkfs_time; 1840 sBlk.s.block_size = sBlk_3.block_size; 1841 sBlk.s.fragments = sBlk_3.fragments; 1842 sBlk.s.block_log = sBlk_3.block_log; 1843 sBlk.s.flags = sBlk_3.flags; 1844 sBlk.s.s_major = sBlk_3.s_major; 1845 sBlk.s.s_minor = sBlk_3.s_minor; 1846 sBlk.s.root_inode = sBlk_3.root_inode; 1847 sBlk.s.bytes_used = sBlk_3.bytes_used; 1848 sBlk.s.inode_table_start = sBlk_3.inode_table_start; 1849 sBlk.s.directory_table_start = sBlk_3.directory_table_start; 1850 sBlk.s.fragment_table_start = sBlk_3.fragment_table_start; 1851 sBlk.s.lookup_table_start = sBlk_3.lookup_table_start; 1852 sBlk.no_uids = sBlk_3.no_uids; 1853 sBlk.no_guids = sBlk_3.no_guids; 1854 sBlk.uid_start = sBlk_3.uid_start; 1855 sBlk.guid_start = sBlk_3.guid_start; 1856 sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK; 1857 1858 /* Check the MAJOR & MINOR versions */ 1859 if(sBlk.s.s_major == 1 || sBlk.s.s_major == 2) { 1860 sBlk.s.bytes_used = sBlk_3.bytes_used_2; 1861 sBlk.uid_start = sBlk_3.uid_start_2; 1862 sBlk.guid_start = sBlk_3.guid_start_2; 1863 sBlk.s.inode_table_start = sBlk_3.inode_table_start_2; 1864 sBlk.s.directory_table_start = sBlk_3.directory_table_start_2; 1865 1866 if(sBlk.s.s_major == 1) { 1867 sBlk.s.block_size = sBlk_3.block_size_1; 1868 sBlk.s.fragment_table_start = sBlk.uid_start; 1869 s_ops.squashfs_opendir = squashfs_opendir_1; 1870 s_ops.read_fragment_table = read_fragment_table_1; 1871 s_ops.read_block_list = read_block_list_1; 1872 s_ops.read_inode = read_inode_1; 1873 s_ops.read_uids_guids = read_uids_guids_1; 1874 } else { 1875 sBlk.s.fragment_table_start = 1876 sBlk_3.fragment_table_start_2; 1877 s_ops.squashfs_opendir = squashfs_opendir_1; 1878 s_ops.read_fragment = read_fragment_2; 1879 s_ops.read_fragment_table = read_fragment_table_2; 1880 s_ops.read_block_list = read_block_list_2; 1881 s_ops.read_inode = read_inode_2; 1882 s_ops.read_uids_guids = read_uids_guids_1; 1883 } 1884 } else if(sBlk.s.s_major == 3) { 1885 s_ops.squashfs_opendir = squashfs_opendir_3; 1886 s_ops.read_fragment = read_fragment_3; 1887 s_ops.read_fragment_table = read_fragment_table_3; 1888 s_ops.read_block_list = read_block_list_2; 1889 s_ops.read_inode = read_inode_3; 1890 s_ops.read_uids_guids = read_uids_guids_1; 1891 } else { 1892 ERROR("Filesystem on %s is (%d:%d), ", source, sBlk.s.s_major, 1893 sBlk.s.s_minor); 1894 ERROR("which is a later filesystem version than I support!\n"); 1895 goto failed_mount; 1896 } 1897 1898 /* 1899 * 1.x, 2.x and 3.x filesystems use gzip compression. 1900 */ 1901 comp = lookup_compressor("gzip"); 1902 return TRUE; 1903 1904failed_mount: 1905 return FALSE; 1906} 1907 1908 1909struct pathname *process_extract_files(struct pathname *path, char *filename) 1910{ 1911 FILE *fd; 1912 char buffer[MAX_LINE + 1]; /* overflow safe */ 1913 char *name; 1914 1915 fd = fopen(filename, "r"); 1916 if(fd == NULL) 1917 EXIT_UNSQUASH("Failed to open extract file \"%s\" because %s\n", 1918 filename, strerror(errno)); 1919 1920 while(fgets(name = buffer, MAX_LINE + 1, fd) != NULL) { 1921 int len = strlen(name); 1922 1923 if(len == MAX_LINE && name[len - 1] != '\n') 1924 /* line too large */ 1925 EXIT_UNSQUASH("Line too long when reading " 1926 "extract file \"%s\", larger than %d " 1927 "bytes\n", filename, MAX_LINE); 1928 1929 /* 1930 * Remove '\n' terminator if it exists (the last line 1931 * in the file may not be '\n' terminated) 1932 */ 1933 if(len && name[len - 1] == '\n') 1934 name[len - 1] = '\0'; 1935 1936 /* Skip any leading whitespace */ 1937 while(isspace(*name)) 1938 name ++; 1939 1940 /* if comment line, skip */ 1941 if(*name == '#') 1942 continue; 1943 1944 /* check for initial backslash, to accommodate 1945 * filenames with leading space or leading # character 1946 */ 1947 if(*name == '\\') 1948 name ++; 1949 1950 /* if line is now empty after skipping characters, skip it */ 1951 if(*name == '\0') 1952 continue; 1953 1954 path = add_path(path, name, name); 1955 } 1956 1957 if(ferror(fd)) 1958 EXIT_UNSQUASH("Reading extract file \"%s\" failed because %s\n", 1959 filename, strerror(errno)); 1960 1961 fclose(fd); 1962 return path; 1963} 1964 1965 1966/* 1967 * reader thread. This thread processes read requests queued by the 1968 * cache_get() routine. 1969 */ 1970void *reader(void *arg) 1971{ 1972 while(1) { 1973 struct cache_entry *entry = queue_get(to_reader); 1974 int res = read_fs_bytes(fd, entry->block, 1975 SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size), 1976 entry->data); 1977 1978 if(res && SQUASHFS_COMPRESSED_BLOCK(entry->size)) 1979 /* 1980 * queue successfully read block to the inflate 1981 * thread(s) for further processing 1982 */ 1983 queue_put(to_inflate, entry); 1984 else 1985 /* 1986 * block has either been successfully read and is 1987 * uncompressed, or an error has occurred, clear pending 1988 * flag, set error appropriately, and wake up any 1989 * threads waiting on this buffer 1990 */ 1991 cache_block_ready(entry, !res); 1992 } 1993} 1994 1995 1996/* 1997 * writer thread. This processes file write requests queued by the 1998 * write_file() routine. 1999 */ 2000void *writer(void *arg) 2001{ 2002 int i; 2003 2004 while(1) { 2005 struct squashfs_file *file = queue_get(to_writer); 2006 int file_fd; 2007 long long hole = 0; 2008 int failed = FALSE; 2009 int error; 2010 2011 if(file == NULL) { 2012 queue_put(from_writer, NULL); 2013 continue; 2014 } else if(file->fd == -1) { 2015 /* write attributes for directory file->pathname */ 2016 set_attributes(file->pathname, file->mode, file->uid, 2017 file->gid, file->time, file->xattr, TRUE); 2018 free(file->pathname); 2019 free(file); 2020 continue; 2021 } 2022 2023 TRACE("writer: regular file, blocks %d\n", file->blocks); 2024 2025 file_fd = file->fd; 2026 2027 for(i = 0; i < file->blocks; i++, cur_blocks ++) { 2028 struct file_entry *block = queue_get(to_writer); 2029 2030 if(block->buffer == 0) { /* sparse file */ 2031 hole += block->size; 2032 free(block); 2033 continue; 2034 } 2035 2036 cache_block_wait(block->buffer); 2037 2038 if(block->buffer->error) 2039 failed = TRUE; 2040 2041 if(failed) 2042 continue; 2043 2044 error = write_block(file_fd, block->buffer->data + 2045 block->offset, block->size, hole, file->sparse); 2046 2047 if(error == FALSE) { 2048 ERROR("writer: failed to write data block %d\n", 2049 i); 2050 failed = TRUE; 2051 } 2052 2053 hole = 0; 2054 cache_block_put(block->buffer); 2055 free(block); 2056 } 2057 2058 if(hole && failed == FALSE) { 2059 /* 2060 * corner case for hole extending to end of file 2061 */ 2062 if(file->sparse == FALSE || 2063 lseek(file_fd, hole, SEEK_CUR) == -1) { 2064 /* 2065 * for files which we don't want to write 2066 * sparsely, or for broken lseeks which cannot 2067 * seek beyond end of file, write_block will do 2068 * the right thing 2069 */ 2070 hole --; 2071 if(write_block(file_fd, "\0", 1, hole, 2072 file->sparse) == FALSE) { 2073 ERROR("writer: failed to write sparse " 2074 "data block\n"); 2075 failed = TRUE; 2076 } 2077 } else if(ftruncate(file_fd, file->file_size) == -1) { 2078 ERROR("writer: failed to write sparse data " 2079 "block\n"); 2080 failed = TRUE; 2081 } 2082 } 2083 2084 close_wake(file_fd); 2085 if(failed == FALSE) 2086 set_attributes(file->pathname, file->mode, file->uid, 2087 file->gid, file->time, file->xattr, force); 2088 else { 2089 ERROR("Failed to write %s, skipping\n", file->pathname); 2090 unlink(file->pathname); 2091 } 2092 free(file->pathname); 2093 free(file); 2094 2095 } 2096} 2097 2098 2099/* 2100 * decompress thread. This decompresses buffers queued by the read thread 2101 */ 2102void *inflator(void *arg) 2103{ 2104 char tmp[block_size]; 2105 2106 while(1) { 2107 struct cache_entry *entry = queue_get(to_inflate); 2108 int error, res; 2109 2110 res = compressor_uncompress(comp, tmp, entry->data, 2111 SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size), block_size, 2112 &error); 2113 2114 if(res == -1) 2115 ERROR("%s uncompress failed with error code %d\n", 2116 comp->name, error); 2117 else 2118 memcpy(entry->data, tmp, res); 2119 2120 /* 2121 * block has been either successfully decompressed, or an error 2122 * occurred, clear pending flag, set error appropriately and 2123 * wake up any threads waiting on this block 2124 */ 2125 cache_block_ready(entry, res == -1); 2126 } 2127} 2128 2129 2130void *progress_thread(void *arg) 2131{ 2132 struct timespec requested_time, remaining; 2133 struct itimerval itimerval; 2134 struct winsize winsize; 2135 2136 if(ioctl(1, TIOCGWINSZ, &winsize) == -1) { 2137 if(isatty(STDOUT_FILENO)) 2138 ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 " 2139 "columns\n"); 2140 columns = 80; 2141 } else 2142 columns = winsize.ws_col; 2143 signal(SIGWINCH, sigwinch_handler); 2144 signal(SIGALRM, sigalrm_handler); 2145 2146 itimerval.it_value.tv_sec = 0; 2147 itimerval.it_value.tv_usec = 250000; 2148 itimerval.it_interval.tv_sec = 0; 2149 itimerval.it_interval.tv_usec = 250000; 2150 setitimer(ITIMER_REAL, &itimerval, NULL); 2151 2152 requested_time.tv_sec = 0; 2153 requested_time.tv_nsec = 250000000; 2154 2155 while(1) { 2156 int res = nanosleep(&requested_time, &remaining); 2157 2158 if(res == -1 && errno != EINTR) 2159 EXIT_UNSQUASH("nanosleep failed in progress thread\n"); 2160 2161 if(progress_enabled) { 2162 pthread_mutex_lock(&screen_mutex); 2163 progress_bar(sym_count + dev_count + 2164 fifo_count + cur_blocks, total_inodes - 2165 total_files + total_blocks, columns); 2166 pthread_mutex_unlock(&screen_mutex); 2167 } 2168 } 2169} 2170 2171 2172void initialise_threads(int fragment_buffer_size, int data_buffer_size) 2173{ 2174 struct rlimit rlim; 2175 int i, max_files, res; 2176 sigset_t sigmask, old_mask; 2177 2178 /* block SIGQUIT and SIGHUP, these are handled by the info thread */ 2179 sigemptyset(&sigmask); 2180 sigaddset(&sigmask, SIGQUIT); 2181 sigaddset(&sigmask, SIGHUP); 2182 sigaddset(&sigmask, SIGALRM); 2183 if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1) 2184 EXIT_UNSQUASH("Failed to set signal mask in initialise_threads" 2185 "\n"); 2186 2187 /* 2188 * temporarily block these signals so the created sub-threads will 2189 * ignore them, ensuring the main thread handles them 2190 */ 2191 sigemptyset(&sigmask); 2192 sigaddset(&sigmask, SIGINT); 2193 sigaddset(&sigmask, SIGTERM); 2194 if(pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1) 2195 EXIT_UNSQUASH("Failed to set signal mask in initialise_threads" 2196 "\n"); 2197 2198 if(processors == -1) { 2199#ifndef linux 2200 int mib[2]; 2201 size_t len = sizeof(processors); 2202 2203 mib[0] = CTL_HW; 2204#ifdef HW_AVAILCPU 2205 mib[1] = HW_AVAILCPU; 2206#else 2207 mib[1] = HW_NCPU; 2208#endif 2209 2210 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) { 2211 ERROR("Failed to get number of available processors. " 2212 "Defaulting to 1\n"); 2213 processors = 1; 2214 } 2215#else 2216 processors = sysconf(_SC_NPROCESSORS_ONLN); 2217#endif 2218 } 2219 2220 if(add_overflow(processors, 3) || 2221 multiply_overflow(processors + 3, sizeof(pthread_t))) 2222 EXIT_UNSQUASH("Processors too large\n"); 2223 2224 thread = malloc((3 + processors) * sizeof(pthread_t)); 2225 if(thread == NULL) 2226 EXIT_UNSQUASH("Out of memory allocating thread descriptors\n"); 2227 inflator_thread = &thread[3]; 2228 2229 /* 2230 * dimensioning the to_reader and to_inflate queues. The size of 2231 * these queues is directly related to the amount of block 2232 * read-ahead possible. To_reader queues block read requests to 2233 * the reader thread and to_inflate queues block decompression 2234 * requests to the inflate thread(s) (once the block has been read by 2235 * the reader thread). The amount of read-ahead is determined by 2236 * the combined size of the data_block and fragment caches which 2237 * determine the total number of blocks which can be "in flight" 2238 * at any one time (either being read or being decompressed) 2239 * 2240 * The maximum file open limit, however, affects the read-ahead 2241 * possible, in that for normal sizes of the fragment and data block 2242 * caches, where the incoming files have few data blocks or one fragment 2243 * only, the file open limit is likely to be reached before the 2244 * caches are full. This means the worst case sizing of the combined 2245 * sizes of the caches is unlikely to ever be necessary. However, is is 2246 * obvious read-ahead up to the data block cache size is always possible 2247 * irrespective of the file open limit, because a single file could 2248 * contain that number of blocks. 2249 * 2250 * Choosing the size as "file open limit + data block cache size" seems 2251 * to be a reasonable estimate. We can reasonably assume the maximum 2252 * likely read-ahead possible is data block cache size + one fragment 2253 * per open file. 2254 * 2255 * dimensioning the to_writer queue. The size of this queue is 2256 * directly related to the amount of block read-ahead possible. 2257 * However, unlike the to_reader and to_inflate queues, this is 2258 * complicated by the fact the to_writer queue not only contains 2259 * entries for fragments and data_blocks but it also contains 2260 * file entries, one per open file in the read-ahead. 2261 * 2262 * Choosing the size as "2 * (file open limit) + 2263 * data block cache size" seems to be a reasonable estimate. 2264 * We can reasonably assume the maximum likely read-ahead possible 2265 * is data block cache size + one fragment per open file, and then 2266 * we will have a file_entry for each open file. 2267 */ 2268 res = getrlimit(RLIMIT_NOFILE, &rlim); 2269 if (res == -1) { 2270 ERROR("failed to get open file limit! Defaulting to 1\n"); 2271 rlim.rlim_cur = 1; 2272 } 2273 2274 if (rlim.rlim_cur != RLIM_INFINITY) { 2275 /* 2276 * leave OPEN_FILE_MARGIN free (rlim_cur includes fds used by 2277 * stdin, stdout, stderr and filesystem fd 2278 */ 2279 if (rlim.rlim_cur <= OPEN_FILE_MARGIN) 2280 /* no margin, use minimum possible */ 2281 max_files = 1; 2282 else 2283 max_files = rlim.rlim_cur - OPEN_FILE_MARGIN; 2284 } else 2285 max_files = -1; 2286 2287 /* set amount of available files for use by open_wait and close_wake */ 2288 open_init(max_files); 2289 2290 /* 2291 * allocate to_reader, to_inflate and to_writer queues. Set based on 2292 * open file limit and cache size, unless open file limit is unlimited, 2293 * in which case set purely based on cache limits 2294 * 2295 * In doing so, check that the user supplied values do not overflow 2296 * a signed int 2297 */ 2298 if (max_files != -1) { 2299 if(add_overflow(data_buffer_size, max_files) || 2300 add_overflow(data_buffer_size, max_files * 2)) 2301 EXIT_UNSQUASH("Data queue size is too large\n"); 2302 2303 to_reader = queue_init(max_files + data_buffer_size); 2304 to_inflate = queue_init(max_files + data_buffer_size); 2305 to_writer = queue_init(max_files * 2 + data_buffer_size); 2306 } else { 2307 int all_buffers_size; 2308 2309 if(add_overflow(fragment_buffer_size, data_buffer_size)) 2310 EXIT_UNSQUASH("Data and fragment queues combined are" 2311 " too large\n"); 2312 2313 all_buffers_size = fragment_buffer_size + data_buffer_size; 2314 2315 if(add_overflow(all_buffers_size, all_buffers_size)) 2316 EXIT_UNSQUASH("Data and fragment queues combined are" 2317 " too large\n"); 2318 2319 to_reader = queue_init(all_buffers_size); 2320 to_inflate = queue_init(all_buffers_size); 2321 to_writer = queue_init(all_buffers_size * 2); 2322 } 2323 2324 from_writer = queue_init(1); 2325 2326 fragment_cache = cache_init(block_size, fragment_buffer_size); 2327 data_cache = cache_init(block_size, data_buffer_size); 2328 pthread_create(&thread[0], NULL, reader, NULL); 2329 pthread_create(&thread[1], NULL, writer, NULL); 2330 pthread_create(&thread[2], NULL, progress_thread, NULL); 2331 init_info(); 2332 pthread_mutex_init(&fragment_mutex, NULL); 2333 2334 for(i = 0; i < processors; i++) { 2335 if(pthread_create(&inflator_thread[i], NULL, inflator, NULL) != 2336 0) 2337 EXIT_UNSQUASH("Failed to create thread\n"); 2338 } 2339 2340 printf("Parallel unsquashfs: Using %d processor%s\n", processors, 2341 processors == 1 ? "" : "s"); 2342 2343 if(pthread_sigmask(SIG_SETMASK, &old_mask, NULL) == -1) 2344 EXIT_UNSQUASH("Failed to set signal mask in initialise_threads" 2345 "\n"); 2346} 2347 2348 2349void enable_progress_bar() 2350{ 2351 pthread_mutex_lock(&screen_mutex); 2352 progress_enabled = progress; 2353 pthread_mutex_unlock(&screen_mutex); 2354} 2355 2356 2357void disable_progress_bar() 2358{ 2359 pthread_mutex_lock(&screen_mutex); 2360 if(progress_enabled) { 2361 progress_bar(sym_count + dev_count + fifo_count + cur_blocks, 2362 total_inodes - total_files + total_blocks, columns); 2363 printf("\n"); 2364 } 2365 progress_enabled = FALSE; 2366 pthread_mutex_unlock(&screen_mutex); 2367} 2368 2369 2370void progressbar_error(char *fmt, ...) 2371{ 2372 va_list ap; 2373 2374 pthread_mutex_lock(&screen_mutex); 2375 2376 if(progress_enabled) 2377 fprintf(stderr, "\n"); 2378 2379 va_start(ap, fmt); 2380 vfprintf(stderr, fmt, ap); 2381 va_end(ap); 2382 2383 pthread_mutex_unlock(&screen_mutex); 2384} 2385 2386 2387void progressbar_info(char *fmt, ...) 2388{ 2389 va_list ap; 2390 2391 pthread_mutex_lock(&screen_mutex); 2392 2393 if(progress_enabled) 2394 printf("\n"); 2395 2396 va_start(ap, fmt); 2397 vprintf(fmt, ap); 2398 va_end(ap); 2399 2400 pthread_mutex_unlock(&screen_mutex); 2401} 2402 2403void progress_bar(long long current, long long max, int columns) 2404{ 2405 char rotate_list[] = { '|', '/', '-', '\\' }; 2406 int max_digits, used, hashes, spaces; 2407 static int tty = -1; 2408 2409 if(max == 0) 2410 return; 2411 2412 max_digits = floor(log10(max)) + 1; 2413 used = max_digits * 2 + 11; 2414 hashes = (current * (columns - used)) / max; 2415 spaces = columns - used - hashes; 2416 2417 if((current > max) || (columns - used < 0)) 2418 return; 2419 2420 if(tty == -1) 2421 tty = isatty(STDOUT_FILENO); 2422 if(!tty) { 2423 static long long previous = -1; 2424 2425 /* 2426 * Updating much more frequently than this results in huge 2427 * log files. 2428 */ 2429 if((current % 100) != 0 && current != max) 2430 return; 2431 /* Don't update just to rotate the spinner. */ 2432 if(current == previous) 2433 return; 2434 previous = current; 2435 } 2436 2437 printf("\r["); 2438 2439 while (hashes --) 2440 putchar('='); 2441 2442 putchar(rotate_list[rotate]); 2443 2444 while(spaces --) 2445 putchar(' '); 2446 2447 printf("] %*lld/%*lld", max_digits, current, max_digits, max); 2448 printf(" %3lld%%", current * 100 / max); 2449 fflush(stdout); 2450} 2451 2452 2453int parse_number(char *arg, int *res) 2454{ 2455 char *b; 2456 long number = strtol(arg, &b, 10); 2457 2458 /* check for trailing junk after number */ 2459 if(*b != '\0') 2460 return 0; 2461 2462 /* 2463 * check for strtol underflow or overflow in conversion. 2464 * Note: strtol can validly return LONG_MIN and LONG_MAX 2465 * if the user entered these values, but, additional code 2466 * to distinguish this scenario is unnecessary, because for 2467 * our purposes LONG_MIN and LONG_MAX are too large anyway 2468 */ 2469 if(number == LONG_MIN || number == LONG_MAX) 2470 return 0; 2471 2472 /* reject negative numbers as invalid */ 2473 if(number < 0) 2474 return 0; 2475 2476 /* check if long result will overflow signed int */ 2477 if(number > INT_MAX) 2478 return 0; 2479 2480 *res = number; 2481 return 1; 2482} 2483 2484 2485#define VERSION() \ 2486 printf("unsquashfs version 4.3 (2014/05/12)\n");\ 2487 printf("copyright (C) 2014 Phillip Lougher "\ 2488 "<phillip@squashfs.org.uk>\n\n");\ 2489 printf("This program is free software; you can redistribute it and/or"\ 2490 "\n");\ 2491 printf("modify it under the terms of the GNU General Public License"\ 2492 "\n");\ 2493 printf("as published by the Free Software Foundation; either version "\ 2494 "2,\n");\ 2495 printf("or (at your option) any later version.\n\n");\ 2496 printf("This program is distributed in the hope that it will be "\ 2497 "useful,\n");\ 2498 printf("but WITHOUT ANY WARRANTY; without even the implied warranty of"\ 2499 "\n");\ 2500 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\ 2501 "\n");\ 2502 printf("GNU General Public License for more details.\n"); 2503int main(int argc, char *argv[]) 2504{ 2505 char *dest = "squashfs-root"; 2506 int i, stat_sys = FALSE, version = FALSE; 2507 int n; 2508 struct pathnames *paths = NULL; 2509 struct pathname *path = NULL; 2510 long long directory_table_end; 2511 int fragment_buffer_size = FRAGMENT_BUFFER_DEFAULT; 2512 int data_buffer_size = DATA_BUFFER_DEFAULT; 2513 2514 pthread_mutex_init(&screen_mutex, NULL); 2515 root_process = geteuid() == 0; 2516 if(root_process) 2517 umask(0); 2518 2519 for(i = 1; i < argc; i++) { 2520 if(*argv[i] != '-') 2521 break; 2522 if(strcmp(argv[i], "-version") == 0 || 2523 strcmp(argv[i], "-v") == 0) { 2524 VERSION(); 2525 version = TRUE; 2526 } else if(strcmp(argv[i], "-info") == 0 || 2527 strcmp(argv[i], "-i") == 0) 2528 info = TRUE; 2529 else if(strcmp(argv[i], "-ls") == 0 || 2530 strcmp(argv[i], "-l") == 0) 2531 lsonly = TRUE; 2532 else if(strcmp(argv[i], "-no-progress") == 0 || 2533 strcmp(argv[i], "-n") == 0) 2534 progress = FALSE; 2535 else if(strcmp(argv[i], "-no-xattrs") == 0 || 2536 strcmp(argv[i], "-no") == 0) 2537 no_xattrs = TRUE; 2538 else if(strcmp(argv[i], "-xattrs") == 0 || 2539 strcmp(argv[i], "-x") == 0) 2540 no_xattrs = FALSE; 2541 else if(strcmp(argv[i], "-user-xattrs") == 0 || 2542 strcmp(argv[i], "-u") == 0) { 2543 user_xattrs = TRUE; 2544 no_xattrs = FALSE; 2545 } else if(strcmp(argv[i], "-dest") == 0 || 2546 strcmp(argv[i], "-d") == 0) { 2547 if(++i == argc) { 2548 fprintf(stderr, "%s: -dest missing filename\n", 2549 argv[0]); 2550 exit(1); 2551 } 2552 dest = argv[i]; 2553 } else if(strcmp(argv[i], "-processors") == 0 || 2554 strcmp(argv[i], "-p") == 0) { 2555 if((++i == argc) || 2556 !parse_number(argv[i], 2557 &processors)) { 2558 ERROR("%s: -processors missing or invalid " 2559 "processor number\n", argv[0]); 2560 exit(1); 2561 } 2562 if(processors < 1) { 2563 ERROR("%s: -processors should be 1 or larger\n", 2564 argv[0]); 2565 exit(1); 2566 } 2567 } else if(strcmp(argv[i], "-data-queue") == 0 || 2568 strcmp(argv[i], "-da") == 0) { 2569 if((++i == argc) || 2570 !parse_number(argv[i], 2571 &data_buffer_size)) { 2572 ERROR("%s: -data-queue missing or invalid " 2573 "queue size\n", argv[0]); 2574 exit(1); 2575 } 2576 if(data_buffer_size < 1) { 2577 ERROR("%s: -data-queue should be 1 Mbyte or " 2578 "larger\n", argv[0]); 2579 exit(1); 2580 } 2581 } else if(strcmp(argv[i], "-frag-queue") == 0 || 2582 strcmp(argv[i], "-fr") == 0) { 2583 if((++i == argc) || 2584 !parse_number(argv[i], 2585 &fragment_buffer_size)) { 2586 ERROR("%s: -frag-queue missing or invalid " 2587 "queue size\n", argv[0]); 2588 exit(1); 2589 } 2590 if(fragment_buffer_size < 1) { 2591 ERROR("%s: -frag-queue should be 1 Mbyte or " 2592 "larger\n", argv[0]); 2593 exit(1); 2594 } 2595 } else if(strcmp(argv[i], "-force") == 0 || 2596 strcmp(argv[i], "-f") == 0) 2597 force = TRUE; 2598 else if(strcmp(argv[i], "-stat") == 0 || 2599 strcmp(argv[i], "-s") == 0) 2600 stat_sys = TRUE; 2601 else if(strcmp(argv[i], "-lls") == 0 || 2602 strcmp(argv[i], "-ll") == 0) { 2603 lsonly = TRUE; 2604 short_ls = FALSE; 2605 } else if(strcmp(argv[i], "-linfo") == 0 || 2606 strcmp(argv[i], "-li") == 0) { 2607 info = TRUE; 2608 short_ls = FALSE; 2609 } else if(strcmp(argv[i], "-ef") == 0 || 2610 strcmp(argv[i], "-e") == 0) { 2611 if(++i == argc) { 2612 fprintf(stderr, "%s: -ef missing filename\n", 2613 argv[0]); 2614 exit(1); 2615 } 2616 path = process_extract_files(path, argv[i]); 2617 } else if(strcmp(argv[i], "-regex") == 0 || 2618 strcmp(argv[i], "-r") == 0) 2619 use_regex = TRUE; 2620 else 2621 goto options; 2622 } 2623 2624 if(lsonly || info) 2625 progress = FALSE; 2626 2627#ifdef SQUASHFS_TRACE 2628 /* 2629 * Disable progress bar if full debug tracing is enabled. 2630 * The progress bar in this case just gets in the way of the 2631 * debug trace output 2632 */ 2633 progress = FALSE; 2634#endif 2635 2636 if(i == argc) { 2637 if(!version) { 2638options: 2639 ERROR("SYNTAX: %s [options] filesystem [directories or " 2640 "files to extract]\n", argv[0]); 2641 ERROR("\t-v[ersion]\t\tprint version, licence and " 2642 "copyright information\n"); 2643 ERROR("\t-d[est] <pathname>\tunsquash to <pathname>, " 2644 "default \"squashfs-root\"\n"); 2645 ERROR("\t-n[o-progress]\t\tdon't display the progress " 2646 "bar\n"); 2647 ERROR("\t-no[-xattrs]\t\tdon't extract xattrs in file system" 2648 NOXOPT_STR"\n"); 2649 ERROR("\t-x[attrs]\t\textract xattrs in file system" 2650 XOPT_STR "\n"); 2651 ERROR("\t-u[ser-xattrs]\t\tonly extract user xattrs in " 2652 "file system.\n\t\t\t\tEnables extracting " 2653 "xattrs\n"); 2654 ERROR("\t-p[rocessors] <number>\tuse <number> " 2655 "processors. By default will use\n"); 2656 ERROR("\t\t\t\tnumber of processors available\n"); 2657 ERROR("\t-i[nfo]\t\t\tprint files as they are " 2658 "unsquashed\n"); 2659 ERROR("\t-li[nfo]\t\tprint files as they are " 2660 "unsquashed with file\n"); 2661 ERROR("\t\t\t\tattributes (like ls -l output)\n"); 2662 ERROR("\t-l[s]\t\t\tlist filesystem, but don't unsquash" 2663 "\n"); 2664 ERROR("\t-ll[s]\t\t\tlist filesystem with file " 2665 "attributes (like\n"); 2666 ERROR("\t\t\t\tls -l output), but don't unsquash\n"); 2667 ERROR("\t-f[orce]\t\tif file already exists then " 2668 "overwrite\n"); 2669 ERROR("\t-s[tat]\t\t\tdisplay filesystem superblock " 2670 "information\n"); 2671 ERROR("\t-e[f] <extract file>\tlist of directories or " 2672 "files to extract.\n\t\t\t\tOne per line\n"); 2673 ERROR("\t-da[ta-queue] <size>\tSet data queue to " 2674 "<size> Mbytes. Default %d\n\t\t\t\tMbytes\n", 2675 DATA_BUFFER_DEFAULT); 2676 ERROR("\t-fr[ag-queue] <size>\tSet fragment queue to " 2677 "<size> Mbytes. Default\n\t\t\t\t%d Mbytes\n", 2678 FRAGMENT_BUFFER_DEFAULT); 2679 ERROR("\t-r[egex]\t\ttreat extract names as POSIX " 2680 "regular expressions\n"); 2681 ERROR("\t\t\t\trather than use the default shell " 2682 "wildcard\n\t\t\t\texpansion (globbing)\n"); 2683 ERROR("\nDecompressors available:\n"); 2684 display_compressors("", ""); 2685 } 2686 exit(1); 2687 } 2688 2689 for(n = i + 1; n < argc; n++) 2690 path = add_path(path, argv[n], argv[n]); 2691 2692 if((fd = open(argv[i], O_RDONLY)) == -1) { 2693 ERROR("Could not open %s, because %s\n", argv[i], 2694 strerror(errno)); 2695 exit(1); 2696 } 2697 2698 if(read_super(argv[i]) == FALSE) 2699 exit(1); 2700 2701 if(stat_sys) { 2702 squashfs_stat(argv[i]); 2703 exit(0); 2704 } 2705 2706 if(!check_compression(comp)) 2707 exit(1); 2708 2709 block_size = sBlk.s.block_size; 2710 block_log = sBlk.s.block_log; 2711 2712 /* 2713 * Sanity check block size and block log. 2714 * 2715 * Check they're within correct limits 2716 */ 2717 if(block_size > SQUASHFS_FILE_MAX_SIZE || 2718 block_log > SQUASHFS_FILE_MAX_LOG) 2719 EXIT_UNSQUASH("Block size or block_log too large." 2720 " File system is corrupt.\n"); 2721 2722 /* 2723 * Check block_size and block_log match 2724 */ 2725 if(block_size != (1 << block_log)) 2726 EXIT_UNSQUASH("Block size and block_log do not match." 2727 " File system is corrupt.\n"); 2728 2729 /* 2730 * convert from queue size in Mbytes to queue size in 2731 * blocks. 2732 * 2733 * In doing so, check that the user supplied values do not 2734 * overflow a signed int 2735 */ 2736 if(shift_overflow(fragment_buffer_size, 20 - block_log)) 2737 EXIT_UNSQUASH("Fragment queue size is too large\n"); 2738 else 2739 fragment_buffer_size <<= 20 - block_log; 2740 2741 if(shift_overflow(data_buffer_size, 20 - block_log)) 2742 EXIT_UNSQUASH("Data queue size is too large\n"); 2743 else 2744 data_buffer_size <<= 20 - block_log; 2745 2746 initialise_threads(fragment_buffer_size, data_buffer_size); 2747 2748 fragment_data = malloc(block_size); 2749 if(fragment_data == NULL) 2750 EXIT_UNSQUASH("failed to allocate fragment_data\n"); 2751 2752 file_data = malloc(block_size); 2753 if(file_data == NULL) 2754 EXIT_UNSQUASH("failed to allocate file_data"); 2755 2756 data = malloc(block_size); 2757 if(data == NULL) 2758 EXIT_UNSQUASH("failed to allocate data\n"); 2759 2760 created_inode = malloc(sBlk.s.inodes * sizeof(char *)); 2761 if(created_inode == NULL) 2762 EXIT_UNSQUASH("failed to allocate created_inode\n"); 2763 2764 memset(created_inode, 0, sBlk.s.inodes * sizeof(char *)); 2765 2766 if(s_ops.read_uids_guids() == FALSE) 2767 EXIT_UNSQUASH("failed to uid/gid table\n"); 2768 2769 if(s_ops.read_fragment_table(&directory_table_end) == FALSE) 2770 EXIT_UNSQUASH("failed to read fragment table\n"); 2771 2772 if(read_inode_table(sBlk.s.inode_table_start, 2773 sBlk.s.directory_table_start) == FALSE) 2774 EXIT_UNSQUASH("failed to read inode table\n"); 2775 2776 if(read_directory_table(sBlk.s.directory_table_start, 2777 directory_table_end) == FALSE) 2778 EXIT_UNSQUASH("failed to read directory table\n"); 2779 2780 if(no_xattrs) 2781 sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK; 2782 2783 if(read_xattrs_from_disk(fd, &sBlk.s) == 0) 2784 EXIT_UNSQUASH("failed to read the xattr table\n"); 2785 2786 if(path) { 2787 paths = init_subdir(); 2788 paths = add_subdir(paths, path); 2789 } 2790 2791 pre_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode), 2792 SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths); 2793 2794 memset(created_inode, 0, sBlk.s.inodes * sizeof(char *)); 2795 inode_number = 1; 2796 2797 printf("%d inodes (%d blocks) to write\n\n", total_inodes, 2798 total_inodes - total_files + total_blocks); 2799 2800 enable_progress_bar(); 2801 2802 dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode), 2803 SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths); 2804 2805 queue_put(to_writer, NULL); 2806 queue_get(from_writer); 2807 2808 disable_progress_bar(); 2809 2810 if(!lsonly) { 2811 printf("\n"); 2812 printf("created %d files\n", file_count); 2813 printf("created %d directories\n", dir_count); 2814 printf("created %d symlinks\n", sym_count); 2815 printf("created %d devices\n", dev_count); 2816 printf("created %d fifos\n", fifo_count); 2817 } 2818 2819 return 0; 2820} 2821