1 /* 2 * Create 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 (at) squashfs.org.uk> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 2, 12 * or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 * 23 * mksquashfs.c 24 */ 25 26 #define FALSE 0 27 #define TRUE 1 28 #define MAX_LINE 16384 29 30 #include <pwd.h> 31 #include <grp.h> 32 #include <time.h> 33 #include <unistd.h> 34 #include <stdio.h> 35 #include <stddef.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <fcntl.h> 39 #include <errno.h> 40 #include <dirent.h> 41 #include <string.h> 42 #include <stdlib.h> 43 #include <signal.h> 44 #include <setjmp.h> 45 #include <sys/types.h> 46 #include <sys/mman.h> 47 #include <pthread.h> 48 #include <regex.h> 49 #include <fnmatch.h> 50 #include <sys/wait.h> 51 #include <limits.h> 52 #include <ctype.h> 53 54 #ifndef linux 55 #define __BYTE_ORDER BYTE_ORDER 56 #define __BIG_ENDIAN BIG_ENDIAN 57 #define __LITTLE_ENDIAN LITTLE_ENDIAN 58 #include <sys/sysctl.h> 59 #else 60 #include <endian.h> 61 #include <sys/sysinfo.h> 62 #endif 63 64 #include "squashfs_fs.h" 65 #include "squashfs_swap.h" 66 #include "mksquashfs.h" 67 #include "sort.h" 68 #include "pseudo.h" 69 #include "compressor.h" 70 #include "xattr.h" 71 #include "action.h" 72 #include "error.h" 73 #include "progressbar.h" 74 #include "info.h" 75 #include "caches-queues-lists.h" 76 #include "read_fs.h" 77 #include "restore.h" 78 #include "process_fragments.h" 79 80 /* ANDROID CHANGES START*/ 81 #ifdef ANDROID 82 #include "android.h" 83 int android_config = FALSE; 84 char *context_file = NULL; 85 char *mount_point = NULL; 86 char *target_out_path = NULL; 87 #endif 88 /* ANDROID CHANGES END */ 89 90 int delete = FALSE; 91 int fd; 92 struct squashfs_super_block sBlk; 93 94 /* filesystem flags for building */ 95 int comp_opts = FALSE; 96 int no_xattrs = XATTR_DEF; 97 int noX = FALSE; 98 int duplicate_checking = TRUE; 99 int noF = FALSE; 100 int no_fragments = FALSE; 101 int always_use_fragments = FALSE; 102 int noI = FALSE; 103 int noD = FALSE; 104 int silent = TRUE; 105 int exportable = TRUE; 106 int sparse_files = TRUE; 107 int old_exclude = TRUE; 108 int use_regex = FALSE; 109 int nopad = FALSE; 110 int exit_on_error = FALSE; 111 112 long long global_uid = -1, global_gid = -1; 113 114 /* superblock attributes */ 115 int block_size = SQUASHFS_FILE_SIZE, block_log; 116 unsigned int id_count = 0; 117 int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0, 118 sock_count = 0; 119 120 /* write position within data section */ 121 long long bytes = 0, total_bytes = 0; 122 123 /* in memory directory table - possibly compressed */ 124 char *directory_table = NULL; 125 unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0; 126 127 /* cached directory table */ 128 char *directory_data_cache = NULL; 129 unsigned int directory_cache_bytes = 0, directory_cache_size = 0; 130 131 /* in memory inode table - possibly compressed */ 132 char *inode_table = NULL; 133 unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0; 134 135 /* cached inode table */ 136 char *data_cache = NULL; 137 unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0; 138 139 /* inode lookup table */ 140 squashfs_inode *inode_lookup_table = NULL; 141 142 /* in memory directory data */ 143 #define I_COUNT_SIZE 128 144 #define DIR_ENTRIES 32 145 #define INODE_HASH_SIZE 65536 146 #define INODE_HASH_MASK (INODE_HASH_SIZE - 1) 147 #define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK) 148 149 struct cached_dir_index { 150 struct squashfs_dir_index index; 151 char *name; 152 }; 153 154 struct directory { 155 unsigned int start_block; 156 unsigned int size; 157 unsigned char *buff; 158 unsigned char *p; 159 unsigned int entry_count; 160 unsigned char *entry_count_p; 161 unsigned int i_count; 162 unsigned int i_size; 163 struct cached_dir_index *index; 164 unsigned char *index_count_p; 165 unsigned int inode_number; 166 }; 167 168 struct inode_info *inode_info[INODE_HASH_SIZE]; 169 170 /* hash tables used to do fast duplicate searches in duplicate check */ 171 struct file_info *dupl[65536]; 172 int dup_files = 0; 173 174 /* exclude file handling */ 175 /* list of exclude dirs/files */ 176 struct exclude_info { 177 dev_t st_dev; 178 ino_t st_ino; 179 }; 180 181 #define EXCLUDE_SIZE 8192 182 int exclude = 0; 183 struct exclude_info *exclude_paths = NULL; 184 int old_excluded(char *filename, struct stat *buf); 185 186 struct path_entry { 187 char *name; 188 regex_t *preg; 189 struct pathname *paths; 190 }; 191 192 struct pathname { 193 int names; 194 struct path_entry *name; 195 }; 196 197 struct pathnames { 198 int count; 199 struct pathname *path[0]; 200 }; 201 #define PATHS_ALLOC_SIZE 10 202 203 struct pathnames *paths = NULL; 204 struct pathname *path = NULL; 205 struct pathname *stickypath = NULL; 206 int excluded(char *name, struct pathnames *paths, struct pathnames **new); 207 208 int fragments = 0; 209 210 #define FRAG_SIZE 32768 211 212 struct squashfs_fragment_entry *fragment_table = NULL; 213 int fragments_outstanding = 0; 214 215 int fragments_locked = FALSE; 216 217 /* current inode number for directories and non directories */ 218 unsigned int inode_no = 1; 219 unsigned int root_inode_number = 0; 220 221 /* list of source dirs/files */ 222 int source = 0; 223 char **source_path; 224 225 /* list of root directory entries read from original filesystem */ 226 int old_root_entries = 0; 227 struct old_root_entry_info { 228 char *name; 229 struct inode_info inode; 230 }; 231 struct old_root_entry_info *old_root_entry; 232 233 /* restore orignal filesystem state if appending to existing filesystem is 234 * cancelled */ 235 int appending = FALSE; 236 char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed; 237 238 long long sbytes, stotal_bytes; 239 240 unsigned int sinode_bytes, scache_bytes, sdirectory_bytes, 241 sdirectory_cache_bytes, sdirectory_compressed_bytes, 242 stotal_inode_bytes, stotal_directory_bytes, 243 sinode_count = 0, sfile_count, ssym_count, sdev_count, 244 sdir_count, sfifo_count, ssock_count, sdup_files; 245 int sfragments; 246 int threads; 247 248 /* flag whether destination file is a block device */ 249 int block_device = FALSE; 250 251 /* flag indicating whether files are sorted using sort list(s) */ 252 int sorted = FALSE; 253 254 /* save destination file name for deleting on error */ 255 char *destination_file = NULL; 256 257 /* recovery file for abnormal exit on appending */ 258 char *recovery_file = NULL; 259 int recover = TRUE; 260 261 struct id *id_hash_table[ID_ENTRIES]; 262 struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS]; 263 unsigned int uid_count = 0, guid_count = 0; 264 unsigned int sid_count = 0, suid_count = 0, sguid_count = 0; 265 266 struct cache *reader_buffer, *fragment_buffer, *reserve_cache; 267 struct cache *bwriter_buffer, *fwriter_buffer; 268 struct queue *to_reader, *to_deflate, *to_writer, *from_writer, 269 *to_frag, *locked_fragment, *to_process_frag; 270 struct seq_queue *to_main; 271 pthread_t reader_thread, writer_thread, main_thread; 272 pthread_t *deflator_thread, *frag_deflator_thread, *frag_thread; 273 pthread_t *restore_thread = NULL; 274 pthread_mutex_t fragment_mutex = PTHREAD_MUTEX_INITIALIZER; 275 pthread_mutex_t pos_mutex = PTHREAD_MUTEX_INITIALIZER; 276 pthread_mutex_t dup_mutex = PTHREAD_MUTEX_INITIALIZER; 277 278 /* user options that control parallelisation */ 279 int processors = -1; 280 int bwriter_size; 281 282 /* compression operations */ 283 struct compressor *comp = NULL; 284 int compressor_opt_parsed = FALSE; 285 void *stream = NULL; 286 287 /* xattr stats */ 288 unsigned int xattr_bytes = 0, total_xattr_bytes = 0; 289 290 /* fragment to file mapping used when appending */ 291 int append_fragments = 0; 292 struct append_file **file_mapping; 293 294 /* root of the in-core directory structure */ 295 struct dir_info *root_dir; 296 297 static char *read_from_disk(long long start, unsigned int avail_bytes); 298 void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, 299 int type); 300 struct file_info *duplicate(long long file_size, long long bytes, 301 unsigned int **block_list, long long *start, struct fragment **fragment, 302 struct file_buffer *file_buffer, int blocks, unsigned short checksum, 303 int checksum_flag); 304 struct dir_info *dir_scan1(char *, char *, struct pathnames *, 305 struct dir_ent *(_readdir)(struct dir_info *), int); 306 void dir_scan2(struct dir_info *dir, struct pseudo *pseudo); 307 void dir_scan3(struct dir_info *dir); 308 void dir_scan4(struct dir_info *dir); 309 void dir_scan5(struct dir_info *dir); 310 void dir_scan6(struct dir_info *dir); 311 void dir_scan7(squashfs_inode *inode, struct dir_info *dir_info); 312 struct file_info *add_non_dup(long long file_size, long long bytes, 313 unsigned int *block_list, long long start, struct fragment *fragment, 314 unsigned short checksum, unsigned short fragment_checksum, 315 int checksum_flag, int checksum_frag_flag); 316 long long generic_write_table(int, void *, int, void *, int); 317 void restorefs(); 318 struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth); 319 void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad); 320 unsigned short get_checksum_mem(char *buff, int bytes); 321 void check_usable_phys_mem(int total_mem); 322 323 324 void prep_exit() 325 { 326 if(restore_thread) { 327 if(pthread_self() == *restore_thread) { 328 /* 329 * Recursive failure when trying to restore filesystem! 330 * Nothing to do except to exit, otherwise we'll just 331 * appear to hang. The user should be able to restore 332 * from the recovery file (which is why it was added, in 333 * case of catastrophic failure in Mksquashfs) 334 */ 335 exit(1); 336 } else { 337 /* signal the restore thread to restore */ 338 pthread_kill(*restore_thread, SIGUSR1); 339 pthread_exit(NULL); 340 } 341 } else if(delete) { 342 if(destination_file && !block_device) 343 unlink(destination_file); 344 } else if(recovery_file) 345 unlink(recovery_file); 346 } 347 348 349 int add_overflow(int a, int b) 350 { 351 return (INT_MAX - a) < b; 352 } 353 354 355 int shift_overflow(int a, int shift) 356 { 357 return (INT_MAX >> shift) < a; 358 } 359 360 361 int multiply_overflow(int a, int multiplier) 362 { 363 return (INT_MAX / multiplier) < a; 364 } 365 366 367 int multiply_overflowll(long long a, int multiplier) 368 { 369 return (LLONG_MAX / multiplier) < a; 370 } 371 372 373 #define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) \ 374 + (((char *)A) - data_cache))) 375 376 377 void restorefs() 378 { 379 ERROR("Exiting - restoring original filesystem!\n\n"); 380 381 bytes = sbytes; 382 memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes); 383 memcpy(directory_data_cache, sdirectory_data_cache, 384 sdirectory_cache_bytes); 385 directory_cache_bytes = sdirectory_cache_bytes; 386 inode_bytes = sinode_bytes; 387 directory_bytes = sdirectory_bytes; 388 memcpy(directory_table + directory_bytes, sdirectory_compressed, 389 sdirectory_compressed_bytes); 390 directory_bytes += sdirectory_compressed_bytes; 391 total_bytes = stotal_bytes; 392 total_inode_bytes = stotal_inode_bytes; 393 total_directory_bytes = stotal_directory_bytes; 394 inode_count = sinode_count; 395 file_count = sfile_count; 396 sym_count = ssym_count; 397 dev_count = sdev_count; 398 dir_count = sdir_count; 399 fifo_count = sfifo_count; 400 sock_count = ssock_count; 401 dup_files = sdup_files; 402 fragments = sfragments; 403 id_count = sid_count; 404 restore_xattrs(); 405 write_filesystem_tables(&sBlk, nopad); 406 exit(1); 407 } 408 409 410 void sighandler() 411 { 412 EXIT_MKSQUASHFS(); 413 } 414 415 416 int mangle2(void *strm, char *d, char *s, int size, 417 int block_size, int uncompressed, int data_block) 418 { 419 int error, c_byte = 0; 420 421 if(!uncompressed) { 422 c_byte = compressor_compress(comp, strm, d, s, size, block_size, 423 &error); 424 if(c_byte == -1) 425 BAD_ERROR("mangle2:: %s compress failed with error " 426 "code %d\n", comp->name, error); 427 } 428 429 if(c_byte == 0 || c_byte >= size) { 430 memcpy(d, s, size); 431 return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK : 432 SQUASHFS_COMPRESSED_BIT); 433 } 434 435 return c_byte; 436 } 437 438 439 int mangle(char *d, char *s, int size, int block_size, 440 int uncompressed, int data_block) 441 { 442 return mangle2(stream, d, s, size, block_size, uncompressed, 443 data_block); 444 } 445 446 447 void *get_inode(int req_size) 448 { 449 int data_space; 450 unsigned short c_byte; 451 452 while(cache_bytes >= SQUASHFS_METADATA_SIZE) { 453 if((inode_size - inode_bytes) < 454 ((SQUASHFS_METADATA_SIZE << 1)) + 2) { 455 void *it = realloc(inode_table, inode_size + 456 (SQUASHFS_METADATA_SIZE << 1) + 2); 457 if(it == NULL) 458 MEM_ERROR(); 459 inode_table = it; 460 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2; 461 } 462 463 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, 464 data_cache, SQUASHFS_METADATA_SIZE, 465 SQUASHFS_METADATA_SIZE, noI, 0); 466 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte); 467 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1); 468 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET; 469 total_inode_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET; 470 memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE, 471 cache_bytes - SQUASHFS_METADATA_SIZE); 472 cache_bytes -= SQUASHFS_METADATA_SIZE; 473 } 474 475 data_space = (cache_size - cache_bytes); 476 if(data_space < req_size) { 477 int realloc_size = cache_size == 0 ? 478 ((req_size + SQUASHFS_METADATA_SIZE) & 479 ~(SQUASHFS_METADATA_SIZE - 1)) : req_size - 480 data_space; 481 482 void *dc = realloc(data_cache, cache_size + 483 realloc_size); 484 if(dc == NULL) 485 MEM_ERROR(); 486 cache_size += realloc_size; 487 data_cache = dc; 488 } 489 490 cache_bytes += req_size; 491 492 return data_cache + cache_bytes - req_size; 493 } 494 495 496 int read_bytes(int fd, void *buff, int bytes) 497 { 498 int res, count; 499 500 for(count = 0; count < bytes; count += res) { 501 res = read(fd, buff + count, bytes - count); 502 if(res < 1) { 503 if(res == 0) 504 goto bytes_read; 505 else if(errno != EINTR) { 506 ERROR("Read failed because %s\n", 507 strerror(errno)); 508 return -1; 509 } else 510 res = 0; 511 } 512 } 513 514 bytes_read: 515 return count; 516 } 517 518 519 int read_fs_bytes(int fd, long long byte, int bytes, void *buff) 520 { 521 off_t off = byte; 522 int res = 1; 523 524 TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n", 525 byte, bytes); 526 527 pthread_cleanup_push((void *) pthread_mutex_unlock, &pos_mutex); 528 pthread_mutex_lock(&pos_mutex); 529 if(lseek(fd, off, SEEK_SET) == -1) { 530 ERROR("read_fs_bytes: Lseek on destination failed because %s, " 531 "offset=0x%llx\n", strerror(errno), off); 532 res = 0; 533 } else if(read_bytes(fd, buff, bytes) < bytes) { 534 ERROR("Read on destination failed\n"); 535 res = 0; 536 } 537 538 pthread_cleanup_pop(1); 539 return res; 540 } 541 542 543 int write_bytes(int fd, void *buff, int bytes) 544 { 545 int res, count; 546 547 for(count = 0; count < bytes; count += res) { 548 res = write(fd, buff + count, bytes - count); 549 if(res == -1) { 550 if(errno != EINTR) { 551 ERROR("Write failed because %s\n", 552 strerror(errno)); 553 return -1; 554 } 555 res = 0; 556 } 557 } 558 559 return 0; 560 } 561 562 563 void write_destination(int fd, long long byte, int bytes, void *buff) 564 { 565 off_t off = byte; 566 567 pthread_cleanup_push((void *) pthread_mutex_unlock, &pos_mutex); 568 pthread_mutex_lock(&pos_mutex); 569 570 if(lseek(fd, off, SEEK_SET) == -1) { 571 ERROR("write_destination: Lseek on destination " 572 "failed because %s, offset=0x%llx\n", strerror(errno), 573 off); 574 BAD_ERROR("Probably out of space on output %s\n", 575 block_device ? "block device" : "filesystem"); 576 } 577 578 if(write_bytes(fd, buff, bytes) == -1) 579 BAD_ERROR("Failed to write to output %s\n", 580 block_device ? "block device" : "filesystem"); 581 582 pthread_cleanup_pop(1); 583 } 584 585 586 long long write_inodes() 587 { 588 unsigned short c_byte; 589 int avail_bytes; 590 char *datap = data_cache; 591 long long start_bytes = bytes; 592 593 while(cache_bytes) { 594 if(inode_size - inode_bytes < 595 ((SQUASHFS_METADATA_SIZE << 1) + 2)) { 596 void *it = realloc(inode_table, inode_size + 597 ((SQUASHFS_METADATA_SIZE << 1) + 2)); 598 if(it == NULL) 599 MEM_ERROR(); 600 inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2; 601 inode_table = it; 602 } 603 avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ? 604 SQUASHFS_METADATA_SIZE : cache_bytes; 605 c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, datap, 606 avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0); 607 TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte); 608 SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1); 609 inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET; 610 total_inode_bytes += avail_bytes + BLOCK_OFFSET; 611 datap += avail_bytes; 612 cache_bytes -= avail_bytes; 613 } 614 615 write_destination(fd, bytes, inode_bytes, inode_table); 616 bytes += inode_bytes; 617 618 return start_bytes; 619 } 620 621 622 long long write_directories() 623 { 624 unsigned short c_byte; 625 int avail_bytes; 626 char *directoryp = directory_data_cache; 627 long long start_bytes = bytes; 628 629 while(directory_cache_bytes) { 630 if(directory_size - directory_bytes < 631 ((SQUASHFS_METADATA_SIZE << 1) + 2)) { 632 void *dt = realloc(directory_table, 633 directory_size + ((SQUASHFS_METADATA_SIZE << 1) 634 + 2)); 635 if(dt == NULL) 636 MEM_ERROR(); 637 directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2; 638 directory_table = dt; 639 } 640 avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ? 641 SQUASHFS_METADATA_SIZE : directory_cache_bytes; 642 c_byte = mangle(directory_table + directory_bytes + 643 BLOCK_OFFSET, directoryp, avail_bytes, 644 SQUASHFS_METADATA_SIZE, noI, 0); 645 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes, 646 c_byte); 647 SQUASHFS_SWAP_SHORTS(&c_byte, 648 directory_table + directory_bytes, 1); 649 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + 650 BLOCK_OFFSET; 651 total_directory_bytes += avail_bytes + BLOCK_OFFSET; 652 directoryp += avail_bytes; 653 directory_cache_bytes -= avail_bytes; 654 } 655 write_destination(fd, bytes, directory_bytes, directory_table); 656 bytes += directory_bytes; 657 658 return start_bytes; 659 } 660 661 662 long long write_id_table() 663 { 664 unsigned int id_bytes = SQUASHFS_ID_BYTES(id_count); 665 unsigned int p[id_count]; 666 int i; 667 668 TRACE("write_id_table: ids %d, id_bytes %d\n", id_count, id_bytes); 669 for(i = 0; i < id_count; i++) { 670 TRACE("write_id_table: id index %d, id %d", i, id_table[i]->id); 671 SQUASHFS_SWAP_INTS(&id_table[i]->id, p + i, 1); 672 } 673 674 return generic_write_table(id_bytes, p, 0, NULL, noI); 675 } 676 677 678 struct id *get_id(unsigned int id) 679 { 680 int hash = ID_HASH(id); 681 struct id *entry = id_hash_table[hash]; 682 683 for(; entry; entry = entry->next) 684 if(entry->id == id) 685 break; 686 687 return entry; 688 } 689 690 691 struct id *create_id(unsigned int id) 692 { 693 int hash = ID_HASH(id); 694 struct id *entry = malloc(sizeof(struct id)); 695 if(entry == NULL) 696 MEM_ERROR(); 697 entry->id = id; 698 entry->index = id_count ++; 699 entry->flags = 0; 700 entry->next = id_hash_table[hash]; 701 id_hash_table[hash] = entry; 702 id_table[entry->index] = entry; 703 return entry; 704 } 705 706 707 unsigned int get_uid(unsigned int uid) 708 { 709 struct id *entry = get_id(uid); 710 711 if(entry == NULL) { 712 if(id_count == SQUASHFS_IDS) 713 BAD_ERROR("Out of uids!\n"); 714 entry = create_id(uid); 715 } 716 717 if((entry->flags & ISA_UID) == 0) { 718 entry->flags |= ISA_UID; 719 uid_count ++; 720 } 721 722 return entry->index; 723 } 724 725 726 unsigned int get_guid(unsigned int guid) 727 { 728 struct id *entry = get_id(guid); 729 730 if(entry == NULL) { 731 if(id_count == SQUASHFS_IDS) 732 BAD_ERROR("Out of gids!\n"); 733 entry = create_id(guid); 734 } 735 736 if((entry->flags & ISA_GID) == 0) { 737 entry->flags |= ISA_GID; 738 guid_count ++; 739 } 740 741 return entry->index; 742 } 743 744 745 #define ALLOC_SIZE 128 746 747 char *_pathname(struct dir_ent *dir_ent, char *pathname, int *size) 748 { 749 if(pathname == NULL) { 750 pathname = malloc(ALLOC_SIZE); 751 if(pathname == NULL) 752 MEM_ERROR(); 753 } 754 755 for(;;) { 756 int res = snprintf(pathname, *size, "%s/%s", 757 dir_ent->our_dir->pathname, 758 dir_ent->source_name ? : dir_ent->name); 759 760 if(res < 0) 761 BAD_ERROR("snprintf failed in pathname\n"); 762 else if(res >= *size) { 763 /* 764 * pathname is too small to contain the result, so 765 * increase it and try again 766 */ 767 *size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1); 768 pathname = realloc(pathname, *size); 769 if(pathname == NULL) 770 MEM_ERROR(); 771 } else 772 break; 773 } 774 775 return pathname; 776 } 777 778 779 char *pathname(struct dir_ent *dir_ent) 780 { 781 static char *pathname = NULL; 782 static int size = ALLOC_SIZE; 783 784 if (dir_ent->nonstandard_pathname) 785 return dir_ent->nonstandard_pathname; 786 787 return pathname = _pathname(dir_ent, pathname, &size); 788 } 789 790 791 char *pathname_reader(struct dir_ent *dir_ent) 792 { 793 static char *pathname = NULL; 794 static int size = ALLOC_SIZE; 795 796 if (dir_ent->nonstandard_pathname) 797 return dir_ent->nonstandard_pathname; 798 799 return pathname = _pathname(dir_ent, pathname, &size); 800 } 801 802 803 char *subpathname(struct dir_ent *dir_ent) 804 { 805 static char *subpath = NULL; 806 static int size = ALLOC_SIZE; 807 int res; 808 809 if(subpath == NULL) { 810 subpath = malloc(ALLOC_SIZE); 811 if(subpath == NULL) 812 MEM_ERROR(); 813 } 814 815 for(;;) { 816 if(dir_ent->our_dir->subpath[0] != '\0') 817 res = snprintf(subpath, size, "%s/%s", 818 dir_ent->our_dir->subpath, dir_ent->name); 819 else 820 res = snprintf(subpath, size, "/%s", dir_ent->name); 821 822 if(res < 0) 823 BAD_ERROR("snprintf failed in subpathname\n"); 824 else if(res >= size) { 825 /* 826 * subpath is too small to contain the result, so 827 * increase it and try again 828 */ 829 size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1); 830 subpath = realloc(subpath, size); 831 if(subpath == NULL) 832 MEM_ERROR(); 833 } else 834 break; 835 } 836 837 return subpath; 838 } 839 840 841 inline unsigned int get_inode_no(struct inode_info *inode) 842 { 843 return inode->inode_number; 844 } 845 846 847 inline unsigned int get_parent_no(struct dir_info *dir) 848 { 849 return dir->depth ? get_inode_no(dir->dir_ent->inode) : inode_no; 850 } 851 852 853 int create_inode(squashfs_inode *i_no, struct dir_info *dir_info, 854 struct dir_ent *dir_ent, int type, long long byte_size, 855 long long start_block, unsigned int offset, unsigned int *block_list, 856 struct fragment *fragment, struct directory *dir_in, long long sparse) 857 { 858 struct stat *buf = &dir_ent->inode->buf; 859 union squashfs_inode_header inode_header; 860 struct squashfs_base_inode_header *base = &inode_header.base; 861 void *inode; 862 char *filename = pathname(dir_ent); 863 int nlink = dir_ent->inode->nlink; 864 int xattr = read_xattrs(dir_ent); 865 866 switch(type) { 867 case SQUASHFS_FILE_TYPE: 868 if(dir_ent->inode->nlink > 1 || 869 byte_size >= (1LL << 32) || 870 start_block >= (1LL << 32) || 871 sparse || IS_XATTR(xattr)) 872 type = SQUASHFS_LREG_TYPE; 873 break; 874 case SQUASHFS_DIR_TYPE: 875 if(dir_info->dir_is_ldir || IS_XATTR(xattr)) 876 type = SQUASHFS_LDIR_TYPE; 877 break; 878 case SQUASHFS_SYMLINK_TYPE: 879 if(IS_XATTR(xattr)) 880 type = SQUASHFS_LSYMLINK_TYPE; 881 break; 882 case SQUASHFS_BLKDEV_TYPE: 883 if(IS_XATTR(xattr)) 884 type = SQUASHFS_LBLKDEV_TYPE; 885 break; 886 case SQUASHFS_CHRDEV_TYPE: 887 if(IS_XATTR(xattr)) 888 type = SQUASHFS_LCHRDEV_TYPE; 889 break; 890 case SQUASHFS_FIFO_TYPE: 891 if(IS_XATTR(xattr)) 892 type = SQUASHFS_LFIFO_TYPE; 893 break; 894 case SQUASHFS_SOCKET_TYPE: 895 if(IS_XATTR(xattr)) 896 type = SQUASHFS_LSOCKET_TYPE; 897 break; 898 } 899 900 base->mode = SQUASHFS_MODE(buf->st_mode); 901 base->uid = get_uid((unsigned int) global_uid == -1 ? 902 buf->st_uid : global_uid); 903 base->inode_type = type; 904 base->guid = get_guid((unsigned int) global_gid == -1 ? 905 buf->st_gid : global_gid); 906 base->mtime = buf->st_mtime; 907 base->inode_number = get_inode_no(dir_ent->inode); 908 909 if(type == SQUASHFS_FILE_TYPE) { 910 int i; 911 struct squashfs_reg_inode_header *reg = &inode_header.reg; 912 size_t off = offsetof(struct squashfs_reg_inode_header, block_list); 913 914 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int)); 915 reg->file_size = byte_size; 916 reg->start_block = start_block; 917 reg->fragment = fragment->index; 918 reg->offset = fragment->offset; 919 SQUASHFS_SWAP_REG_INODE_HEADER(reg, inode); 920 SQUASHFS_SWAP_INTS(block_list, inode + off, offset); 921 TRACE("File inode, file_size %lld, start_block 0x%llx, blocks " 922 "%d, fragment %d, offset %d, size %d\n", byte_size, 923 start_block, offset, fragment->index, fragment->offset, 924 fragment->size); 925 for(i = 0; i < offset; i++) 926 TRACE("Block %d, size %d\n", i, block_list[i]); 927 } 928 else if(type == SQUASHFS_LREG_TYPE) { 929 int i; 930 struct squashfs_lreg_inode_header *reg = &inode_header.lreg; 931 size_t off = offsetof(struct squashfs_lreg_inode_header, block_list); 932 933 inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int)); 934 reg->nlink = nlink; 935 reg->file_size = byte_size; 936 reg->start_block = start_block; 937 reg->fragment = fragment->index; 938 reg->offset = fragment->offset; 939 if(sparse && sparse >= byte_size) 940 sparse = byte_size - 1; 941 reg->sparse = sparse; 942 reg->xattr = xattr; 943 SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inode); 944 SQUASHFS_SWAP_INTS(block_list, inode + off, offset); 945 TRACE("Long file inode, file_size %lld, start_block 0x%llx, " 946 "blocks %d, fragment %d, offset %d, size %d, nlink %d" 947 "\n", byte_size, start_block, offset, fragment->index, 948 fragment->offset, fragment->size, nlink); 949 for(i = 0; i < offset; i++) 950 TRACE("Block %d, size %d\n", i, block_list[i]); 951 } 952 else if(type == SQUASHFS_LDIR_TYPE) { 953 int i; 954 unsigned char *p; 955 struct squashfs_ldir_inode_header *dir = &inode_header.ldir; 956 struct cached_dir_index *index = dir_in->index; 957 unsigned int i_count = dir_in->i_count; 958 unsigned int i_size = dir_in->i_size; 959 960 if(byte_size >= 1 << 27) 961 BAD_ERROR("directory greater than 2^27-1 bytes!\n"); 962 963 inode = get_inode(sizeof(*dir) + i_size); 964 dir->inode_type = SQUASHFS_LDIR_TYPE; 965 dir->nlink = dir_ent->dir->directory_count + 2; 966 dir->file_size = byte_size; 967 dir->offset = offset; 968 dir->start_block = start_block; 969 dir->i_count = i_count; 970 dir->parent_inode = get_parent_no(dir_ent->our_dir); 971 dir->xattr = xattr; 972 973 SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode); 974 p = inode + offsetof(struct squashfs_ldir_inode_header, index); 975 for(i = 0; i < i_count; i++) { 976 SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p); 977 p += offsetof(struct squashfs_dir_index, name); 978 memcpy(p, index[i].name, index[i].index.size + 1); 979 p += index[i].index.size + 1; 980 } 981 TRACE("Long directory inode, file_size %lld, start_block " 982 "0x%llx, offset 0x%x, nlink %d\n", byte_size, 983 start_block, offset, dir_ent->dir->directory_count + 2); 984 } 985 else if(type == SQUASHFS_DIR_TYPE) { 986 struct squashfs_dir_inode_header *dir = &inode_header.dir; 987 988 inode = get_inode(sizeof(*dir)); 989 dir->nlink = dir_ent->dir->directory_count + 2; 990 dir->file_size = byte_size; 991 dir->offset = offset; 992 dir->start_block = start_block; 993 dir->parent_inode = get_parent_no(dir_ent->our_dir); 994 SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode); 995 TRACE("Directory inode, file_size %lld, start_block 0x%llx, " 996 "offset 0x%x, nlink %d\n", byte_size, start_block, 997 offset, dir_ent->dir->directory_count + 2); 998 } 999 else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) { 1000 struct squashfs_dev_inode_header *dev = &inode_header.dev; 1001 unsigned int major = major(buf->st_rdev); 1002 unsigned int minor = minor(buf->st_rdev); 1003 1004 if(major > 0xfff) { 1005 ERROR("Major %d out of range in device node %s, " 1006 "truncating to %d\n", major, filename, 1007 major & 0xfff); 1008 major &= 0xfff; 1009 } 1010 if(minor > 0xfffff) { 1011 ERROR("Minor %d out of range in device node %s, " 1012 "truncating to %d\n", minor, filename, 1013 minor & 0xfffff); 1014 minor &= 0xfffff; 1015 } 1016 inode = get_inode(sizeof(*dev)); 1017 dev->nlink = nlink; 1018 dev->rdev = (major << 8) | (minor & 0xff) | 1019 ((minor & ~0xff) << 12); 1020 SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode); 1021 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink); 1022 } 1023 else if(type == SQUASHFS_LCHRDEV_TYPE || type == SQUASHFS_LBLKDEV_TYPE) { 1024 struct squashfs_ldev_inode_header *dev = &inode_header.ldev; 1025 unsigned int major = major(buf->st_rdev); 1026 unsigned int minor = minor(buf->st_rdev); 1027 1028 if(major > 0xfff) { 1029 ERROR("Major %d out of range in device node %s, " 1030 "truncating to %d\n", major, filename, 1031 major & 0xfff); 1032 major &= 0xfff; 1033 } 1034 if(minor > 0xfffff) { 1035 ERROR("Minor %d out of range in device node %s, " 1036 "truncating to %d\n", minor, filename, 1037 minor & 0xfffff); 1038 minor &= 0xfffff; 1039 } 1040 inode = get_inode(sizeof(*dev)); 1041 dev->nlink = nlink; 1042 dev->rdev = (major << 8) | (minor & 0xff) | 1043 ((minor & ~0xff) << 12); 1044 dev->xattr = xattr; 1045 SQUASHFS_SWAP_LDEV_INODE_HEADER(dev, inode); 1046 TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink); 1047 } 1048 else if(type == SQUASHFS_SYMLINK_TYPE) { 1049 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink; 1050 int byte = strlen(dir_ent->inode->symlink); 1051 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink); 1052 1053 inode = get_inode(sizeof(*symlink) + byte); 1054 symlink->nlink = nlink; 1055 symlink->symlink_size = byte; 1056 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode); 1057 strncpy(inode + off, dir_ent->inode->symlink, byte); 1058 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte, 1059 nlink); 1060 } 1061 else if(type == SQUASHFS_LSYMLINK_TYPE) { 1062 struct squashfs_symlink_inode_header *symlink = &inode_header.symlink; 1063 int byte = strlen(dir_ent->inode->symlink); 1064 size_t off = offsetof(struct squashfs_symlink_inode_header, symlink); 1065 1066 inode = get_inode(sizeof(*symlink) + byte + 1067 sizeof(unsigned int)); 1068 symlink->nlink = nlink; 1069 symlink->symlink_size = byte; 1070 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode); 1071 strncpy(inode + off, dir_ent->inode->symlink, byte); 1072 SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1); 1073 TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte, 1074 nlink); 1075 } 1076 else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) { 1077 struct squashfs_ipc_inode_header *ipc = &inode_header.ipc; 1078 1079 inode = get_inode(sizeof(*ipc)); 1080 ipc->nlink = nlink; 1081 SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode); 1082 TRACE("ipc inode, type %s, nlink %d\n", type == 1083 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink); 1084 } 1085 else if(type == SQUASHFS_LFIFO_TYPE || type == SQUASHFS_LSOCKET_TYPE) { 1086 struct squashfs_lipc_inode_header *ipc = &inode_header.lipc; 1087 1088 inode = get_inode(sizeof(*ipc)); 1089 ipc->nlink = nlink; 1090 ipc->xattr = xattr; 1091 SQUASHFS_SWAP_LIPC_INODE_HEADER(ipc, inode); 1092 TRACE("ipc inode, type %s, nlink %d\n", type == 1093 SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink); 1094 } else 1095 BAD_ERROR("Unrecognised inode %d in create_inode\n", type); 1096 1097 *i_no = MKINODE(inode); 1098 inode_count ++; 1099 1100 TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type, 1101 base->uid, base->guid); 1102 1103 return TRUE; 1104 } 1105 1106 1107 void add_dir(squashfs_inode inode, unsigned int inode_number, char *name, 1108 int type, struct directory *dir) 1109 { 1110 unsigned char *buff; 1111 struct squashfs_dir_entry idir; 1112 unsigned int start_block = inode >> 16; 1113 unsigned int offset = inode & 0xffff; 1114 unsigned int size = strlen(name); 1115 size_t name_off = offsetof(struct squashfs_dir_entry, name); 1116 1117 if(size > SQUASHFS_NAME_LEN) { 1118 size = SQUASHFS_NAME_LEN; 1119 ERROR("Filename is greater than %d characters, truncating! ..." 1120 "\n", SQUASHFS_NAME_LEN); 1121 } 1122 1123 if(dir->p + sizeof(struct squashfs_dir_entry) + size + 1124 sizeof(struct squashfs_dir_header) 1125 >= dir->buff + dir->size) { 1126 buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE); 1127 if(buff == NULL) 1128 MEM_ERROR(); 1129 1130 dir->p = (dir->p - dir->buff) + buff; 1131 if(dir->entry_count_p) 1132 dir->entry_count_p = (dir->entry_count_p - dir->buff + 1133 buff); 1134 dir->index_count_p = dir->index_count_p - dir->buff + buff; 1135 dir->buff = buff; 1136 } 1137 1138 if(dir->entry_count == 256 || start_block != dir->start_block || 1139 ((dir->entry_count_p != NULL) && 1140 ((dir->p + sizeof(struct squashfs_dir_entry) + size - 1141 dir->index_count_p) > SQUASHFS_METADATA_SIZE)) || 1142 ((long long) inode_number - dir->inode_number) > 32767 1143 || ((long long) inode_number - dir->inode_number) 1144 < -32768) { 1145 if(dir->entry_count_p) { 1146 struct squashfs_dir_header dir_header; 1147 1148 if((dir->p + sizeof(struct squashfs_dir_entry) + size - 1149 dir->index_count_p) > 1150 SQUASHFS_METADATA_SIZE) { 1151 if(dir->i_count % I_COUNT_SIZE == 0) { 1152 dir->index = realloc(dir->index, 1153 (dir->i_count + I_COUNT_SIZE) * 1154 sizeof(struct cached_dir_index)); 1155 if(dir->index == NULL) 1156 MEM_ERROR(); 1157 } 1158 dir->index[dir->i_count].index.index = 1159 dir->p - dir->buff; 1160 dir->index[dir->i_count].index.size = size - 1; 1161 dir->index[dir->i_count++].name = name; 1162 dir->i_size += sizeof(struct squashfs_dir_index) 1163 + size; 1164 dir->index_count_p = dir->p; 1165 } 1166 1167 dir_header.count = dir->entry_count - 1; 1168 dir_header.start_block = dir->start_block; 1169 dir_header.inode_number = dir->inode_number; 1170 SQUASHFS_SWAP_DIR_HEADER(&dir_header, 1171 dir->entry_count_p); 1172 1173 } 1174 1175 1176 dir->entry_count_p = dir->p; 1177 dir->start_block = start_block; 1178 dir->entry_count = 0; 1179 dir->inode_number = inode_number; 1180 dir->p += sizeof(struct squashfs_dir_header); 1181 } 1182 1183 idir.offset = offset; 1184 idir.type = type; 1185 idir.size = size - 1; 1186 idir.inode_number = ((long long) inode_number - dir->inode_number); 1187 SQUASHFS_SWAP_DIR_ENTRY(&idir, dir->p); 1188 strncpy((char *) dir->p + name_off, name, size); 1189 dir->p += sizeof(struct squashfs_dir_entry) + size; 1190 dir->entry_count ++; 1191 } 1192 1193 1194 void write_dir(squashfs_inode *inode, struct dir_info *dir_info, 1195 struct directory *dir) 1196 { 1197 unsigned int dir_size = dir->p - dir->buff; 1198 int data_space = directory_cache_size - directory_cache_bytes; 1199 unsigned int directory_block, directory_offset, i_count, index; 1200 unsigned short c_byte; 1201 1202 if(data_space < dir_size) { 1203 int realloc_size = directory_cache_size == 0 ? 1204 ((dir_size + SQUASHFS_METADATA_SIZE) & 1205 ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space; 1206 1207 void *dc = realloc(directory_data_cache, 1208 directory_cache_size + realloc_size); 1209 if(dc == NULL) 1210 MEM_ERROR(); 1211 directory_cache_size += realloc_size; 1212 directory_data_cache = dc; 1213 } 1214 1215 if(dir_size) { 1216 struct squashfs_dir_header dir_header; 1217 1218 dir_header.count = dir->entry_count - 1; 1219 dir_header.start_block = dir->start_block; 1220 dir_header.inode_number = dir->inode_number; 1221 SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p); 1222 memcpy(directory_data_cache + directory_cache_bytes, dir->buff, 1223 dir_size); 1224 } 1225 directory_offset = directory_cache_bytes; 1226 directory_block = directory_bytes; 1227 directory_cache_bytes += dir_size; 1228 i_count = 0; 1229 index = SQUASHFS_METADATA_SIZE - directory_offset; 1230 1231 while(1) { 1232 while(i_count < dir->i_count && 1233 dir->index[i_count].index.index < index) 1234 dir->index[i_count++].index.start_block = 1235 directory_bytes; 1236 index += SQUASHFS_METADATA_SIZE; 1237 1238 if(directory_cache_bytes < SQUASHFS_METADATA_SIZE) 1239 break; 1240 1241 if((directory_size - directory_bytes) < 1242 ((SQUASHFS_METADATA_SIZE << 1) + 2)) { 1243 void *dt = realloc(directory_table, 1244 directory_size + (SQUASHFS_METADATA_SIZE << 1) 1245 + 2); 1246 if(dt == NULL) 1247 MEM_ERROR(); 1248 directory_size += SQUASHFS_METADATA_SIZE << 1; 1249 directory_table = dt; 1250 } 1251 1252 c_byte = mangle(directory_table + directory_bytes + 1253 BLOCK_OFFSET, directory_data_cache, 1254 SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, 1255 noI, 0); 1256 TRACE("Directory block @ 0x%x, size %d\n", directory_bytes, 1257 c_byte); 1258 SQUASHFS_SWAP_SHORTS(&c_byte, 1259 directory_table + directory_bytes, 1); 1260 directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + 1261 BLOCK_OFFSET; 1262 total_directory_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET; 1263 memmove(directory_data_cache, directory_data_cache + 1264 SQUASHFS_METADATA_SIZE, directory_cache_bytes - 1265 SQUASHFS_METADATA_SIZE); 1266 directory_cache_bytes -= SQUASHFS_METADATA_SIZE; 1267 } 1268 1269 create_inode(inode, dir_info, dir_info->dir_ent, SQUASHFS_DIR_TYPE, 1270 dir_size + 3, directory_block, directory_offset, NULL, NULL, 1271 dir, 0); 1272 1273 #ifdef SQUASHFS_TRACE 1274 { 1275 unsigned char *dirp; 1276 int count; 1277 1278 TRACE("Directory contents of inode 0x%llx\n", *inode); 1279 dirp = dir->buff; 1280 while(dirp < dir->p) { 1281 char buffer[SQUASHFS_NAME_LEN + 1]; 1282 struct squashfs_dir_entry idir, *idirp; 1283 struct squashfs_dir_header dirh; 1284 SQUASHFS_SWAP_DIR_HEADER((struct squashfs_dir_header *) dirp, 1285 &dirh); 1286 count = dirh.count + 1; 1287 dirp += sizeof(struct squashfs_dir_header); 1288 1289 TRACE("\tStart block 0x%x, count %d\n", 1290 dirh.start_block, count); 1291 1292 while(count--) { 1293 idirp = (struct squashfs_dir_entry *) dirp; 1294 SQUASHFS_SWAP_DIR_ENTRY(idirp, &idir); 1295 strncpy(buffer, idirp->name, idir.size + 1); 1296 buffer[idir.size + 1] = '\0'; 1297 TRACE("\t\tname %s, inode offset 0x%x, type " 1298 "%d\n", buffer, idir.offset, idir.type); 1299 dirp += sizeof(struct squashfs_dir_entry) + idir.size + 1300 1; 1301 } 1302 } 1303 } 1304 #endif 1305 dir_count ++; 1306 } 1307 1308 1309 static struct file_buffer *get_fragment(struct fragment *fragment) 1310 { 1311 struct squashfs_fragment_entry *disk_fragment; 1312 struct file_buffer *buffer, *compressed_buffer; 1313 long long start_block; 1314 int res, size, index = fragment->index; 1315 char locked; 1316 1317 /* 1318 * Lookup fragment block in cache. 1319 * If the fragment block doesn't exist, then get the compressed version 1320 * from the writer cache or off disk, and decompress it. 1321 * 1322 * This routine has two things which complicate the code: 1323 * 1324 * 1. Multiple threads can simultaneously lookup/create the 1325 * same buffer. This means a buffer needs to be "locked" 1326 * when it is being filled in, to prevent other threads from 1327 * using it when it is not ready. This is because we now do 1328 * fragment duplicate checking in parallel. 1329 * 2. We have two caches which need to be checked for the 1330 * presence of fragment blocks: the normal fragment cache 1331 * and a "reserve" cache. The reserve cache is used to 1332 * prevent an unnecessary pipeline stall when the fragment cache 1333 * is full of fragments waiting to be compressed. 1334 */ 1335 1336 if(fragment->index == SQUASHFS_INVALID_FRAG) 1337 return NULL; 1338 1339 pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex); 1340 pthread_mutex_lock(&dup_mutex); 1341 1342 again: 1343 buffer = cache_lookup_nowait(fragment_buffer, index, &locked); 1344 if(buffer) { 1345 pthread_mutex_unlock(&dup_mutex); 1346 if(locked) 1347 /* got a buffer being filled in. Wait for it */ 1348 cache_wait_unlock(buffer); 1349 goto finished; 1350 } 1351 1352 /* not in fragment cache, is it in the reserve cache? */ 1353 buffer = cache_lookup_nowait(reserve_cache, index, &locked); 1354 if(buffer) { 1355 pthread_mutex_unlock(&dup_mutex); 1356 if(locked) 1357 /* got a buffer being filled in. Wait for it */ 1358 cache_wait_unlock(buffer); 1359 goto finished; 1360 } 1361 1362 /* in neither cache, try to get it from the fragment cache */ 1363 buffer = cache_get_nowait(fragment_buffer, index); 1364 if(!buffer) { 1365 /* 1366 * no room, get it from the reserve cache, this is 1367 * dimensioned so it will always have space (no more than 1368 * processors + 1 can have an outstanding reserve buffer) 1369 */ 1370 buffer = cache_get_nowait(reserve_cache, index); 1371 if(!buffer) { 1372 /* failsafe */ 1373 ERROR("no space in reserve cache\n"); 1374 goto again; 1375 } 1376 } 1377 1378 pthread_mutex_unlock(&dup_mutex); 1379 1380 compressed_buffer = cache_lookup(fwriter_buffer, index); 1381 1382 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex); 1383 pthread_mutex_lock(&fragment_mutex); 1384 disk_fragment = &fragment_table[index]; 1385 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size); 1386 start_block = disk_fragment->start_block; 1387 pthread_cleanup_pop(1); 1388 1389 if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) { 1390 int error; 1391 char *data; 1392 1393 if(compressed_buffer) 1394 data = compressed_buffer->data; 1395 else { 1396 data = read_from_disk(start_block, size); 1397 if(data == NULL) { 1398 ERROR("Failed to read fragment from output" 1399 " filesystem\n"); 1400 BAD_ERROR("Output filesystem corrupted?\n"); 1401 } 1402 } 1403 1404 res = compressor_uncompress(comp, buffer->data, data, size, 1405 block_size, &error); 1406 if(res == -1) 1407 BAD_ERROR("%s uncompress failed with error code %d\n", 1408 comp->name, error); 1409 } else if(compressed_buffer) 1410 memcpy(buffer->data, compressed_buffer->data, size); 1411 else { 1412 res = read_fs_bytes(fd, start_block, size, buffer->data); 1413 if(res == 0) { 1414 ERROR("Failed to read fragment from output " 1415 "filesystem\n"); 1416 BAD_ERROR("Output filesystem corrupted?\n"); 1417 } 1418 } 1419 1420 cache_unlock(buffer); 1421 cache_block_put(compressed_buffer); 1422 1423 finished: 1424 pthread_cleanup_pop(0); 1425 1426 return buffer; 1427 } 1428 1429 1430 unsigned short get_fragment_checksum(struct file_info *file) 1431 { 1432 struct file_buffer *frag_buffer; 1433 struct append_file *append; 1434 int res, index = file->fragment->index; 1435 unsigned short checksum; 1436 1437 if(index == SQUASHFS_INVALID_FRAG) 1438 return 0; 1439 1440 pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex); 1441 pthread_mutex_lock(&dup_mutex); 1442 res = file->have_frag_checksum; 1443 checksum = file->fragment_checksum; 1444 pthread_cleanup_pop(1); 1445 1446 if(res) 1447 return checksum; 1448 1449 frag_buffer = get_fragment(file->fragment); 1450 1451 pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex); 1452 1453 for(append = file_mapping[index]; append; append = append->next) { 1454 int offset = append->file->fragment->offset; 1455 int size = append->file->fragment->size; 1456 unsigned short cksum = 1457 get_checksum_mem(frag_buffer->data + offset, size); 1458 1459 if(file == append->file) 1460 checksum = cksum; 1461 1462 pthread_mutex_lock(&dup_mutex); 1463 append->file->fragment_checksum = cksum; 1464 append->file->have_frag_checksum = TRUE; 1465 pthread_mutex_unlock(&dup_mutex); 1466 } 1467 1468 cache_block_put(frag_buffer); 1469 pthread_cleanup_pop(0); 1470 1471 return checksum; 1472 } 1473 1474 1475 void lock_fragments() 1476 { 1477 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex); 1478 pthread_mutex_lock(&fragment_mutex); 1479 fragments_locked = TRUE; 1480 pthread_cleanup_pop(1); 1481 } 1482 1483 1484 void unlock_fragments() 1485 { 1486 int frg, size; 1487 struct file_buffer *write_buffer; 1488 1489 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex); 1490 pthread_mutex_lock(&fragment_mutex); 1491 1492 /* 1493 * Note queue_empty() is inherently racy with respect to concurrent 1494 * queue get and pushes. We avoid this because we're holding the 1495 * fragment_mutex which ensures no other threads can be using the 1496 * queue at this time. 1497 */ 1498 while(!queue_empty(locked_fragment)) { 1499 write_buffer = queue_get(locked_fragment); 1500 frg = write_buffer->block; 1501 size = SQUASHFS_COMPRESSED_SIZE_BLOCK(fragment_table[frg].size); 1502 fragment_table[frg].start_block = bytes; 1503 write_buffer->block = bytes; 1504 bytes += size; 1505 fragments_outstanding --; 1506 queue_put(to_writer, write_buffer); 1507 TRACE("fragment_locked writing fragment %d, compressed size %d" 1508 "\n", frg, size); 1509 } 1510 fragments_locked = FALSE; 1511 pthread_cleanup_pop(1); 1512 } 1513 1514 /* Called with the fragment_mutex locked */ 1515 void add_pending_fragment(struct file_buffer *write_buffer, int c_byte, 1516 int fragment) 1517 { 1518 fragment_table[fragment].size = c_byte; 1519 write_buffer->block = fragment; 1520 1521 queue_put(locked_fragment, write_buffer); 1522 } 1523 1524 1525 void write_fragment(struct file_buffer *fragment) 1526 { 1527 if(fragment == NULL) 1528 return; 1529 1530 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex); 1531 pthread_mutex_lock(&fragment_mutex); 1532 fragment_table[fragment->block].unused = 0; 1533 fragments_outstanding ++; 1534 queue_put(to_frag, fragment); 1535 pthread_cleanup_pop(1); 1536 } 1537 1538 1539 struct file_buffer *allocate_fragment() 1540 { 1541 struct file_buffer *fragment = cache_get(fragment_buffer, fragments); 1542 1543 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex); 1544 pthread_mutex_lock(&fragment_mutex); 1545 1546 if(fragments % FRAG_SIZE == 0) { 1547 void *ft = realloc(fragment_table, (fragments + 1548 FRAG_SIZE) * sizeof(struct squashfs_fragment_entry)); 1549 if(ft == NULL) 1550 MEM_ERROR(); 1551 fragment_table = ft; 1552 } 1553 1554 fragment->size = 0; 1555 fragment->block = fragments ++; 1556 1557 pthread_cleanup_pop(1); 1558 1559 return fragment; 1560 } 1561 1562 1563 static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0}; 1564 1565 1566 void free_fragment(struct fragment *fragment) 1567 { 1568 if(fragment != &empty_fragment) 1569 free(fragment); 1570 } 1571 1572 1573 struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer, 1574 struct dir_ent *dir_ent) 1575 { 1576 struct fragment *ffrg; 1577 struct file_buffer **fragment; 1578 1579 if(file_buffer == NULL || file_buffer->size == 0) 1580 return &empty_fragment; 1581 1582 fragment = eval_frag_actions(root_dir, dir_ent); 1583 1584 if((*fragment) && (*fragment)->size + file_buffer->size > block_size) { 1585 write_fragment(*fragment); 1586 *fragment = NULL; 1587 } 1588 1589 ffrg = malloc(sizeof(struct fragment)); 1590 if(ffrg == NULL) 1591 MEM_ERROR(); 1592 1593 if(*fragment == NULL) 1594 *fragment = allocate_fragment(); 1595 1596 ffrg->index = (*fragment)->block; 1597 ffrg->offset = (*fragment)->size; 1598 ffrg->size = file_buffer->size; 1599 memcpy((*fragment)->data + (*fragment)->size, file_buffer->data, 1600 file_buffer->size); 1601 (*fragment)->size += file_buffer->size; 1602 1603 return ffrg; 1604 } 1605 1606 1607 long long generic_write_table(int length, void *buffer, int length2, 1608 void *buffer2, int uncompressed) 1609 { 1610 int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) / 1611 SQUASHFS_METADATA_SIZE; 1612 long long *list, start_bytes; 1613 int compressed_size, i, list_size = meta_blocks * sizeof(long long); 1614 unsigned short c_byte; 1615 char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2]; 1616 1617 #ifdef SQUASHFS_TRACE 1618 long long obytes = bytes; 1619 int olength = length; 1620 #endif 1621 1622 list = malloc(list_size); 1623 if(list == NULL) 1624 MEM_ERROR(); 1625 1626 for(i = 0; i < meta_blocks; i++) { 1627 int avail_bytes = length > SQUASHFS_METADATA_SIZE ? 1628 SQUASHFS_METADATA_SIZE : length; 1629 c_byte = mangle(cbuffer + BLOCK_OFFSET, buffer + i * 1630 SQUASHFS_METADATA_SIZE , avail_bytes, 1631 SQUASHFS_METADATA_SIZE, uncompressed, 0); 1632 SQUASHFS_SWAP_SHORTS(&c_byte, cbuffer, 1); 1633 list[i] = bytes; 1634 compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) + 1635 BLOCK_OFFSET; 1636 TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes, 1637 compressed_size); 1638 write_destination(fd, bytes, compressed_size, cbuffer); 1639 bytes += compressed_size; 1640 total_bytes += avail_bytes; 1641 length -= avail_bytes; 1642 } 1643 1644 start_bytes = bytes; 1645 if(length2) { 1646 write_destination(fd, bytes, length2, buffer2); 1647 bytes += length2; 1648 total_bytes += length2; 1649 } 1650 1651 SQUASHFS_INSWAP_LONG_LONGS(list, meta_blocks); 1652 write_destination(fd, bytes, list_size, list); 1653 bytes += list_size; 1654 total_bytes += list_size; 1655 1656 TRACE("generic_write_table: total uncompressed %d compressed %lld\n", 1657 olength, bytes - obytes); 1658 1659 free(list); 1660 1661 return start_bytes; 1662 } 1663 1664 1665 long long write_fragment_table() 1666 { 1667 unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments); 1668 int i; 1669 1670 TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments, 1671 frag_bytes); 1672 for(i = 0; i < fragments; i++) { 1673 TRACE("write_fragment_table: fragment %d, start_block 0x%llx, " 1674 "size %d\n", i, fragment_table[i].start_block, 1675 fragment_table[i].size); 1676 SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]); 1677 } 1678 1679 return generic_write_table(frag_bytes, fragment_table, 0, NULL, noF); 1680 } 1681 1682 1683 char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE]; 1684 static char *read_from_disk(long long start, unsigned int avail_bytes) 1685 { 1686 int res; 1687 1688 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer); 1689 if(res == 0) 1690 return NULL; 1691 1692 return read_from_file_buffer; 1693 } 1694 1695 1696 char read_from_file_buffer2[SQUASHFS_FILE_MAX_SIZE]; 1697 char *read_from_disk2(long long start, unsigned int avail_bytes) 1698 { 1699 int res; 1700 1701 res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2); 1702 if(res == 0) 1703 return NULL; 1704 1705 return read_from_file_buffer2; 1706 } 1707 1708 1709 /* 1710 * Compute 16 bit BSD checksum over the data 1711 */ 1712 unsigned short get_checksum(char *buff, int bytes, unsigned short chksum) 1713 { 1714 unsigned char *b = (unsigned char *) buff; 1715 1716 while(bytes --) { 1717 chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1; 1718 chksum += *b++; 1719 } 1720 1721 return chksum; 1722 } 1723 1724 1725 unsigned short get_checksum_disk(long long start, long long l, 1726 unsigned int *blocks) 1727 { 1728 unsigned short chksum = 0; 1729 unsigned int bytes; 1730 struct file_buffer *write_buffer; 1731 int i; 1732 1733 for(i = 0; l; i++) { 1734 bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]); 1735 if(bytes == 0) /* sparse block */ 1736 continue; 1737 write_buffer = cache_lookup(bwriter_buffer, start); 1738 if(write_buffer) { 1739 chksum = get_checksum(write_buffer->data, bytes, 1740 chksum); 1741 cache_block_put(write_buffer); 1742 } else { 1743 void *data = read_from_disk(start, bytes); 1744 if(data == NULL) { 1745 ERROR("Failed to checksum data from output" 1746 " filesystem\n"); 1747 BAD_ERROR("Output filesystem corrupted?\n"); 1748 } 1749 1750 chksum = get_checksum(data, bytes, chksum); 1751 } 1752 1753 l -= bytes; 1754 start += bytes; 1755 } 1756 1757 return chksum; 1758 } 1759 1760 1761 unsigned short get_checksum_mem(char *buff, int bytes) 1762 { 1763 return get_checksum(buff, bytes, 0); 1764 } 1765 1766 1767 unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer) 1768 { 1769 if(file_buffer == NULL) 1770 return 0; 1771 else 1772 return get_checksum(file_buffer->data, file_buffer->size, 0); 1773 } 1774 1775 1776 #define DUP_HASH(a) (a & 0xffff) 1777 void add_file(long long start, long long file_size, long long file_bytes, 1778 unsigned int *block_listp, int blocks, unsigned int fragment, 1779 int offset, int bytes) 1780 { 1781 struct fragment *frg; 1782 unsigned int *block_list = block_listp; 1783 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)]; 1784 struct append_file *append_file; 1785 struct file_info *file; 1786 1787 if(!duplicate_checking || file_size == 0) 1788 return; 1789 1790 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) { 1791 if(file_size != dupl_ptr->file_size) 1792 continue; 1793 if(blocks != 0 && start != dupl_ptr->start) 1794 continue; 1795 if(fragment != dupl_ptr->fragment->index) 1796 continue; 1797 if(fragment != SQUASHFS_INVALID_FRAG && (offset != 1798 dupl_ptr->fragment->offset || bytes != 1799 dupl_ptr->fragment->size)) 1800 continue; 1801 return; 1802 } 1803 1804 frg = malloc(sizeof(struct fragment)); 1805 if(frg == NULL) 1806 MEM_ERROR(); 1807 1808 frg->index = fragment; 1809 frg->offset = offset; 1810 frg->size = bytes; 1811 1812 file = add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, 1813 FALSE, FALSE); 1814 1815 if(fragment == SQUASHFS_INVALID_FRAG) 1816 return; 1817 1818 append_file = malloc(sizeof(struct append_file)); 1819 if(append_file == NULL) 1820 MEM_ERROR(); 1821 1822 append_file->file = file; 1823 append_file->next = file_mapping[fragment]; 1824 file_mapping[fragment] = append_file; 1825 } 1826 1827 1828 int pre_duplicate(long long file_size) 1829 { 1830 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)]; 1831 1832 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) 1833 if(dupl_ptr->file_size == file_size) 1834 return TRUE; 1835 1836 return FALSE; 1837 } 1838 1839 1840 struct file_info *add_non_dup(long long file_size, long long bytes, 1841 unsigned int *block_list, long long start, struct fragment *fragment, 1842 unsigned short checksum, unsigned short fragment_checksum, 1843 int checksum_flag, int checksum_frag_flag) 1844 { 1845 struct file_info *dupl_ptr = malloc(sizeof(struct file_info)); 1846 1847 if(dupl_ptr == NULL) 1848 MEM_ERROR(); 1849 1850 dupl_ptr->file_size = file_size; 1851 dupl_ptr->bytes = bytes; 1852 dupl_ptr->block_list = block_list; 1853 dupl_ptr->start = start; 1854 dupl_ptr->fragment = fragment; 1855 dupl_ptr->checksum = checksum; 1856 dupl_ptr->fragment_checksum = fragment_checksum; 1857 dupl_ptr->have_frag_checksum = checksum_frag_flag; 1858 dupl_ptr->have_checksum = checksum_flag; 1859 1860 pthread_cleanup_push((void *) pthread_mutex_unlock, &dup_mutex); 1861 pthread_mutex_lock(&dup_mutex); 1862 dupl_ptr->next = dupl[DUP_HASH(file_size)]; 1863 dupl[DUP_HASH(file_size)] = dupl_ptr; 1864 dup_files ++; 1865 pthread_cleanup_pop(1); 1866 1867 return dupl_ptr; 1868 } 1869 1870 1871 struct fragment *frag_duplicate(struct file_buffer *file_buffer, char *dont_put) 1872 { 1873 struct file_info *dupl_ptr; 1874 struct file_buffer *buffer; 1875 struct file_info *dupl_start = file_buffer->dupl_start; 1876 long long file_size = file_buffer->file_size; 1877 unsigned short checksum = file_buffer->checksum; 1878 int res; 1879 1880 if(file_buffer->duplicate) { 1881 TRACE("Found duplicate file, fragment %d, size %d, offset %d, " 1882 "checksum 0x%x\n", dupl_start->fragment->index, 1883 file_size, dupl_start->fragment->offset, checksum); 1884 *dont_put = TRUE; 1885 return dupl_start->fragment; 1886 } else { 1887 *dont_put = FALSE; 1888 dupl_ptr = dupl[DUP_HASH(file_size)]; 1889 } 1890 1891 for(; dupl_ptr && dupl_ptr != dupl_start; dupl_ptr = dupl_ptr->next) { 1892 if(file_size == dupl_ptr->file_size && file_size == 1893 dupl_ptr->fragment->size) { 1894 if(get_fragment_checksum(dupl_ptr) == checksum) { 1895 buffer = get_fragment(dupl_ptr->fragment); 1896 res = memcmp(file_buffer->data, buffer->data + 1897 dupl_ptr->fragment->offset, file_size); 1898 cache_block_put(buffer); 1899 if(res == 0) 1900 break; 1901 } 1902 } 1903 } 1904 1905 if(!dupl_ptr || dupl_ptr == dupl_start) 1906 return NULL; 1907 1908 TRACE("Found duplicate file, fragment %d, size %d, offset %d, " 1909 "checksum 0x%x\n", dupl_ptr->fragment->index, file_size, 1910 dupl_ptr->fragment->offset, checksum); 1911 1912 return dupl_ptr->fragment; 1913 } 1914 1915 1916 struct file_info *duplicate(long long file_size, long long bytes, 1917 unsigned int **block_list, long long *start, struct fragment **fragment, 1918 struct file_buffer *file_buffer, int blocks, unsigned short checksum, 1919 int checksum_flag) 1920 { 1921 struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)]; 1922 int frag_bytes = file_buffer ? file_buffer->size : 0; 1923 unsigned short fragment_checksum = file_buffer ? 1924 file_buffer->checksum : 0; 1925 1926 for(; dupl_ptr; dupl_ptr = dupl_ptr->next) 1927 if(file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes 1928 && frag_bytes == dupl_ptr->fragment->size) { 1929 long long target_start, dup_start = dupl_ptr->start; 1930 int block; 1931 1932 if(memcmp(*block_list, dupl_ptr->block_list, blocks * 1933 sizeof(unsigned int)) != 0) 1934 continue; 1935 1936 if(checksum_flag == FALSE) { 1937 checksum = get_checksum_disk(*start, bytes, 1938 *block_list); 1939 checksum_flag = TRUE; 1940 } 1941 1942 if(!dupl_ptr->have_checksum) { 1943 dupl_ptr->checksum = 1944 get_checksum_disk(dupl_ptr->start, 1945 dupl_ptr->bytes, dupl_ptr->block_list); 1946 dupl_ptr->have_checksum = TRUE; 1947 } 1948 1949 if(checksum != dupl_ptr->checksum || 1950 fragment_checksum != 1951 get_fragment_checksum(dupl_ptr)) 1952 continue; 1953 1954 target_start = *start; 1955 for(block = 0; block < blocks; block ++) { 1956 int size = SQUASHFS_COMPRESSED_SIZE_BLOCK 1957 ((*block_list)[block]); 1958 struct file_buffer *target_buffer = NULL; 1959 struct file_buffer *dup_buffer = NULL; 1960 char *target_data, *dup_data; 1961 int res; 1962 1963 if(size == 0) 1964 continue; 1965 target_buffer = cache_lookup(bwriter_buffer, 1966 target_start); 1967 if(target_buffer) 1968 target_data = target_buffer->data; 1969 else { 1970 target_data = 1971 read_from_disk(target_start, 1972 size); 1973 if(target_data == NULL) { 1974 ERROR("Failed to read data from" 1975 " output filesystem\n"); 1976 BAD_ERROR("Output filesystem" 1977 " corrupted?\n"); 1978 } 1979 } 1980 1981 dup_buffer = cache_lookup(bwriter_buffer, 1982 dup_start); 1983 if(dup_buffer) 1984 dup_data = dup_buffer->data; 1985 else { 1986 dup_data = read_from_disk2(dup_start, 1987 size); 1988 if(dup_data == NULL) { 1989 ERROR("Failed to read data from" 1990 " output filesystem\n"); 1991 BAD_ERROR("Output filesystem" 1992 " corrupted?\n"); 1993 } 1994 } 1995 1996 res = memcmp(target_data, dup_data, size); 1997 cache_block_put(target_buffer); 1998 cache_block_put(dup_buffer); 1999 if(res != 0) 2000 break; 2001 target_start += size; 2002 dup_start += size; 2003 } 2004 if(block == blocks) { 2005 struct file_buffer *frag_buffer = 2006 get_fragment(dupl_ptr->fragment); 2007 2008 if(frag_bytes == 0 || 2009 memcmp(file_buffer->data, 2010 frag_buffer->data + 2011 dupl_ptr->fragment->offset, 2012 frag_bytes) == 0) { 2013 TRACE("Found duplicate file, start " 2014 "0x%llx, size %lld, checksum " 2015 "0x%x, fragment %d, size %d, " 2016 "offset %d, checksum 0x%x\n", 2017 dupl_ptr->start, 2018 dupl_ptr->bytes, 2019 dupl_ptr->checksum, 2020 dupl_ptr->fragment->index, 2021 frag_bytes, 2022 dupl_ptr->fragment->offset, 2023 fragment_checksum); 2024 *block_list = dupl_ptr->block_list; 2025 *start = dupl_ptr->start; 2026 *fragment = dupl_ptr->fragment; 2027 cache_block_put(frag_buffer); 2028 return 0; 2029 } 2030 cache_block_put(frag_buffer); 2031 } 2032 } 2033 2034 2035 return add_non_dup(file_size, bytes, *block_list, *start, *fragment, 2036 checksum, fragment_checksum, checksum_flag, TRUE); 2037 } 2038 2039 2040 inline int is_fragment(struct inode_info *inode) 2041 { 2042 off_t file_size = inode->buf.st_size; 2043 2044 /* 2045 * If this block is to be compressed differently to the 2046 * fragment compression then it cannot be a fragment 2047 */ 2048 if(inode->noF != noF) 2049 return FALSE; 2050 2051 return !inode->no_fragments && file_size && (file_size < block_size || 2052 (inode->always_use_fragments && file_size & (block_size - 1))); 2053 } 2054 2055 2056 void put_file_buffer(struct file_buffer *file_buffer) 2057 { 2058 /* 2059 * Decide where to send the file buffer: 2060 * - compressible non-fragment blocks go to the deflate threads, 2061 * - fragments go to the process fragment threads, 2062 * - all others go directly to the main thread 2063 */ 2064 if(file_buffer->error) { 2065 file_buffer->fragment = 0; 2066 seq_queue_put(to_main, file_buffer); 2067 } else if (file_buffer->file_size == 0) 2068 seq_queue_put(to_main, file_buffer); 2069 else if(file_buffer->fragment) 2070 queue_put(to_process_frag, file_buffer); 2071 else 2072 queue_put(to_deflate, file_buffer); 2073 } 2074 2075 2076 static int seq = 0; 2077 void reader_read_process(struct dir_ent *dir_ent) 2078 { 2079 long long bytes = 0; 2080 struct inode_info *inode = dir_ent->inode; 2081 struct file_buffer *prev_buffer = NULL, *file_buffer; 2082 int status, byte, res, child; 2083 int file = pseudo_exec_file(get_pseudo_file(inode->pseudo_id), &child); 2084 2085 if(!file) { 2086 file_buffer = cache_get_nohash(reader_buffer); 2087 file_buffer->sequence = seq ++; 2088 goto read_err; 2089 } 2090 2091 while(1) { 2092 file_buffer = cache_get_nohash(reader_buffer); 2093 file_buffer->sequence = seq ++; 2094 file_buffer->noD = inode->noD; 2095 2096 byte = read_bytes(file, file_buffer->data, block_size); 2097 if(byte == -1) 2098 goto read_err2; 2099 2100 file_buffer->size = byte; 2101 file_buffer->file_size = -1; 2102 file_buffer->error = FALSE; 2103 file_buffer->fragment = FALSE; 2104 bytes += byte; 2105 2106 if(byte == 0) 2107 break; 2108 2109 /* 2110 * Update progress bar size. This is done 2111 * on every block rather than waiting for all blocks to be 2112 * read incase write_file_process() is running in parallel 2113 * with this. Otherwise the current progress bar position 2114 * may get ahead of the progress bar size. 2115 */ 2116 progress_bar_size(1); 2117 2118 if(prev_buffer) 2119 put_file_buffer(prev_buffer); 2120 prev_buffer = file_buffer; 2121 } 2122 2123 /* 2124 * Update inode file size now that the size of the dynamic pseudo file 2125 * is known. This is needed for the -info option. 2126 */ 2127 inode->buf.st_size = bytes; 2128 2129 res = waitpid(child, &status, 0); 2130 close(file); 2131 2132 if(res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) 2133 goto read_err; 2134 2135 if(prev_buffer == NULL) 2136 prev_buffer = file_buffer; 2137 else { 2138 cache_block_put(file_buffer); 2139 seq --; 2140 } 2141 prev_buffer->file_size = bytes; 2142 prev_buffer->fragment = is_fragment(inode); 2143 put_file_buffer(prev_buffer); 2144 2145 return; 2146 2147 read_err2: 2148 close(file); 2149 read_err: 2150 if(prev_buffer) { 2151 cache_block_put(file_buffer); 2152 seq --; 2153 file_buffer = prev_buffer; 2154 } 2155 file_buffer->error = TRUE; 2156 put_file_buffer(file_buffer); 2157 } 2158 2159 2160 void reader_read_file(struct dir_ent *dir_ent) 2161 { 2162 struct stat *buf = &dir_ent->inode->buf, buf2; 2163 struct file_buffer *file_buffer; 2164 int blocks, file, res; 2165 long long bytes, read_size; 2166 struct inode_info *inode = dir_ent->inode; 2167 2168 if(inode->read) 2169 return; 2170 2171 inode->read = TRUE; 2172 again: 2173 bytes = 0; 2174 read_size = buf->st_size; 2175 blocks = (read_size + block_size - 1) >> block_log; 2176 2177 file = open(pathname_reader(dir_ent), O_RDONLY); 2178 if(file == -1) { 2179 file_buffer = cache_get_nohash(reader_buffer); 2180 file_buffer->sequence = seq ++; 2181 goto read_err2; 2182 } 2183 2184 do { 2185 file_buffer = cache_get_nohash(reader_buffer); 2186 file_buffer->file_size = read_size; 2187 file_buffer->sequence = seq ++; 2188 file_buffer->noD = inode->noD; 2189 file_buffer->error = FALSE; 2190 2191 /* 2192 * Always try to read block_size bytes from the file rather 2193 * than expected bytes (which will be less than the block_size 2194 * at the file tail) to check that the file hasn't grown 2195 * since being stated. If it is longer (or shorter) than 2196 * expected, then restat, and try again. Note the special 2197 * case where the file is an exact multiple of the block_size 2198 * is dealt with later. 2199 */ 2200 file_buffer->size = read_bytes(file, file_buffer->data, 2201 block_size); 2202 if(file_buffer->size == -1) 2203 goto read_err; 2204 2205 bytes += file_buffer->size; 2206 2207 if(blocks > 1) { 2208 /* non-tail block should be exactly block_size */ 2209 if(file_buffer->size < block_size) 2210 goto restat; 2211 2212 file_buffer->fragment = FALSE; 2213 put_file_buffer(file_buffer); 2214 } 2215 } while(-- blocks > 0); 2216 2217 /* Overall size including tail should match */ 2218 if(read_size != bytes) 2219 goto restat; 2220 2221 if(read_size && read_size % block_size == 0) { 2222 /* 2223 * Special case where we've not tried to read past the end of 2224 * the file. We expect to get EOF, i.e. the file isn't larger 2225 * than we expect. 2226 */ 2227 char buffer; 2228 int res; 2229 2230 res = read_bytes(file, &buffer, 1); 2231 if(res == -1) 2232 goto read_err; 2233 2234 if(res != 0) 2235 goto restat; 2236 } 2237 2238 file_buffer->fragment = is_fragment(inode); 2239 put_file_buffer(file_buffer); 2240 2241 close(file); 2242 2243 return; 2244 2245 restat: 2246 res = fstat(file, &buf2); 2247 if(res == -1) { 2248 ERROR("Cannot stat dir/file %s because %s\n", 2249 pathname_reader(dir_ent), strerror(errno)); 2250 goto read_err; 2251 } 2252 2253 if(read_size != buf2.st_size) { 2254 close(file); 2255 memcpy(buf, &buf2, sizeof(struct stat)); 2256 file_buffer->error = 2; 2257 put_file_buffer(file_buffer); 2258 goto again; 2259 } 2260 read_err: 2261 close(file); 2262 read_err2: 2263 file_buffer->error = TRUE; 2264 put_file_buffer(file_buffer); 2265 } 2266 2267 2268 void reader_scan(struct dir_info *dir) { 2269 struct dir_ent *dir_ent = dir->list; 2270 2271 for(; dir_ent; dir_ent = dir_ent->next) { 2272 struct stat *buf = &dir_ent->inode->buf; 2273 if(dir_ent->inode->root_entry) 2274 continue; 2275 2276 if(IS_PSEUDO_PROCESS(dir_ent->inode)) { 2277 reader_read_process(dir_ent); 2278 continue; 2279 } 2280 2281 switch(buf->st_mode & S_IFMT) { 2282 case S_IFREG: 2283 reader_read_file(dir_ent); 2284 break; 2285 case S_IFDIR: 2286 reader_scan(dir_ent->dir); 2287 break; 2288 } 2289 } 2290 } 2291 2292 2293 void *reader(void *arg) 2294 { 2295 if(!sorted) 2296 reader_scan(queue_get(to_reader)); 2297 else { 2298 int i; 2299 struct priority_entry *entry; 2300 2301 queue_get(to_reader); 2302 for(i = 65535; i >= 0; i--) 2303 for(entry = priority_list[i]; entry; 2304 entry = entry->next) 2305 reader_read_file(entry->dir); 2306 } 2307 2308 pthread_exit(NULL); 2309 } 2310 2311 2312 void *writer(void *arg) 2313 { 2314 while(1) { 2315 struct file_buffer *file_buffer = queue_get(to_writer); 2316 off_t off; 2317 2318 if(file_buffer == NULL) { 2319 queue_put(from_writer, NULL); 2320 continue; 2321 } 2322 2323 off = file_buffer->block; 2324 2325 pthread_cleanup_push((void *) pthread_mutex_unlock, &pos_mutex); 2326 pthread_mutex_lock(&pos_mutex); 2327 2328 if(lseek(fd, off, SEEK_SET) == -1) { 2329 ERROR("writer: Lseek on destination failed because " 2330 "%s, offset=0x%llx\n", strerror(errno), off); 2331 BAD_ERROR("Probably out of space on output " 2332 "%s\n", block_device ? "block device" : 2333 "filesystem"); 2334 } 2335 2336 if(write_bytes(fd, file_buffer->data, 2337 file_buffer->size) == -1) 2338 BAD_ERROR("Failed to write to output %s\n", 2339 block_device ? "block device" : "filesystem"); 2340 2341 pthread_cleanup_pop(1); 2342 2343 cache_block_put(file_buffer); 2344 } 2345 } 2346 2347 2348 int all_zero(struct file_buffer *file_buffer) 2349 { 2350 int i; 2351 long entries = file_buffer->size / sizeof(long); 2352 long *p = (long *) file_buffer->data; 2353 2354 for(i = 0; i < entries && p[i] == 0; i++); 2355 2356 if(i == entries) { 2357 for(i = file_buffer->size & ~(sizeof(long) - 1); 2358 i < file_buffer->size && file_buffer->data[i] == 0; 2359 i++); 2360 2361 return i == file_buffer->size; 2362 } 2363 2364 return 0; 2365 } 2366 2367 2368 void *deflator(void *arg) 2369 { 2370 struct file_buffer *write_buffer = cache_get_nohash(bwriter_buffer); 2371 void *stream = NULL; 2372 int res; 2373 2374 res = compressor_init(comp, &stream, block_size, 1); 2375 if(res) 2376 BAD_ERROR("deflator:: compressor_init failed\n"); 2377 2378 while(1) { 2379 struct file_buffer *file_buffer = queue_get(to_deflate); 2380 2381 if(sparse_files && all_zero(file_buffer)) { 2382 file_buffer->c_byte = 0; 2383 seq_queue_put(to_main, file_buffer); 2384 } else { 2385 write_buffer->c_byte = mangle2(stream, 2386 write_buffer->data, file_buffer->data, 2387 file_buffer->size, block_size, 2388 file_buffer->noD, 1); 2389 write_buffer->sequence = file_buffer->sequence; 2390 write_buffer->file_size = file_buffer->file_size; 2391 write_buffer->block = file_buffer->block; 2392 write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK 2393 (write_buffer->c_byte); 2394 write_buffer->fragment = FALSE; 2395 write_buffer->error = FALSE; 2396 cache_block_put(file_buffer); 2397 seq_queue_put(to_main, write_buffer); 2398 write_buffer = cache_get_nohash(bwriter_buffer); 2399 } 2400 } 2401 } 2402 2403 2404 void *frag_deflator(void *arg) 2405 { 2406 void *stream = NULL; 2407 int res; 2408 2409 res = compressor_init(comp, &stream, block_size, 1); 2410 if(res) 2411 BAD_ERROR("frag_deflator:: compressor_init failed\n"); 2412 2413 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex); 2414 2415 while(1) { 2416 int c_byte, compressed_size; 2417 struct file_buffer *file_buffer = queue_get(to_frag); 2418 struct file_buffer *write_buffer = 2419 cache_get(fwriter_buffer, file_buffer->block); 2420 2421 c_byte = mangle2(stream, write_buffer->data, file_buffer->data, 2422 file_buffer->size, block_size, noF, 1); 2423 compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); 2424 write_buffer->size = compressed_size; 2425 pthread_mutex_lock(&fragment_mutex); 2426 if(fragments_locked == FALSE) { 2427 fragment_table[file_buffer->block].size = c_byte; 2428 fragment_table[file_buffer->block].start_block = bytes; 2429 write_buffer->block = bytes; 2430 bytes += compressed_size; 2431 fragments_outstanding --; 2432 queue_put(to_writer, write_buffer); 2433 pthread_mutex_unlock(&fragment_mutex); 2434 TRACE("Writing fragment %lld, uncompressed size %d, " 2435 "compressed size %d\n", file_buffer->block, 2436 file_buffer->size, compressed_size); 2437 } else { 2438 add_pending_fragment(write_buffer, c_byte, 2439 file_buffer->block); 2440 pthread_mutex_unlock(&fragment_mutex); 2441 } 2442 cache_block_put(file_buffer); 2443 } 2444 2445 pthread_cleanup_pop(0); 2446 } 2447 2448 2449 struct file_buffer *get_file_buffer() 2450 { 2451 struct file_buffer *file_buffer = seq_queue_get(to_main); 2452 2453 return file_buffer; 2454 } 2455 2456 2457 void write_file_empty(squashfs_inode *inode, struct dir_ent *dir_ent, 2458 struct file_buffer *file_buffer, int *duplicate_file) 2459 { 2460 file_count ++; 2461 *duplicate_file = FALSE; 2462 cache_block_put(file_buffer); 2463 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0, 2464 NULL, &empty_fragment, NULL, 0); 2465 } 2466 2467 2468 void write_file_frag(squashfs_inode *inode, struct dir_ent *dir_ent, 2469 struct file_buffer *file_buffer, int *duplicate_file) 2470 { 2471 int size = file_buffer->file_size; 2472 struct fragment *fragment; 2473 unsigned short checksum = file_buffer->checksum; 2474 char dont_put; 2475 2476 fragment = frag_duplicate(file_buffer, &dont_put); 2477 *duplicate_file = !fragment; 2478 if(!fragment) { 2479 fragment = get_and_fill_fragment(file_buffer, dir_ent); 2480 if(duplicate_checking) 2481 add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, 2482 TRUE, TRUE); 2483 } 2484 2485 if(dont_put) 2486 free(file_buffer); 2487 else 2488 cache_block_put(file_buffer); 2489 2490 total_bytes += size; 2491 file_count ++; 2492 2493 inc_progress_bar(); 2494 2495 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0, 2496 0, NULL, fragment, NULL, 0); 2497 2498 if(!duplicate_checking) 2499 free_fragment(fragment); 2500 } 2501 2502 2503 int write_file_process(squashfs_inode *inode, struct dir_ent *dir_ent, 2504 struct file_buffer *read_buffer, int *duplicate_file) 2505 { 2506 long long read_size, file_bytes, start; 2507 struct fragment *fragment; 2508 unsigned int *block_list = NULL; 2509 int block = 0, status; 2510 long long sparse = 0; 2511 struct file_buffer *fragment_buffer = NULL; 2512 2513 *duplicate_file = FALSE; 2514 2515 lock_fragments(); 2516 2517 file_bytes = 0; 2518 start = bytes; 2519 while (1) { 2520 read_size = read_buffer->file_size; 2521 if(read_buffer->fragment) 2522 fragment_buffer = read_buffer; 2523 else { 2524 block_list = realloc(block_list, (block + 1) * 2525 sizeof(unsigned int)); 2526 if(block_list == NULL) 2527 MEM_ERROR(); 2528 block_list[block ++] = read_buffer->c_byte; 2529 if(read_buffer->c_byte) { 2530 read_buffer->block = bytes; 2531 bytes += read_buffer->size; 2532 cache_hash(read_buffer, read_buffer->block); 2533 file_bytes += read_buffer->size; 2534 queue_put(to_writer, read_buffer); 2535 } else { 2536 sparse += read_buffer->size; 2537 cache_block_put(read_buffer); 2538 } 2539 } 2540 inc_progress_bar(); 2541 2542 if(read_size != -1) 2543 break; 2544 2545 read_buffer = get_file_buffer(); 2546 if(read_buffer->error) 2547 goto read_err; 2548 } 2549 2550 unlock_fragments(); 2551 fragment = get_and_fill_fragment(fragment_buffer, dir_ent); 2552 2553 if(duplicate_checking) 2554 add_non_dup(read_size, file_bytes, block_list, start, fragment, 2555 0, fragment_buffer ? fragment_buffer->checksum : 0, 2556 FALSE, TRUE); 2557 cache_block_put(fragment_buffer); 2558 file_count ++; 2559 total_bytes += read_size; 2560 2561 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start, 2562 block, block_list, fragment, NULL, sparse); 2563 2564 if(duplicate_checking == FALSE) { 2565 free(block_list); 2566 free_fragment(fragment); 2567 } 2568 2569 return 0; 2570 2571 read_err: 2572 dec_progress_bar(block); 2573 status = read_buffer->error; 2574 bytes = start; 2575 if(!block_device) { 2576 int res; 2577 2578 queue_put(to_writer, NULL); 2579 if(queue_get(from_writer) != 0) 2580 EXIT_MKSQUASHFS(); 2581 res = ftruncate(fd, bytes); 2582 if(res != 0) 2583 BAD_ERROR("Failed to truncate dest file because %s\n", 2584 strerror(errno)); 2585 } 2586 unlock_fragments(); 2587 free(block_list); 2588 cache_block_put(read_buffer); 2589 return status; 2590 } 2591 2592 2593 int write_file_blocks_dup(squashfs_inode *inode, struct dir_ent *dir_ent, 2594 struct file_buffer *read_buffer, int *duplicate_file) 2595 { 2596 int block, thresh; 2597 long long read_size = read_buffer->file_size; 2598 long long file_bytes, dup_start, start; 2599 struct fragment *fragment; 2600 struct file_info *dupl_ptr; 2601 int blocks = (read_size + block_size - 1) >> block_log; 2602 unsigned int *block_list, *block_listp; 2603 struct file_buffer **buffer_list; 2604 int status; 2605 long long sparse = 0; 2606 struct file_buffer *fragment_buffer = NULL; 2607 2608 block_list = malloc(blocks * sizeof(unsigned int)); 2609 if(block_list == NULL) 2610 MEM_ERROR(); 2611 block_listp = block_list; 2612 2613 buffer_list = malloc(blocks * sizeof(struct file_buffer *)); 2614 if(buffer_list == NULL) 2615 MEM_ERROR(); 2616 2617 lock_fragments(); 2618 2619 file_bytes = 0; 2620 start = dup_start = bytes; 2621 thresh = blocks > bwriter_size ? blocks - bwriter_size : 0; 2622 2623 for(block = 0; block < blocks;) { 2624 if(read_buffer->fragment) { 2625 block_list[block] = 0; 2626 buffer_list[block] = NULL; 2627 fragment_buffer = read_buffer; 2628 blocks = read_size >> block_log; 2629 } else { 2630 block_list[block] = read_buffer->c_byte; 2631 2632 if(read_buffer->c_byte) { 2633 read_buffer->block = bytes; 2634 bytes += read_buffer->size; 2635 file_bytes += read_buffer->size; 2636 cache_hash(read_buffer, read_buffer->block); 2637 if(block < thresh) { 2638 buffer_list[block] = NULL; 2639 queue_put(to_writer, read_buffer); 2640 } else 2641 buffer_list[block] = read_buffer; 2642 } else { 2643 buffer_list[block] = NULL; 2644 sparse += read_buffer->size; 2645 cache_block_put(read_buffer); 2646 } 2647 } 2648 inc_progress_bar(); 2649 2650 if(++block < blocks) { 2651 read_buffer = get_file_buffer(); 2652 if(read_buffer->error) 2653 goto read_err; 2654 } 2655 } 2656 2657 dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start, 2658 &fragment, fragment_buffer, blocks, 0, FALSE); 2659 2660 if(dupl_ptr) { 2661 *duplicate_file = FALSE; 2662 for(block = thresh; block < blocks; block ++) 2663 if(buffer_list[block]) 2664 queue_put(to_writer, buffer_list[block]); 2665 fragment = get_and_fill_fragment(fragment_buffer, dir_ent); 2666 dupl_ptr->fragment = fragment; 2667 } else { 2668 *duplicate_file = TRUE; 2669 for(block = thresh; block < blocks; block ++) 2670 cache_block_put(buffer_list[block]); 2671 bytes = start; 2672 if(thresh && !block_device) { 2673 int res; 2674 2675 queue_put(to_writer, NULL); 2676 if(queue_get(from_writer) != 0) 2677 EXIT_MKSQUASHFS(); 2678 res = ftruncate(fd, bytes); 2679 if(res != 0) 2680 BAD_ERROR("Failed to truncate dest file because" 2681 " %s\n", strerror(errno)); 2682 } 2683 } 2684 2685 unlock_fragments(); 2686 cache_block_put(fragment_buffer); 2687 free(buffer_list); 2688 file_count ++; 2689 total_bytes += read_size; 2690 2691 /* 2692 * sparse count is needed to ensure squashfs correctly reports a 2693 * a smaller block count on stat calls to sparse files. This is 2694 * to ensure intelligent applications like cp correctly handle the 2695 * file as a sparse file. If the file in the original filesystem isn't 2696 * stored as a sparse file then still store it sparsely in squashfs, but 2697 * report it as non-sparse on stat calls to preserve semantics 2698 */ 2699 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size) 2700 sparse = 0; 2701 2702 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, 2703 dup_start, blocks, block_listp, fragment, NULL, sparse); 2704 2705 if(*duplicate_file == TRUE) 2706 free(block_list); 2707 2708 return 0; 2709 2710 read_err: 2711 dec_progress_bar(block); 2712 status = read_buffer->error; 2713 bytes = start; 2714 if(thresh && !block_device) { 2715 int res; 2716 2717 queue_put(to_writer, NULL); 2718 if(queue_get(from_writer) != 0) 2719 EXIT_MKSQUASHFS(); 2720 res = ftruncate(fd, bytes); 2721 if(res != 0) 2722 BAD_ERROR("Failed to truncate dest file because %s\n", 2723 strerror(errno)); 2724 } 2725 unlock_fragments(); 2726 for(blocks = thresh; blocks < block; blocks ++) 2727 cache_block_put(buffer_list[blocks]); 2728 free(buffer_list); 2729 free(block_list); 2730 cache_block_put(read_buffer); 2731 return status; 2732 } 2733 2734 2735 int write_file_blocks(squashfs_inode *inode, struct dir_ent *dir_ent, 2736 struct file_buffer *read_buffer, int *dup) 2737 { 2738 long long read_size = read_buffer->file_size; 2739 long long file_bytes, start; 2740 struct fragment *fragment; 2741 unsigned int *block_list; 2742 int block, status; 2743 int blocks = (read_size + block_size - 1) >> block_log; 2744 long long sparse = 0; 2745 struct file_buffer *fragment_buffer = NULL; 2746 2747 if(pre_duplicate(read_size)) 2748 return write_file_blocks_dup(inode, dir_ent, read_buffer, dup); 2749 2750 *dup = FALSE; 2751 2752 block_list = malloc(blocks * sizeof(unsigned int)); 2753 if(block_list == NULL) 2754 MEM_ERROR(); 2755 2756 lock_fragments(); 2757 2758 file_bytes = 0; 2759 start = bytes; 2760 for(block = 0; block < blocks;) { 2761 if(read_buffer->fragment) { 2762 block_list[block] = 0; 2763 fragment_buffer = read_buffer; 2764 blocks = read_size >> block_log; 2765 } else { 2766 block_list[block] = read_buffer->c_byte; 2767 if(read_buffer->c_byte) { 2768 read_buffer->block = bytes; 2769 bytes += read_buffer->size; 2770 cache_hash(read_buffer, read_buffer->block); 2771 file_bytes += read_buffer->size; 2772 queue_put(to_writer, read_buffer); 2773 } else { 2774 sparse += read_buffer->size; 2775 cache_block_put(read_buffer); 2776 } 2777 } 2778 inc_progress_bar(); 2779 2780 if(++block < blocks) { 2781 read_buffer = get_file_buffer(); 2782 if(read_buffer->error) 2783 goto read_err; 2784 } 2785 } 2786 2787 unlock_fragments(); 2788 fragment = get_and_fill_fragment(fragment_buffer, dir_ent); 2789 2790 if(duplicate_checking) 2791 add_non_dup(read_size, file_bytes, block_list, start, fragment, 2792 0, fragment_buffer ? fragment_buffer->checksum : 0, 2793 FALSE, TRUE); 2794 cache_block_put(fragment_buffer); 2795 file_count ++; 2796 total_bytes += read_size; 2797 2798 /* 2799 * sparse count is needed to ensure squashfs correctly reports a 2800 * a smaller block count on stat calls to sparse files. This is 2801 * to ensure intelligent applications like cp correctly handle the 2802 * file as a sparse file. If the file in the original filesystem isn't 2803 * stored as a sparse file then still store it sparsely in squashfs, but 2804 * report it as non-sparse on stat calls to preserve semantics 2805 */ 2806 if(sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size) 2807 sparse = 0; 2808 2809 create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start, 2810 blocks, block_list, fragment, NULL, sparse); 2811 2812 if(duplicate_checking == FALSE) { 2813 free(block_list); 2814 free_fragment(fragment); 2815 } 2816 2817 return 0; 2818 2819 read_err: 2820 dec_progress_bar(block); 2821 status = read_buffer->error; 2822 bytes = start; 2823 if(!block_device) { 2824 int res; 2825 2826 queue_put(to_writer, NULL); 2827 if(queue_get(from_writer) != 0) 2828 EXIT_MKSQUASHFS(); 2829 res = ftruncate(fd, bytes); 2830 if(res != 0) 2831 BAD_ERROR("Failed to truncate dest file because %s\n", 2832 strerror(errno)); 2833 } 2834 unlock_fragments(); 2835 free(block_list); 2836 cache_block_put(read_buffer); 2837 return status; 2838 } 2839 2840 2841 void write_file(squashfs_inode *inode, struct dir_ent *dir, int *dup) 2842 { 2843 int status; 2844 struct file_buffer *read_buffer; 2845 2846 again: 2847 read_buffer = get_file_buffer(); 2848 status = read_buffer->error; 2849 2850 if(status) 2851 cache_block_put(read_buffer); 2852 else if(read_buffer->file_size == -1) 2853 status = write_file_process(inode, dir, read_buffer, dup); 2854 else if(read_buffer->file_size == 0) 2855 write_file_empty(inode, dir, read_buffer, dup); 2856 else if(read_buffer->fragment && read_buffer->c_byte) 2857 write_file_frag(inode, dir, read_buffer, dup); 2858 else 2859 status = write_file_blocks(inode, dir, read_buffer, dup); 2860 2861 if(status == 2) { 2862 ERROR("File %s changed size while reading filesystem, " 2863 "attempting to re-read\n", pathname(dir)); 2864 goto again; 2865 } else if(status == 1) { 2866 ERROR_START("Failed to read file %s", pathname(dir)); 2867 ERROR_EXIT(", creating empty file\n"); 2868 write_file_empty(inode, dir, NULL, dup); 2869 } 2870 } 2871 2872 2873 #define BUFF_SIZE 512 2874 char *name; 2875 char *basename_r(); 2876 2877 char *getbase(char *pathname) 2878 { 2879 static char *b_buffer = NULL; 2880 static int b_size = BUFF_SIZE; 2881 char *result; 2882 2883 if(b_buffer == NULL) { 2884 b_buffer = malloc(b_size); 2885 if(b_buffer == NULL) 2886 MEM_ERROR(); 2887 } 2888 2889 while(1) { 2890 if(*pathname != '/') { 2891 result = getcwd(b_buffer, b_size); 2892 if(result == NULL && errno != ERANGE) 2893 BAD_ERROR("Getcwd failed in getbase\n"); 2894 2895 /* enough room for pathname + "/" + '\0' terminator? */ 2896 if(result && strlen(pathname) + 2 <= 2897 b_size - strlen(b_buffer)) { 2898 strcat(strcat(b_buffer, "/"), pathname); 2899 break; 2900 } 2901 } else if(strlen(pathname) < b_size) { 2902 strcpy(b_buffer, pathname); 2903 break; 2904 } 2905 2906 /* Buffer not large enough, realloc and try again */ 2907 b_buffer = realloc(b_buffer, b_size += BUFF_SIZE); 2908 if(b_buffer == NULL) 2909 MEM_ERROR(); 2910 } 2911 2912 name = b_buffer; 2913 if(((result = basename_r()) == NULL) || (strcmp(result, "..") == 0)) 2914 return NULL; 2915 else 2916 return result; 2917 } 2918 2919 2920 char *basename_r() 2921 { 2922 char *s; 2923 char *p; 2924 int n = 1; 2925 2926 for(;;) { 2927 s = name; 2928 if(*name == '\0') 2929 return NULL; 2930 if(*name != '/') { 2931 while(*name != '\0' && *name != '/') name++; 2932 n = name - s; 2933 } 2934 while(*name == '/') name++; 2935 if(strncmp(s, ".", n) == 0) 2936 continue; 2937 if((*name == '\0') || (strncmp(s, "..", n) == 0) || 2938 ((p = basename_r()) == NULL)) { 2939 s[n] = '\0'; 2940 return s; 2941 } 2942 if(strcmp(p, "..") == 0) 2943 continue; 2944 return p; 2945 } 2946 } 2947 2948 2949 struct inode_info *lookup_inode3(struct stat *buf, int pseudo, int id, 2950 char *symlink, int bytes) 2951 { 2952 int ino_hash = INODE_HASH(buf->st_dev, buf->st_ino); 2953 struct inode_info *inode; 2954 2955 /* 2956 * Look-up inode in hash table, if it already exists we have a 2957 * hard-link, so increment the nlink count and return it. 2958 * Don't do the look-up for directories because we don't hard-link 2959 * directories. 2960 */ 2961 if ((buf->st_mode & S_IFMT) != S_IFDIR) { 2962 for(inode = inode_info[ino_hash]; inode; inode = inode->next) { 2963 if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) { 2964 inode->nlink ++; 2965 return inode; 2966 } 2967 } 2968 } 2969 2970 inode = malloc(sizeof(struct inode_info) + bytes); 2971 if(inode == NULL) 2972 MEM_ERROR(); 2973 2974 if(bytes) 2975 memcpy(&inode->symlink, symlink, bytes); 2976 memcpy(&inode->buf, buf, sizeof(struct stat)); 2977 inode->read = FALSE; 2978 inode->root_entry = FALSE; 2979 inode->pseudo_file = pseudo; 2980 inode->pseudo_id = id; 2981 inode->inode = SQUASHFS_INVALID_BLK; 2982 inode->nlink = 1; 2983 inode->inode_number = 0; 2984 2985 /* 2986 * Copy filesystem wide defaults into inode, these filesystem 2987 * wide defaults may be altered on an individual inode basis by 2988 * user specified actions 2989 * 2990 */ 2991 inode->no_fragments = no_fragments; 2992 inode->always_use_fragments = always_use_fragments; 2993 inode->noD = noD; 2994 inode->noF = noF; 2995 2996 inode->next = inode_info[ino_hash]; 2997 inode_info[ino_hash] = inode; 2998 2999 return inode; 3000 } 3001 3002 3003 struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id) 3004 { 3005 return lookup_inode3(buf, pseudo, id, NULL, 0); 3006 } 3007 3008 3009 inline struct inode_info *lookup_inode(struct stat *buf) 3010 { 3011 return lookup_inode2(buf, 0, 0); 3012 } 3013 3014 3015 inline void alloc_inode_no(struct inode_info *inode, unsigned int use_this) 3016 { 3017 if (inode->inode_number == 0) { 3018 inode->inode_number = use_this ? : inode_no ++; 3019 if((inode->buf.st_mode & S_IFMT) == S_IFREG) 3020 progress_bar_size((inode->buf.st_size + block_size - 1) 3021 >> block_log); 3022 } 3023 } 3024 3025 3026 inline struct dir_ent *create_dir_entry(char *name, char *source_name, 3027 char *nonstandard_pathname, struct dir_info *dir) 3028 { 3029 struct dir_ent *dir_ent = malloc(sizeof(struct dir_ent)); 3030 if(dir_ent == NULL) 3031 MEM_ERROR(); 3032 3033 dir_ent->name = name; 3034 dir_ent->source_name = source_name; 3035 dir_ent->nonstandard_pathname = nonstandard_pathname; 3036 dir_ent->our_dir = dir; 3037 dir_ent->inode = NULL; 3038 dir_ent->next = NULL; 3039 3040 return dir_ent; 3041 } 3042 3043 3044 inline void add_dir_entry(struct dir_ent *dir_ent, struct dir_info *sub_dir, 3045 struct inode_info *inode_info) 3046 { 3047 struct dir_info *dir = dir_ent->our_dir; 3048 3049 if(sub_dir) 3050 sub_dir->dir_ent = dir_ent; 3051 3052 /* ANDROID CHANGES START*/ 3053 #ifdef ANDROID 3054 if (android_config) { 3055 if (mount_point) { 3056 char *mounted_path; 3057 alloc_mounted_path(mount_point, subpathname(dir_ent), &mounted_path); 3058 android_fs_config(mounted_path, &inode_info->buf, target_out_path); 3059 free(mounted_path); 3060 } else { 3061 android_fs_config(pathname(dir_ent), &inode_info->buf, target_out_path); 3062 } 3063 } 3064 #endif 3065 /* ANDROID CHANGES END */ 3066 3067 dir_ent->inode = inode_info; 3068 dir_ent->dir = sub_dir; 3069 3070 dir_ent->next = dir->list; 3071 dir->list = dir_ent; 3072 dir->count++; 3073 } 3074 3075 /* ANDROID CHANGES START*/ 3076 #ifdef ANDROID 3077 /* Weird linker bug that complains those inline functions are undefined. */ 3078 extern inline void add_dir_entry(struct dir_ent *dir_ent, struct dir_info *sub_dir, 3079 struct inode_info *inode_info); 3080 extern inline void add_dir_entry2(char *name, char *source_name, 3081 char *nonstandard_pathname, struct dir_info *sub_dir, 3082 struct inode_info *inode_info, struct dir_info *dir); 3083 #endif 3084 /* ANDROID CHANGES END */ 3085 3086 inline void add_dir_entry2(char *name, char *source_name, 3087 char *nonstandard_pathname, struct dir_info *sub_dir, 3088 struct inode_info *inode_info, struct dir_info *dir) 3089 { 3090 struct dir_ent *dir_ent = create_dir_entry(name, source_name, 3091 nonstandard_pathname, dir); 3092 3093 3094 add_dir_entry(dir_ent, sub_dir, inode_info); 3095 } 3096 3097 3098 inline void free_dir_entry(struct dir_ent *dir_ent) 3099 { 3100 if(dir_ent->name) 3101 free(dir_ent->name); 3102 3103 if(dir_ent->source_name) 3104 free(dir_ent->source_name); 3105 3106 if(dir_ent->nonstandard_pathname) 3107 free(dir_ent->nonstandard_pathname); 3108 3109 /* if this entry has been associated with an inode, then we need 3110 * to update the inode nlink count. Orphaned inodes are harmless, and 3111 * is easier to leave them than go to the bother of deleting them */ 3112 if(dir_ent->inode && !dir_ent->inode->root_entry) 3113 dir_ent->inode->nlink --; 3114 3115 free(dir_ent); 3116 } 3117 3118 3119 inline void add_excluded(struct dir_info *dir) 3120 { 3121 dir->excluded ++; 3122 } 3123 3124 3125 void dir_scan(squashfs_inode *inode, char *pathname, 3126 struct dir_ent *(_readdir)(struct dir_info *), int progress) 3127 { 3128 struct stat buf; 3129 struct dir_ent *dir_ent; 3130 3131 root_dir = dir_scan1(pathname, "", paths, _readdir, 1); 3132 if(root_dir == NULL) 3133 return; 3134 3135 /* Create root directory dir_ent and associated inode, and connect 3136 * it to the root directory dir_info structure */ 3137 dir_ent = create_dir_entry("", NULL, pathname, 3138 scan1_opendir("", "", 0)); 3139 3140 if(pathname[0] == '\0') { 3141 /* 3142 * dummy top level directory, if multiple sources specified on 3143 * command line 3144 */ 3145 memset(&buf, 0, sizeof(buf)); 3146 buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR; 3147 buf.st_uid = getuid(); 3148 buf.st_gid = getgid(); 3149 buf.st_mtime = time(NULL); 3150 buf.st_dev = 0; 3151 buf.st_ino = 0; 3152 dir_ent->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0); 3153 } else { 3154 if(lstat(pathname, &buf) == -1) 3155 /* source directory has disappeared? */ 3156 BAD_ERROR("Cannot stat source directory %s because %s\n", 3157 pathname, strerror(errno)); 3158 /* ANDROID CHANGES START*/ 3159 #ifdef ANDROID 3160 if (android_config) 3161 if (mount_point) 3162 android_fs_config(mount_point, &buf, target_out_path); 3163 else 3164 android_fs_config(pathname, &buf, target_out_path); 3165 #endif 3166 /* ANDROID CHANGES END */ 3167 dir_ent->inode = lookup_inode(&buf); 3168 } 3169 3170 dir_ent->dir = root_dir; 3171 root_dir->dir_ent = dir_ent; 3172 3173 /* 3174 * Process most actions and any pseudo files 3175 */ 3176 if(actions() || get_pseudo()) 3177 dir_scan2(root_dir, get_pseudo()); 3178 3179 /* 3180 * Process move actions 3181 */ 3182 if(move_actions()) { 3183 dir_scan3(root_dir); 3184 do_move_actions(); 3185 } 3186 3187 /* 3188 * Process prune actions 3189 */ 3190 if(prune_actions()) 3191 dir_scan4(root_dir); 3192 3193 /* 3194 * Process empty actions 3195 */ 3196 if(empty_actions()) 3197 dir_scan5(root_dir); 3198 3199 /* 3200 * Sort directories and compute the inode numbers 3201 */ 3202 dir_scan6(root_dir); 3203 3204 alloc_inode_no(dir_ent->inode, root_inode_number); 3205 3206 eval_actions(root_dir, dir_ent); 3207 3208 if(sorted) 3209 generate_file_priorities(root_dir, 0, 3210 &root_dir->dir_ent->inode->buf); 3211 3212 if(appending) { 3213 sigset_t sigmask; 3214 3215 restore_thread = init_restore_thread(); 3216 sigemptyset(&sigmask); 3217 sigaddset(&sigmask, SIGINT); 3218 sigaddset(&sigmask, SIGTERM); 3219 sigaddset(&sigmask, SIGUSR1); 3220 if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1) 3221 BAD_ERROR("Failed to set signal mask\n"); 3222 write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0"); 3223 } 3224 3225 queue_put(to_reader, root_dir); 3226 3227 set_progressbar_state(progress); 3228 3229 if(sorted) 3230 sort_files_and_write(root_dir); 3231 3232 dir_scan7(inode, root_dir); 3233 dir_ent->inode->inode = *inode; 3234 dir_ent->inode->type = SQUASHFS_DIR_TYPE; 3235 } 3236 3237 3238 /* 3239 * dir_scan1 routines... 3240 * These scan the source directories into memory for processing. 3241 * Exclude actions are processed here (in contrast to the other actions) 3242 * because they affect what is scanned. 3243 */ 3244 struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth) 3245 { 3246 struct dir_info *dir; 3247 3248 dir = malloc(sizeof(struct dir_info)); 3249 if(dir == NULL) 3250 MEM_ERROR(); 3251 3252 if(pathname[0] != '\0') { 3253 dir->linuxdir = opendir(pathname); 3254 if(dir->linuxdir == NULL) { 3255 free(dir); 3256 return NULL; 3257 } 3258 } 3259 3260 dir->pathname = strdup(pathname); 3261 dir->subpath = strdup(subpath); 3262 dir->count = 0; 3263 dir->directory_count = 0; 3264 dir->dir_is_ldir = TRUE; 3265 dir->list = NULL; 3266 dir->depth = depth; 3267 dir->excluded = 0; 3268 3269 return dir; 3270 } 3271 3272 3273 struct dir_ent *scan1_encomp_readdir(struct dir_info *dir) 3274 { 3275 static int index = 0; 3276 3277 if(dir->count < old_root_entries) { 3278 int i; 3279 3280 for(i = 0; i < old_root_entries; i++) { 3281 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE) 3282 dir->directory_count ++; 3283 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL, 3284 &old_root_entry[i].inode, dir); 3285 } 3286 } 3287 3288 while(index < source) { 3289 char *basename = NULL; 3290 char *dir_name = getbase(source_path[index]); 3291 int pass = 1, res; 3292 3293 if(dir_name == NULL) { 3294 ERROR_START("Bad source directory %s", 3295 source_path[index]); 3296 ERROR_EXIT(" - skipping ...\n"); 3297 index ++; 3298 continue; 3299 } 3300 dir_name = strdup(dir_name); 3301 for(;;) { 3302 struct dir_ent *dir_ent = dir->list; 3303 3304 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0; 3305 dir_ent = dir_ent->next); 3306 if(dir_ent == NULL) 3307 break; 3308 ERROR("Source directory entry %s already used! - trying" 3309 " ", dir_name); 3310 if(pass == 1) 3311 basename = dir_name; 3312 else 3313 free(dir_name); 3314 res = asprintf(&dir_name, "%s_%d", basename, pass++); 3315 if(res == -1) 3316 BAD_ERROR("asprintf failed in " 3317 "scan1_encomp_readdir\n"); 3318 ERROR("%s\n", dir_name); 3319 } 3320 return create_dir_entry(dir_name, basename, 3321 strdup(source_path[index ++]), dir); 3322 } 3323 return NULL; 3324 } 3325 3326 3327 struct dir_ent *scan1_single_readdir(struct dir_info *dir) 3328 { 3329 struct dirent *d_name; 3330 int i; 3331 3332 if(dir->count < old_root_entries) { 3333 for(i = 0; i < old_root_entries; i++) { 3334 if(old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE) 3335 dir->directory_count ++; 3336 add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL, 3337 &old_root_entry[i].inode, dir); 3338 } 3339 } 3340 3341 if((d_name = readdir(dir->linuxdir)) != NULL) { 3342 char *basename = NULL; 3343 char *dir_name = strdup(d_name->d_name); 3344 int pass = 1, res; 3345 3346 for(;;) { 3347 struct dir_ent *dir_ent = dir->list; 3348 3349 for(; dir_ent && strcmp(dir_ent->name, dir_name) != 0; 3350 dir_ent = dir_ent->next); 3351 if(dir_ent == NULL) 3352 break; 3353 ERROR("Source directory entry %s already used! - trying" 3354 " ", dir_name); 3355 if (pass == 1) 3356 basename = dir_name; 3357 else 3358 free(dir_name); 3359 res = asprintf(&dir_name, "%s_%d", d_name->d_name, pass++); 3360 if(res == -1) 3361 BAD_ERROR("asprintf failed in " 3362 "scan1_single_readdir\n"); 3363 ERROR("%s\n", dir_name); 3364 } 3365 return create_dir_entry(dir_name, basename, NULL, dir); 3366 } 3367 3368 return NULL; 3369 } 3370 3371 3372 struct dir_ent *scan1_readdir(struct dir_info *dir) 3373 { 3374 struct dirent *d_name = readdir(dir->linuxdir); 3375 3376 return d_name ? 3377 create_dir_entry(strdup(d_name->d_name), NULL, NULL, dir) : 3378 NULL; 3379 } 3380 3381 3382 void scan1_freedir(struct dir_info *dir) 3383 { 3384 if(dir->pathname[0] != '\0') 3385 closedir(dir->linuxdir); 3386 } 3387 3388 3389 struct dir_info *dir_scan1(char *filename, char *subpath, 3390 struct pathnames *paths, 3391 struct dir_ent *(_readdir)(struct dir_info *), int depth) 3392 { 3393 struct dir_info *dir = scan1_opendir(filename, subpath, depth); 3394 struct dir_ent *dir_ent; 3395 3396 if(dir == NULL) { 3397 ERROR_START("Could not open %s", filename); 3398 ERROR_EXIT(", skipping...\n"); 3399 return NULL; 3400 } 3401 3402 while((dir_ent = _readdir(dir))) { 3403 struct dir_info *sub_dir; 3404 struct stat buf; 3405 struct pathnames *new = NULL; 3406 char *filename = pathname(dir_ent); 3407 char *subpath = NULL; 3408 char *dir_name = dir_ent->name; 3409 3410 if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0) { 3411 free_dir_entry(dir_ent); 3412 continue; 3413 } 3414 3415 if(lstat(filename, &buf) == -1) { 3416 ERROR_START("Cannot stat dir/file %s because %s", 3417 filename, strerror(errno)); 3418 ERROR_EXIT(", ignoring\n"); 3419 free_dir_entry(dir_ent); 3420 continue; 3421 } 3422 3423 if((buf.st_mode & S_IFMT) != S_IFREG && 3424 (buf.st_mode & S_IFMT) != S_IFDIR && 3425 (buf.st_mode & S_IFMT) != S_IFLNK && 3426 (buf.st_mode & S_IFMT) != S_IFCHR && 3427 (buf.st_mode & S_IFMT) != S_IFBLK && 3428 (buf.st_mode & S_IFMT) != S_IFIFO && 3429 (buf.st_mode & S_IFMT) != S_IFSOCK) { 3430 ERROR_START("File %s has unrecognised filetype %d", 3431 filename, buf.st_mode & S_IFMT); 3432 ERROR_EXIT(", ignoring\n"); 3433 free_dir_entry(dir_ent); 3434 continue; 3435 } 3436 3437 if((old_exclude && old_excluded(filename, &buf)) || 3438 (!old_exclude && excluded(dir_name, paths, &new))) { 3439 add_excluded(dir); 3440 free_dir_entry(dir_ent); 3441 continue; 3442 } 3443 3444 if(exclude_actions()) { 3445 subpath = subpathname(dir_ent); 3446 3447 if(eval_exclude_actions(dir_name, filename, subpath, 3448 &buf, depth, dir_ent)) { 3449 add_excluded(dir); 3450 free_dir_entry(dir_ent); 3451 continue; 3452 } 3453 } 3454 3455 switch(buf.st_mode & S_IFMT) { 3456 case S_IFDIR: 3457 if(subpath == NULL) 3458 subpath = subpathname(dir_ent); 3459 3460 sub_dir = dir_scan1(filename, subpath, new, 3461 scan1_readdir, depth + 1); 3462 if(sub_dir) { 3463 dir->directory_count ++; 3464 add_dir_entry(dir_ent, sub_dir, 3465 lookup_inode(&buf)); 3466 } else 3467 free_dir_entry(dir_ent); 3468 break; 3469 case S_IFLNK: { 3470 int byte; 3471 static char buff[65536]; /* overflow safe */ 3472 3473 byte = readlink(filename, buff, 65536); 3474 if(byte == -1) { 3475 ERROR_START("Failed to read symlink %s", 3476 filename); 3477 ERROR_EXIT(", ignoring\n"); 3478 } else if(byte == 65536) { 3479 ERROR_START("Symlink %s is greater than 65536 " 3480 "bytes!", filename); 3481 ERROR_EXIT(", ignoring\n"); 3482 } else { 3483 /* readlink doesn't 0 terminate the returned 3484 * path */ 3485 buff[byte] = '\0'; 3486 add_dir_entry(dir_ent, NULL, lookup_inode3(&buf, 3487 0, 0, buff, byte + 1)); 3488 } 3489 break; 3490 } 3491 default: 3492 add_dir_entry(dir_ent, NULL, lookup_inode(&buf)); 3493 } 3494 3495 free(new); 3496 } 3497 3498 scan1_freedir(dir); 3499 3500 return dir; 3501 } 3502 3503 3504 /* 3505 * dir_scan2 routines... 3506 * This processes most actions and any pseudo files 3507 */ 3508 struct dir_ent *scan2_readdir(struct dir_info *dir, struct dir_ent *dir_ent) 3509 { 3510 if (dir_ent == NULL) 3511 dir_ent = dir->list; 3512 else 3513 dir_ent = dir_ent->next; 3514 3515 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next); 3516 3517 return dir_ent; 3518 } 3519 3520 3521 struct dir_ent *scan2_lookup(struct dir_info *dir, char *name) 3522 { 3523 struct dir_ent *dir_ent = dir->list; 3524 3525 for(; dir_ent && strcmp(dir_ent->name, name) != 0; 3526 dir_ent = dir_ent->next); 3527 3528 return dir_ent; 3529 } 3530 3531 3532 void dir_scan2(struct dir_info *dir, struct pseudo *pseudo) 3533 { 3534 struct dir_ent *dir_ent = NULL; 3535 struct pseudo_entry *pseudo_ent; 3536 struct stat buf; 3537 static int pseudo_ino = 1; 3538 3539 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) { 3540 struct inode_info *inode_info = dir_ent->inode; 3541 struct stat *buf = &inode_info->buf; 3542 char *name = dir_ent->name; 3543 3544 eval_actions(root_dir, dir_ent); 3545 3546 if((buf->st_mode & S_IFMT) == S_IFDIR) 3547 dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo)); 3548 } 3549 3550 while((pseudo_ent = pseudo_readdir(pseudo)) != NULL) { 3551 dir_ent = scan2_lookup(dir, pseudo_ent->name); 3552 if(pseudo_ent->dev->type == 'm') { 3553 struct stat *buf; 3554 if(dir_ent == NULL) { 3555 ERROR_START("Pseudo modify file \"%s\" does " 3556 "not exist in source filesystem.", 3557 pseudo_ent->pathname); 3558 ERROR_EXIT(" Ignoring.\n"); 3559 continue; 3560 } 3561 if(dir_ent->inode->root_entry) { 3562 ERROR_START("Pseudo modify file \"%s\" is a " 3563 "pre-existing file in the filesystem " 3564 "being appended to. It cannot be "\ 3565 "modified.", pseudo_ent->pathname); 3566 ERROR_EXIT(" Ignoring.\n"); 3567 continue; 3568 } 3569 buf = &dir_ent->inode->buf; 3570 buf->st_mode = (buf->st_mode & S_IFMT) | 3571 pseudo_ent->dev->mode; 3572 buf->st_uid = pseudo_ent->dev->uid; 3573 buf->st_gid = pseudo_ent->dev->gid; 3574 continue; 3575 } 3576 3577 if(dir_ent) { 3578 if(dir_ent->inode->root_entry) { 3579 ERROR_START("Pseudo file \"%s\" is a " 3580 "pre-existing file in the filesystem " 3581 "being appended to.", 3582 pseudo_ent->pathname); 3583 ERROR_EXIT(" Ignoring.\n"); 3584 } else { 3585 ERROR_START("Pseudo file \"%s\" exists in " 3586 "source filesystem \"%s\".", 3587 pseudo_ent->pathname, 3588 pathname(dir_ent)); 3589 ERROR_EXIT("\nIgnoring, exclude it (-e/-ef) to " 3590 "override.\n"); 3591 } 3592 continue; 3593 } 3594 3595 memset(&buf, 0, sizeof(buf)); 3596 buf.st_mode = pseudo_ent->dev->mode; 3597 buf.st_uid = pseudo_ent->dev->uid; 3598 buf.st_gid = pseudo_ent->dev->gid; 3599 buf.st_rdev = makedev(pseudo_ent->dev->major, 3600 pseudo_ent->dev->minor); 3601 buf.st_mtime = time(NULL); 3602 buf.st_ino = pseudo_ino ++; 3603 3604 if(pseudo_ent->dev->type == 'd') { 3605 struct dir_ent *dir_ent = 3606 create_dir_entry(pseudo_ent->name, NULL, 3607 pseudo_ent->pathname, dir); 3608 char *subpath = strdup(subpathname(dir_ent)); 3609 struct dir_info *sub_dir = scan1_opendir("", subpath, 3610 dir->depth + 1); 3611 if(sub_dir == NULL) { 3612 ERROR_START("Could not create pseudo directory " 3613 "\"%s\"", pseudo_ent->pathname); 3614 ERROR_EXIT(", skipping...\n"); 3615 free(subpath); 3616 pseudo_ino --; 3617 continue; 3618 } 3619 dir_scan2(sub_dir, pseudo_ent->pseudo); 3620 dir->directory_count ++; 3621 add_dir_entry(dir_ent, sub_dir, 3622 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0)); 3623 } else if(pseudo_ent->dev->type == 'f') { 3624 add_dir_entry2(pseudo_ent->name, NULL, 3625 pseudo_ent->pathname, NULL, 3626 lookup_inode2(&buf, PSEUDO_FILE_PROCESS, 3627 pseudo_ent->dev->pseudo_id), dir); 3628 } else { 3629 add_dir_entry2(pseudo_ent->name, NULL, 3630 pseudo_ent->pathname, NULL, 3631 lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir); 3632 } 3633 } 3634 } 3635 3636 3637 /* 3638 * dir_scan3 routines... 3639 * This processes the move action 3640 */ 3641 void dir_scan3(struct dir_info *dir) 3642 { 3643 struct dir_ent *dir_ent = NULL; 3644 3645 while((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) { 3646 3647 eval_move_actions(root_dir, dir_ent); 3648 3649 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) 3650 dir_scan3(dir_ent->dir); 3651 } 3652 } 3653 3654 3655 /* 3656 * dir_scan4 routines... 3657 * This processes the prune action. This action is designed to do fine 3658 * grained tuning of the in-core directory structure after the exclude, 3659 * move and pseudo actions have been performed. This allows complex 3660 * tests to be performed which are impossible at exclude time (i.e. 3661 * tests which rely on the in-core directory structure) 3662 */ 3663 void free_dir(struct dir_info *dir) 3664 { 3665 struct dir_ent *dir_ent = dir->list; 3666 3667 while(dir_ent) { 3668 struct dir_ent *tmp = dir_ent; 3669 3670 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) 3671 free_dir(dir_ent->dir); 3672 3673 dir_ent = dir_ent->next; 3674 free_dir_entry(tmp); 3675 } 3676 3677 free(dir->pathname); 3678 free(dir->subpath); 3679 free(dir); 3680 } 3681 3682 3683 void dir_scan4(struct dir_info *dir) 3684 { 3685 struct dir_ent *dir_ent = dir->list, *prev = NULL; 3686 3687 while(dir_ent) { 3688 if(dir_ent->inode->root_entry) { 3689 prev = dir_ent; 3690 dir_ent = dir_ent->next; 3691 continue; 3692 } 3693 3694 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) 3695 dir_scan4(dir_ent->dir); 3696 3697 if(eval_prune_actions(root_dir, dir_ent)) { 3698 struct dir_ent *tmp = dir_ent; 3699 3700 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) { 3701 free_dir(dir_ent->dir); 3702 dir->directory_count --; 3703 } 3704 3705 dir->count --; 3706 3707 /* remove dir_ent from list */ 3708 dir_ent = dir_ent->next; 3709 if(prev) 3710 prev->next = dir_ent; 3711 else 3712 dir->list = dir_ent; 3713 3714 /* free it */ 3715 free_dir_entry(tmp); 3716 3717 add_excluded(dir); 3718 continue; 3719 } 3720 3721 prev = dir_ent; 3722 dir_ent = dir_ent->next; 3723 } 3724 } 3725 3726 3727 /* 3728 * dir_scan5 routines... 3729 * This processes the empty action. This action has to be processed after 3730 * all other actions because the previous exclude and move actions and the 3731 * pseudo actions affect whether a directory is empty 3732 */ 3733 void dir_scan5(struct dir_info *dir) 3734 { 3735 struct dir_ent *dir_ent = dir->list, *prev = NULL; 3736 3737 while(dir_ent) { 3738 if(dir_ent->inode->root_entry) { 3739 prev = dir_ent; 3740 dir_ent = dir_ent->next; 3741 continue; 3742 } 3743 3744 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) { 3745 dir_scan5(dir_ent->dir); 3746 3747 if(eval_empty_actions(root_dir, dir_ent)) { 3748 struct dir_ent *tmp = dir_ent; 3749 3750 /* 3751 * delete sub-directory, this is by definition 3752 * empty 3753 */ 3754 free(dir_ent->dir->pathname); 3755 free(dir_ent->dir->subpath); 3756 free(dir_ent->dir); 3757 3758 /* remove dir_ent from list */ 3759 dir_ent = dir_ent->next; 3760 if(prev) 3761 prev->next = dir_ent; 3762 else 3763 dir->list = dir_ent; 3764 3765 /* free it */ 3766 free_dir_entry(tmp); 3767 3768 /* update counts */ 3769 dir->directory_count --; 3770 dir->count --; 3771 add_excluded(dir); 3772 continue; 3773 } 3774 } 3775 3776 prev = dir_ent; 3777 dir_ent = dir_ent->next; 3778 } 3779 } 3780 3781 3782 /* 3783 * dir_scan6 routines... 3784 * This sorts every directory and computes the inode numbers 3785 */ 3786 3787 /* 3788 * Bottom up linked list merge sort. 3789 * 3790 * Qsort and other O(n log n) algorithms work well with arrays but not 3791 * linked lists. Merge sort another O(n log n) sort algorithm on the other hand 3792 * is not ideal for arrays (as it needs an additonal n storage locations 3793 * as sorting is not done in place), but it is ideal for linked lists because 3794 * it doesn't require any extra storage, 3795 */ 3796 void sort_directory(struct dir_info *dir) 3797 { 3798 struct dir_ent *cur, *l1, *l2, *next; 3799 int len1, len2, stride = 1; 3800 3801 if(dir->list == NULL || dir->count < 2) 3802 return; 3803 3804 /* 3805 * We can consider our linked-list to be made up of stride length 3806 * sublists. Eacn iteration around this loop merges adjacent 3807 * stride length sublists into larger 2*stride sublists. We stop 3808 * when stride becomes equal to the entire list. 3809 * 3810 * Initially stride = 1 (by definition a sublist of 1 is sorted), and 3811 * these 1 element sublists are merged into 2 element sublists, which 3812 * are then merged into 4 element sublists and so on. 3813 */ 3814 do { 3815 l2 = dir->list; /* head of current linked list */ 3816 cur = NULL; /* empty output list */ 3817 3818 /* 3819 * Iterate through the linked list, merging adjacent sublists. 3820 * On each interation l2 points to the next sublist pair to be 3821 * merged (if there's only one sublist left this is simply added 3822 * to the output list) 3823 */ 3824 while(l2) { 3825 l1 = l2; 3826 for(len1 = 0; l2 && len1 < stride; len1 ++, l2 = l2->next); 3827 len2 = stride; 3828 3829 /* 3830 * l1 points to first sublist. 3831 * l2 points to second sublist. 3832 * Merge them onto the output list 3833 */ 3834 while(len1 && l2 && len2) { 3835 if(strcmp(l1->name, l2->name) <= 0) { 3836 next = l1; 3837 l1 = l1->next; 3838 len1 --; 3839 } else { 3840 next = l2; 3841 l2 = l2->next; 3842 len2 --; 3843 } 3844 3845 if(cur) { 3846 cur->next = next; 3847 cur = next; 3848 } else 3849 dir->list = cur = next; 3850 } 3851 /* 3852 * One sublist is now empty, copy the other one onto the 3853 * output list 3854 */ 3855 for(; len1; len1 --, l1 = l1->next) { 3856 if(cur) { 3857 cur->next = l1; 3858 cur = l1; 3859 } else 3860 dir->list = cur = l1; 3861 } 3862 for(; l2 && len2; len2 --, l2 = l2->next) { 3863 if(cur) { 3864 cur->next = l2; 3865 cur = l2; 3866 } else 3867 dir->list = cur = l2; 3868 } 3869 } 3870 cur->next = NULL; 3871 stride = stride << 1; 3872 } while(stride < dir->count); 3873 } 3874 3875 3876 void dir_scan6(struct dir_info *dir) 3877 { 3878 struct dir_ent *dir_ent; 3879 unsigned int byte_count = 0; 3880 3881 sort_directory(dir); 3882 3883 for(dir_ent = dir->list; dir_ent; dir_ent = dir_ent->next) { 3884 byte_count += strlen(dir_ent->name) + 3885 sizeof(struct squashfs_dir_entry); 3886 3887 if(dir_ent->inode->root_entry) 3888 continue; 3889 3890 alloc_inode_no(dir_ent->inode, 0); 3891 3892 if((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) 3893 dir_scan6(dir_ent->dir); 3894 } 3895 3896 if((dir->count < 257 && byte_count < SQUASHFS_METADATA_SIZE)) 3897 dir->dir_is_ldir = FALSE; 3898 } 3899 3900 3901 /* 3902 * dir_scan6 routines... 3903 * This generates the filesystem metadata and writes it out to the destination 3904 */ 3905 void scan7_init_dir(struct directory *dir) 3906 { 3907 dir->buff = malloc(SQUASHFS_METADATA_SIZE); 3908 if(dir->buff == NULL) 3909 MEM_ERROR(); 3910 3911 dir->size = SQUASHFS_METADATA_SIZE; 3912 dir->p = dir->index_count_p = dir->buff; 3913 dir->entry_count = 256; 3914 dir->entry_count_p = NULL; 3915 dir->index = NULL; 3916 dir->i_count = dir->i_size = 0; 3917 } 3918 3919 3920 struct dir_ent *scan7_readdir(struct directory *dir, struct dir_info *dir_info, 3921 struct dir_ent *dir_ent) 3922 { 3923 if (dir_ent == NULL) 3924 dir_ent = dir_info->list; 3925 else 3926 dir_ent = dir_ent->next; 3927 3928 for(; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next) 3929 add_dir(dir_ent->inode->inode, dir_ent->inode->inode_number, 3930 dir_ent->name, dir_ent->inode->type, dir); 3931 3932 return dir_ent; 3933 } 3934 3935 3936 void scan7_freedir(struct directory *dir) 3937 { 3938 if(dir->index) 3939 free(dir->index); 3940 free(dir->buff); 3941 } 3942 3943 3944 void dir_scan7(squashfs_inode *inode, struct dir_info *dir_info) 3945 { 3946 int squashfs_type; 3947 int duplicate_file; 3948 struct directory dir; 3949 struct dir_ent *dir_ent = NULL; 3950 3951 scan7_init_dir(&dir); 3952 3953 while((dir_ent = scan7_readdir(&dir, dir_info, dir_ent)) != NULL) { 3954 struct stat *buf = &dir_ent->inode->buf; 3955 3956 update_info(dir_ent); 3957 3958 if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) { 3959 switch(buf->st_mode & S_IFMT) { 3960 case S_IFREG: 3961 squashfs_type = SQUASHFS_FILE_TYPE; 3962 write_file(inode, dir_ent, 3963 &duplicate_file); 3964 INFO("file %s, uncompressed size %lld " 3965 "bytes %s\n", 3966 subpathname(dir_ent), 3967 (long long) buf->st_size, 3968 duplicate_file ? "DUPLICATE" : 3969 ""); 3970 break; 3971 3972 case S_IFDIR: 3973 squashfs_type = SQUASHFS_DIR_TYPE; 3974 dir_scan7(inode, dir_ent->dir); 3975 break; 3976 3977 case S_IFLNK: 3978 squashfs_type = SQUASHFS_SYMLINK_TYPE; 3979 create_inode(inode, NULL, dir_ent, 3980 squashfs_type, 0, 0, 0, NULL, 3981 NULL, NULL, 0); 3982 INFO("symbolic link %s inode 0x%llx\n", 3983 subpathname(dir_ent), *inode); 3984 sym_count ++; 3985 break; 3986 3987 case S_IFCHR: 3988 squashfs_type = SQUASHFS_CHRDEV_TYPE; 3989 create_inode(inode, NULL, dir_ent, 3990 squashfs_type, 0, 0, 0, NULL, 3991 NULL, NULL, 0); 3992 INFO("character device %s inode 0x%llx" 3993 "\n", subpathname(dir_ent), 3994 *inode); 3995 dev_count ++; 3996 break; 3997 3998 case S_IFBLK: 3999 squashfs_type = SQUASHFS_BLKDEV_TYPE; 4000 create_inode(inode, NULL, dir_ent, 4001 squashfs_type, 0, 0, 0, NULL, 4002 NULL, NULL, 0); 4003 INFO("block device %s inode 0x%llx\n", 4004 subpathname(dir_ent), *inode); 4005 dev_count ++; 4006 break; 4007 4008 case S_IFIFO: 4009 squashfs_type = SQUASHFS_FIFO_TYPE; 4010 create_inode(inode, NULL, dir_ent, 4011 squashfs_type, 0, 0, 0, NULL, 4012 NULL, NULL, 0); 4013 INFO("fifo %s inode 0x%llx\n", 4014 subpathname(dir_ent), *inode); 4015 fifo_count ++; 4016 break; 4017 4018 case S_IFSOCK: 4019 squashfs_type = SQUASHFS_SOCKET_TYPE; 4020 create_inode(inode, NULL, dir_ent, 4021 squashfs_type, 0, 0, 0, NULL, 4022 NULL, NULL, 0); 4023 INFO("unix domain socket %s inode " 4024 "0x%llx\n", 4025 subpathname(dir_ent), *inode); 4026 sock_count ++; 4027 break; 4028 4029 default: 4030 BAD_ERROR("%s unrecognised file type, " 4031 "mode is %x\n", 4032 subpathname(dir_ent), 4033 buf->st_mode); 4034 } 4035 dir_ent->inode->inode = *inode; 4036 dir_ent->inode->type = squashfs_type; 4037 } else { 4038 *inode = dir_ent->inode->inode; 4039 squashfs_type = dir_ent->inode->type; 4040 switch(squashfs_type) { 4041 case SQUASHFS_FILE_TYPE: 4042 if(!sorted) 4043 INFO("file %s, uncompressed " 4044 "size %lld bytes LINK" 4045 "\n", 4046 subpathname(dir_ent), 4047 (long long) 4048 buf->st_size); 4049 break; 4050 case SQUASHFS_SYMLINK_TYPE: 4051 INFO("symbolic link %s inode 0x%llx " 4052 "LINK\n", subpathname(dir_ent), 4053 *inode); 4054 break; 4055 case SQUASHFS_CHRDEV_TYPE: 4056 INFO("character device %s inode 0x%llx " 4057 "LINK\n", subpathname(dir_ent), 4058 *inode); 4059 break; 4060 case SQUASHFS_BLKDEV_TYPE: 4061 INFO("block device %s inode 0x%llx " 4062 "LINK\n", subpathname(dir_ent), 4063 *inode); 4064 break; 4065 case SQUASHFS_FIFO_TYPE: 4066 INFO("fifo %s inode 0x%llx LINK\n", 4067 subpathname(dir_ent), *inode); 4068 break; 4069 case SQUASHFS_SOCKET_TYPE: 4070 INFO("unix domain socket %s inode " 4071 "0x%llx LINK\n", 4072 subpathname(dir_ent), *inode); 4073 break; 4074 } 4075 } 4076 4077 add_dir(*inode, get_inode_no(dir_ent->inode), dir_ent->name, 4078 squashfs_type, &dir); 4079 } 4080 4081 write_dir(inode, dir_info, &dir); 4082 INFO("directory %s inode 0x%llx\n", subpathname(dir_info->dir_ent), 4083 *inode); 4084 4085 scan7_freedir(&dir); 4086 } 4087 4088 4089 unsigned int slog(unsigned int block) 4090 { 4091 int i; 4092 4093 for(i = 12; i <= 20; i++) 4094 if(block == (1 << i)) 4095 return i; 4096 return 0; 4097 } 4098 4099 4100 int old_excluded(char *filename, struct stat *buf) 4101 { 4102 int i; 4103 4104 for(i = 0; i < exclude; i++) 4105 if((exclude_paths[i].st_dev == buf->st_dev) && 4106 (exclude_paths[i].st_ino == buf->st_ino)) 4107 return TRUE; 4108 return FALSE; 4109 } 4110 4111 4112 #define ADD_ENTRY(buf) \ 4113 if(exclude % EXCLUDE_SIZE == 0) { \ 4114 exclude_paths = realloc(exclude_paths, (exclude + EXCLUDE_SIZE) \ 4115 * sizeof(struct exclude_info)); \ 4116 if(exclude_paths == NULL) \ 4117 MEM_ERROR(); \ 4118 } \ 4119 exclude_paths[exclude].st_dev = buf.st_dev; \ 4120 exclude_paths[exclude++].st_ino = buf.st_ino; 4121 int old_add_exclude(char *path) 4122 { 4123 int i; 4124 char *filename; 4125 struct stat buf; 4126 4127 if(path[0] == '/' || strncmp(path, "./", 2) == 0 || 4128 strncmp(path, "../", 3) == 0) { 4129 if(lstat(path, &buf) == -1) { 4130 ERROR_START("Cannot stat exclude dir/file %s because " 4131 "%s", path, strerror(errno)); 4132 ERROR_EXIT(", ignoring\n"); 4133 return TRUE; 4134 } 4135 ADD_ENTRY(buf); 4136 return TRUE; 4137 } 4138 4139 for(i = 0; i < source; i++) { 4140 int res = asprintf(&filename, "%s/%s", source_path[i], path); 4141 if(res == -1) 4142 BAD_ERROR("asprintf failed in old_add_exclude\n"); 4143 if(lstat(filename, &buf) == -1) { 4144 if(!(errno == ENOENT || errno == ENOTDIR)) { 4145 ERROR_START("Cannot stat exclude dir/file %s " 4146 "because %s", filename, strerror(errno)); 4147 ERROR_EXIT(", ignoring\n"); 4148 } 4149 free(filename); 4150 continue; 4151 } 4152 free(filename); 4153 ADD_ENTRY(buf); 4154 } 4155 return TRUE; 4156 } 4157 4158 4159 void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, 4160 int type) 4161 { 4162 old_root_entry = realloc(old_root_entry, 4163 sizeof(struct old_root_entry_info) * (old_root_entries + 1)); 4164 if(old_root_entry == NULL) 4165 MEM_ERROR(); 4166 4167 old_root_entry[old_root_entries].name = strdup(name); 4168 old_root_entry[old_root_entries].inode.inode = inode; 4169 old_root_entry[old_root_entries].inode.inode_number = inode_number; 4170 old_root_entry[old_root_entries].inode.type = type; 4171 old_root_entry[old_root_entries++].inode.root_entry = TRUE; 4172 } 4173 4174 4175 void initialise_threads(int readq, int fragq, int bwriteq, int fwriteq, 4176 int freelst, char *destination_file) 4177 { 4178 int i; 4179 sigset_t sigmask, old_mask; 4180 int total_mem = readq; 4181 int reader_size; 4182 int fragment_size; 4183 int fwriter_size; 4184 /* 4185 * bwriter_size is global because it is needed in 4186 * write_file_blocks_dup() 4187 */ 4188 4189 /* 4190 * Never allow the total size of the queues to be larger than 4191 * physical memory 4192 * 4193 * When adding together the possibly user supplied values, make 4194 * sure they've not been deliberately contrived to overflow an int 4195 */ 4196 if(add_overflow(total_mem, fragq)) 4197 BAD_ERROR("Queue sizes rediculously too large\n"); 4198 total_mem += fragq; 4199 if(add_overflow(total_mem, bwriteq)) 4200 BAD_ERROR("Queue sizes rediculously too large\n"); 4201 total_mem += bwriteq; 4202 if(add_overflow(total_mem, fwriteq)) 4203 BAD_ERROR("Queue sizes rediculously too large\n"); 4204 total_mem += fwriteq; 4205 4206 check_usable_phys_mem(total_mem); 4207 4208 /* 4209 * convert from queue size in Mbytes to queue size in 4210 * blocks. 4211 * 4212 * This isn't going to overflow an int unless there exists 4213 * systems with more than 8 Petabytes of RAM! 4214 */ 4215 reader_size = readq << (20 - block_log); 4216 fragment_size = fragq << (20 - block_log); 4217 bwriter_size = bwriteq << (20 - block_log); 4218 fwriter_size = fwriteq << (20 - block_log); 4219 4220 /* 4221 * setup signal handlers for the main thread, these cleanup 4222 * deleting the destination file, if appending the 4223 * handlers for SIGTERM and SIGINT will be replaced with handlers 4224 * allowing the user to press ^C twice to restore the existing 4225 * filesystem. 4226 * 4227 * SIGUSR1 is an internal signal, which is used by the sub-threads 4228 * to tell the main thread to terminate, deleting the destination file, 4229 * or if necessary restoring the filesystem on appending 4230 */ 4231 signal(SIGTERM, sighandler); 4232 signal(SIGINT, sighandler); 4233 signal(SIGUSR1, sighandler); 4234 4235 /* block SIGQUIT and SIGHUP, these are handled by the info thread */ 4236 sigemptyset(&sigmask); 4237 sigaddset(&sigmask, SIGQUIT); 4238 sigaddset(&sigmask, SIGHUP); 4239 if(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1) 4240 BAD_ERROR("Failed to set signal mask in intialise_threads\n"); 4241 4242 /* 4243 * temporarily block these signals, so the created sub-threads 4244 * will ignore them, ensuring the main thread handles them 4245 */ 4246 sigemptyset(&sigmask); 4247 sigaddset(&sigmask, SIGINT); 4248 sigaddset(&sigmask, SIGTERM); 4249 sigaddset(&sigmask, SIGUSR1); 4250 if(pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1) 4251 BAD_ERROR("Failed to set signal mask in intialise_threads\n"); 4252 4253 if(processors == -1) { 4254 #ifndef linux 4255 int mib[2]; 4256 size_t len = sizeof(processors); 4257 4258 mib[0] = CTL_HW; 4259 #ifdef HW_AVAILCPU 4260 mib[1] = HW_AVAILCPU; 4261 #else 4262 mib[1] = HW_NCPU; 4263 #endif 4264 4265 if(sysctl(mib, 2, &processors, &len, NULL, 0) == -1) { 4266 ERROR_START("Failed to get number of available " 4267 "processors."); 4268 ERROR_EXIT(" Defaulting to 1\n"); 4269 processors = 1; 4270 } 4271 #else 4272 processors = sysconf(_SC_NPROCESSORS_ONLN); 4273 #endif 4274 } 4275 4276 if(multiply_overflow(processors, 3) || 4277 multiply_overflow(processors * 3, sizeof(pthread_t))) 4278 BAD_ERROR("Processors too large\n"); 4279 4280 deflator_thread = malloc(processors * 3 * sizeof(pthread_t)); 4281 if(deflator_thread == NULL) 4282 MEM_ERROR(); 4283 4284 frag_deflator_thread = &deflator_thread[processors]; 4285 frag_thread = &frag_deflator_thread[processors]; 4286 4287 to_reader = queue_init(1); 4288 to_deflate = queue_init(reader_size); 4289 to_process_frag = queue_init(reader_size); 4290 to_writer = queue_init(bwriter_size + fwriter_size); 4291 from_writer = queue_init(1); 4292 to_frag = queue_init(fragment_size); 4293 locked_fragment = queue_init(fragment_size); 4294 to_main = seq_queue_init(); 4295 reader_buffer = cache_init(block_size, reader_size, 0, 0); 4296 bwriter_buffer = cache_init(block_size, bwriter_size, 1, freelst); 4297 fwriter_buffer = cache_init(block_size, fwriter_size, 1, freelst); 4298 fragment_buffer = cache_init(block_size, fragment_size, 1, 0); 4299 reserve_cache = cache_init(block_size, processors + 1, 1, 0); 4300 pthread_create(&reader_thread, NULL, reader, NULL); 4301 pthread_create(&writer_thread, NULL, writer, NULL); 4302 init_progress_bar(); 4303 init_info(); 4304 4305 for(i = 0; i < processors; i++) { 4306 if(pthread_create(&deflator_thread[i], NULL, deflator, NULL)) 4307 BAD_ERROR("Failed to create thread\n"); 4308 if(pthread_create(&frag_deflator_thread[i], NULL, frag_deflator, 4309 NULL) != 0) 4310 BAD_ERROR("Failed to create thread\n"); 4311 if(pthread_create(&frag_thread[i], NULL, frag_thrd, 4312 (void *) destination_file) != 0) 4313 BAD_ERROR("Failed to create thread\n"); 4314 } 4315 4316 main_thread = pthread_self(); 4317 4318 printf("Parallel mksquashfs: Using %d processor%s\n", processors, 4319 processors == 1 ? "" : "s"); 4320 4321 /* Restore the signal mask for the main thread */ 4322 if(pthread_sigmask(SIG_SETMASK, &old_mask, NULL) == -1) 4323 BAD_ERROR("Failed to set signal mask in intialise_threads\n"); 4324 } 4325 4326 4327 long long write_inode_lookup_table() 4328 { 4329 int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count); 4330 void *it; 4331 4332 if(inode_count == sinode_count) 4333 goto skip_inode_hash_table; 4334 4335 it = realloc(inode_lookup_table, lookup_bytes); 4336 if(it == NULL) 4337 MEM_ERROR(); 4338 inode_lookup_table = it; 4339 4340 for(i = 0; i < INODE_HASH_SIZE; i ++) { 4341 struct inode_info *inode; 4342 4343 for(inode = inode_info[i]; inode; inode = inode->next) { 4344 4345 inode_number = get_inode_no(inode); 4346 4347 /* The empty action will produce orphaned inode 4348 * entries in the inode_info[] table. These 4349 * entries because they are orphaned will not be 4350 * allocated an inode number in dir_scan5(), so 4351 * skip any entries with the default dummy inode 4352 * number of 0 */ 4353 if(inode_number == 0) 4354 continue; 4355 4356 SQUASHFS_SWAP_LONG_LONGS(&inode->inode, 4357 &inode_lookup_table[inode_number - 1], 1); 4358 4359 } 4360 } 4361 4362 skip_inode_hash_table: 4363 return generic_write_table(lookup_bytes, inode_lookup_table, 0, NULL, 4364 noI); 4365 } 4366 4367 4368 char *get_component(char *target, char **targname) 4369 { 4370 char *start; 4371 4372 while(*target == '/') 4373 target ++; 4374 4375 start = target; 4376 while(*target != '/' && *target != '\0') 4377 target ++; 4378 4379 *targname = strndup(start, target - start); 4380 4381 while(*target == '/') 4382 target ++; 4383 4384 return target; 4385 } 4386 4387 4388 void free_path(struct pathname *paths) 4389 { 4390 int i; 4391 4392 for(i = 0; i < paths->names; i++) { 4393 if(paths->name[i].paths) 4394 free_path(paths->name[i].paths); 4395 free(paths->name[i].name); 4396 if(paths->name[i].preg) { 4397 regfree(paths->name[i].preg); 4398 free(paths->name[i].preg); 4399 } 4400 } 4401 4402 free(paths); 4403 } 4404 4405 4406 struct pathname *add_path(struct pathname *paths, char *target, char *alltarget) 4407 { 4408 char *targname; 4409 int i, error; 4410 4411 target = get_component(target, &targname); 4412 4413 if(paths == NULL) { 4414 paths = malloc(sizeof(struct pathname)); 4415 if(paths == NULL) 4416 MEM_ERROR(); 4417 4418 paths->names = 0; 4419 paths->name = NULL; 4420 } 4421 4422 for(i = 0; i < paths->names; i++) 4423 if(strcmp(paths->name[i].name, targname) == 0) 4424 break; 4425 4426 if(i == paths->names) { 4427 /* allocate new name entry */ 4428 paths->names ++; 4429 paths->name = realloc(paths->name, (i + 1) * 4430 sizeof(struct path_entry)); 4431 if(paths->name == NULL) 4432 MEM_ERROR(); 4433 paths->name[i].name = targname; 4434 paths->name[i].paths = NULL; 4435 if(use_regex) { 4436 paths->name[i].preg = malloc(sizeof(regex_t)); 4437 if(paths->name[i].preg == NULL) 4438 MEM_ERROR(); 4439 error = regcomp(paths->name[i].preg, targname, 4440 REG_EXTENDED|REG_NOSUB); 4441 if(error) { 4442 char str[1024]; /* overflow safe */ 4443 4444 regerror(error, paths->name[i].preg, str, 1024); 4445 BAD_ERROR("invalid regex %s in export %s, " 4446 "because %s\n", targname, alltarget, 4447 str); 4448 } 4449 } else 4450 paths->name[i].preg = NULL; 4451 4452 if(target[0] == '\0') 4453 /* at leaf pathname component */ 4454 paths->name[i].paths = NULL; 4455 else 4456 /* recurse adding child components */ 4457 paths->name[i].paths = add_path(NULL, target, 4458 alltarget); 4459 } else { 4460 /* existing matching entry */ 4461 free(targname); 4462 4463 if(paths->name[i].paths == NULL) { 4464 /* No sub-directory which means this is the leaf 4465 * component of a pre-existing exclude which subsumes 4466 * the exclude currently being added, in which case stop 4467 * adding components */ 4468 } else if(target[0] == '\0') { 4469 /* at leaf pathname component and child components exist 4470 * from more specific excludes, delete as they're 4471 * subsumed by this exclude */ 4472 free_path(paths->name[i].paths); 4473 paths->name[i].paths = NULL; 4474 } else 4475 /* recurse adding child components */ 4476 add_path(paths->name[i].paths, target, alltarget); 4477 } 4478 4479 return paths; 4480 } 4481 4482 4483 void add_exclude(char *target) 4484 { 4485 4486 if(target[0] == '/' || strncmp(target, "./", 2) == 0 || 4487 strncmp(target, "../", 3) == 0) 4488 BAD_ERROR("/, ./ and ../ prefixed excludes not supported with " 4489 "-wildcards or -regex options\n"); 4490 else if(strncmp(target, "... ", 4) == 0) 4491 stickypath = add_path(stickypath, target + 4, target + 4); 4492 else 4493 path = add_path(path, target, target); 4494 } 4495 4496 4497 void display_path(int depth, struct pathname *paths) 4498 { 4499 int i, n; 4500 4501 if(paths == NULL) 4502 return; 4503 4504 for(i = 0; i < paths->names; i++) { 4505 for(n = 0; n < depth; n++) 4506 printf("\t"); 4507 printf("%d: %s\n", depth, paths->name[i].name); 4508 display_path(depth + 1, paths->name[i].paths); 4509 } 4510 } 4511 4512 4513 void display_path2(struct pathname *paths, char *string) 4514 { 4515 int i; 4516 char *path; 4517 4518 if(paths == NULL) { 4519 printf("%s\n", string); 4520 return; 4521 } 4522 4523 for(i = 0; i < paths->names; i++) { 4524 int res = asprintf(&path, "%s/%s", string, paths->name[i].name); 4525 if(res == -1) 4526 BAD_ERROR("asprintf failed in display_path2\n"); 4527 display_path2(paths->name[i].paths, path); 4528 free(path); 4529 } 4530 } 4531 4532 4533 struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path) 4534 { 4535 int count = paths == NULL ? 0 : paths->count; 4536 4537 if(count % PATHS_ALLOC_SIZE == 0) { 4538 paths = realloc(paths, sizeof(struct pathnames) + 4539 (count + PATHS_ALLOC_SIZE) * sizeof(struct pathname *)); 4540 if(paths == NULL) 4541 MEM_ERROR(); 4542 } 4543 4544 paths->path[count] = path; 4545 paths->count = count + 1; 4546 return paths; 4547 } 4548 4549 4550 int excluded_match(char *name, struct pathname *path, struct pathnames **new) 4551 { 4552 int i; 4553 4554 for(i = 0; i < path->names; i++) { 4555 int match = use_regex ? 4556 regexec(path->name[i].preg, name, (size_t) 0, 4557 NULL, 0) == 0 : 4558 fnmatch(path->name[i].name, name, 4559 FNM_PATHNAME|FNM_PERIOD|FNM_EXTMATCH) == 0; 4560 4561 if(match) { 4562 if(path->name[i].paths == NULL || new == NULL) 4563 /* match on a leaf component, any subdirectories 4564 * in the filesystem should be excluded */ 4565 return TRUE; 4566 else 4567 /* match on a non-leaf component, add any 4568 * subdirectories to the new set of 4569 * subdirectories to scan for this name */ 4570 *new = add_subdir(*new, path->name[i].paths); 4571 } 4572 } 4573 4574 return FALSE; 4575 } 4576 4577 4578 int excluded(char *name, struct pathnames *paths, struct pathnames **new) 4579 { 4580 int n; 4581 4582 if(stickypath && excluded_match(name, stickypath, NULL)) 4583 return TRUE; 4584 4585 for(n = 0; paths && n < paths->count; n++) { 4586 int res = excluded_match(name, paths->path[n], new); 4587 if(res) { 4588 free(*new); 4589 *new = NULL; 4590 return TRUE; 4591 } 4592 } 4593 4594 /* 4595 * Either: 4596 * - no matching names found, return empty new search set, or 4597 * - one or more matches with sub-directories found (no leaf matches), 4598 * in which case return new search set. 4599 * 4600 * In either case return FALSE as we don't want to exclude this entry 4601 */ 4602 return FALSE; 4603 } 4604 4605 4606 void process_exclude_file(char *argv) 4607 { 4608 FILE *fd; 4609 char buffer[MAX_LINE + 1]; /* overflow safe */ 4610 char *filename; 4611 4612 fd = fopen(argv, "r"); 4613 if(fd == NULL) 4614 BAD_ERROR("Failed to open exclude file \"%s\" because %s\n", 4615 argv, strerror(errno)); 4616 4617 while(fgets(filename = buffer, MAX_LINE + 1, fd) != NULL) { 4618 int len = strlen(filename); 4619 4620 if(len == MAX_LINE && filename[len - 1] != '\n') 4621 /* line too large */ 4622 BAD_ERROR("Line too long when reading " 4623 "exclude file \"%s\", larger than %d " 4624 "bytes\n", argv, MAX_LINE); 4625 4626 /* 4627 * Remove '\n' terminator if it exists (the last line 4628 * in the file may not be '\n' terminated) 4629 */ 4630 if(len && filename[len - 1] == '\n') 4631 filename[len - 1] = '\0'; 4632 4633 /* Skip any leading whitespace */ 4634 while(isspace(*filename)) 4635 filename ++; 4636 4637 /* if comment line, skip */ 4638 if(*filename == '#') 4639 continue; 4640 4641 /* 4642 * check for initial backslash, to accommodate 4643 * filenames with leading space or leading # character 4644 */ 4645 if(*filename == '\\') 4646 filename ++; 4647 4648 /* if line is now empty after skipping characters, skip it */ 4649 if(*filename == '\0') 4650 continue; 4651 4652 if(old_exclude) 4653 old_add_exclude(filename); 4654 else 4655 add_exclude(filename); 4656 } 4657 4658 if(ferror(fd)) 4659 BAD_ERROR("Reading exclude file \"%s\" failed because %s\n", 4660 argv, strerror(errno)); 4661 4662 fclose(fd); 4663 } 4664 4665 4666 #define RECOVER_ID "Squashfs recovery file v1.0\n" 4667 #define RECOVER_ID_SIZE 28 4668 4669 void write_recovery_data(struct squashfs_super_block *sBlk) 4670 { 4671 int res, recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start; 4672 pid_t pid = getpid(); 4673 char *metadata; 4674 char header[] = RECOVER_ID; 4675 4676 if(recover == FALSE) { 4677 printf("No recovery data option specified.\n"); 4678 printf("Skipping saving recovery file.\n\n"); 4679 return; 4680 } 4681 4682 metadata = malloc(bytes); 4683 if(metadata == NULL) 4684 MEM_ERROR(); 4685 4686 res = read_fs_bytes(fd, sBlk->inode_table_start, bytes, metadata); 4687 if(res == 0) { 4688 ERROR("Failed to read append filesystem metadata\n"); 4689 BAD_ERROR("Filesystem corrupted?\n"); 4690 } 4691 4692 res = asprintf(&recovery_file, "squashfs_recovery_%s_%d", 4693 getbase(destination_file), pid); 4694 if(res == -1) 4695 MEM_ERROR(); 4696 4697 recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU); 4698 if(recoverfd == -1) 4699 BAD_ERROR("Failed to create recovery file, because %s. " 4700 "Aborting\n", strerror(errno)); 4701 4702 if(write_bytes(recoverfd, header, RECOVER_ID_SIZE) == -1) 4703 BAD_ERROR("Failed to write recovery file, because %s\n", 4704 strerror(errno)); 4705 4706 if(write_bytes(recoverfd, sBlk, sizeof(struct squashfs_super_block)) == -1) 4707 BAD_ERROR("Failed to write recovery file, because %s\n", 4708 strerror(errno)); 4709 4710 if(write_bytes(recoverfd, metadata, bytes) == -1) 4711 BAD_ERROR("Failed to write recovery file, because %s\n", 4712 strerror(errno)); 4713 4714 close(recoverfd); 4715 free(metadata); 4716 4717 printf("Recovery file \"%s\" written\n", recovery_file); 4718 printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n"); 4719 printf("mksquashfs dummy %s -recover %s\n", destination_file, 4720 recovery_file); 4721 printf("to restore filesystem\n\n"); 4722 } 4723 4724 4725 void read_recovery_data(char *recovery_file, char *destination_file) 4726 { 4727 int fd, recoverfd, bytes; 4728 struct squashfs_super_block orig_sBlk, sBlk; 4729 char *metadata; 4730 int res; 4731 struct stat buf; 4732 char header[] = RECOVER_ID; 4733 char header2[RECOVER_ID_SIZE]; 4734 4735 recoverfd = open(recovery_file, O_RDONLY); 4736 if(recoverfd == -1) 4737 BAD_ERROR("Failed to open recovery file because %s\n", 4738 strerror(errno)); 4739 4740 if(stat(destination_file, &buf) == -1) 4741 BAD_ERROR("Failed to stat destination file, because %s\n", 4742 strerror(errno)); 4743 4744 fd = open(destination_file, O_RDWR); 4745 if(fd == -1) 4746 BAD_ERROR("Failed to open destination file because %s\n", 4747 strerror(errno)); 4748 4749 res = read_bytes(recoverfd, header2, RECOVER_ID_SIZE); 4750 if(res == -1) 4751 BAD_ERROR("Failed to read recovery file, because %s\n", 4752 strerror(errno)); 4753 if(res < RECOVER_ID_SIZE) 4754 BAD_ERROR("Recovery file appears to be truncated\n"); 4755 if(strncmp(header, header2, RECOVER_ID_SIZE) !=0 ) 4756 BAD_ERROR("Not a recovery file\n"); 4757 4758 res = read_bytes(recoverfd, &sBlk, sizeof(struct squashfs_super_block)); 4759 if(res == -1) 4760 BAD_ERROR("Failed to read recovery file, because %s\n", 4761 strerror(errno)); 4762 if(res < sizeof(struct squashfs_super_block)) 4763 BAD_ERROR("Recovery file appears to be truncated\n"); 4764 4765 res = read_fs_bytes(fd, 0, sizeof(struct squashfs_super_block), &orig_sBlk); 4766 if(res == 0) { 4767 ERROR("Failed to read superblock from output filesystem\n"); 4768 BAD_ERROR("Output filesystem is empty!\n"); 4769 } 4770 4771 if(memcmp(((char *) &sBlk) + 4, ((char *) &orig_sBlk) + 4, 4772 sizeof(struct squashfs_super_block) - 4) != 0) 4773 BAD_ERROR("Recovery file and destination file do not seem to " 4774 "match\n"); 4775 4776 bytes = sBlk.bytes_used - sBlk.inode_table_start; 4777 4778 metadata = malloc(bytes); 4779 if(metadata == NULL) 4780 MEM_ERROR(); 4781 4782 res = read_bytes(recoverfd, metadata, bytes); 4783 if(res == -1) 4784 BAD_ERROR("Failed to read recovery file, because %s\n", 4785 strerror(errno)); 4786 if(res < bytes) 4787 BAD_ERROR("Recovery file appears to be truncated\n"); 4788 4789 write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk); 4790 4791 write_destination(fd, sBlk.inode_table_start, bytes, metadata); 4792 4793 close(recoverfd); 4794 close(fd); 4795 4796 printf("Successfully wrote recovery file \"%s\". Exiting\n", 4797 recovery_file); 4798 4799 exit(0); 4800 } 4801 4802 4803 void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad) 4804 { 4805 int i; 4806 4807 sBlk->fragments = fragments; 4808 sBlk->no_ids = id_count; 4809 sBlk->inode_table_start = write_inodes(); 4810 sBlk->directory_table_start = write_directories(); 4811 sBlk->fragment_table_start = write_fragment_table(); 4812 sBlk->lookup_table_start = exportable ? write_inode_lookup_table() : 4813 SQUASHFS_INVALID_BLK; 4814 sBlk->id_table_start = write_id_table(); 4815 sBlk->xattr_id_table_start = write_xattrs(); 4816 4817 TRACE("sBlk->inode_table_start 0x%llx\n", sBlk->inode_table_start); 4818 TRACE("sBlk->directory_table_start 0x%llx\n", 4819 sBlk->directory_table_start); 4820 TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk->fragment_table_start); 4821 if(exportable) 4822 TRACE("sBlk->lookup_table_start 0x%llx\n", 4823 sBlk->lookup_table_start); 4824 4825 sBlk->bytes_used = bytes; 4826 4827 sBlk->compression = comp->id; 4828 4829 SQUASHFS_INSWAP_SUPER_BLOCK(sBlk); 4830 write_destination(fd, SQUASHFS_START, sizeof(*sBlk), sBlk); 4831 4832 if(!nopad && (i = bytes & (4096 - 1))) { 4833 char temp[4096] = {0}; 4834 write_destination(fd, bytes, 4096 - i, temp); 4835 } 4836 4837 close(fd); 4838 4839 if(recovery_file) 4840 unlink(recovery_file); 4841 4842 total_bytes += total_inode_bytes + total_directory_bytes + 4843 sizeof(struct squashfs_super_block) + total_xattr_bytes; 4844 4845 printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size" 4846 " %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR, 4847 SQUASHFS_MINOR, comp->name, block_size); 4848 printf("\t%s data, %s metadata, %s fragments, %s xattrs\n", 4849 noD ? "uncompressed" : "compressed", noI ? "uncompressed" : 4850 "compressed", no_fragments ? "no" : noF ? "uncompressed" : 4851 "compressed", no_xattrs ? "no" : noX ? "uncompressed" : 4852 "compressed"); 4853 printf("\tduplicates are %sremoved\n", duplicate_checking ? "" : 4854 "not "); 4855 printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0, 4856 bytes / (1024.0 * 1024.0)); 4857 printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n", 4858 ((float) bytes / total_bytes) * 100.0, total_bytes / 1024.0); 4859 printf("Inode table size %d bytes (%.2f Kbytes)\n", 4860 inode_bytes, inode_bytes / 1024.0); 4861 printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n", 4862 ((float) inode_bytes / total_inode_bytes) * 100.0, 4863 total_inode_bytes); 4864 printf("Directory table size %d bytes (%.2f Kbytes)\n", 4865 directory_bytes, directory_bytes / 1024.0); 4866 printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n", 4867 ((float) directory_bytes / total_directory_bytes) * 100.0, 4868 total_directory_bytes); 4869 if(total_xattr_bytes) { 4870 printf("Xattr table size %d bytes (%.2f Kbytes)\n", 4871 xattr_bytes, xattr_bytes / 1024.0); 4872 printf("\t%.2f%% of uncompressed xattr table size (%d bytes)\n", 4873 ((float) xattr_bytes / total_xattr_bytes) * 100.0, 4874 total_xattr_bytes); 4875 } 4876 if(duplicate_checking) 4877 printf("Number of duplicate files found %d\n", file_count - 4878 dup_files); 4879 else 4880 printf("No duplicate files removed\n"); 4881 printf("Number of inodes %d\n", inode_count); 4882 printf("Number of files %d\n", file_count); 4883 if(!no_fragments) 4884 printf("Number of fragments %d\n", fragments); 4885 printf("Number of symbolic links %d\n", sym_count); 4886 printf("Number of device nodes %d\n", dev_count); 4887 printf("Number of fifo nodes %d\n", fifo_count); 4888 printf("Number of socket nodes %d\n", sock_count); 4889 printf("Number of directories %d\n", dir_count); 4890 printf("Number of ids (unique uids + gids) %d\n", id_count); 4891 printf("Number of uids %d\n", uid_count); 4892 4893 for(i = 0; i < id_count; i++) { 4894 if(id_table[i]->flags & ISA_UID) { 4895 struct passwd *user = getpwuid(id_table[i]->id); 4896 printf("\t%s (%d)\n", user == NULL ? "unknown" : 4897 user->pw_name, id_table[i]->id); 4898 } 4899 } 4900 4901 printf("Number of gids %d\n", guid_count); 4902 4903 for(i = 0; i < id_count; i++) { 4904 if(id_table[i]->flags & ISA_GID) { 4905 struct group *group = getgrgid(id_table[i]->id); 4906 printf("\t%s (%d)\n", group == NULL ? "unknown" : 4907 group->gr_name, id_table[i]->id); 4908 } 4909 } 4910 } 4911 4912 4913 int parse_numberll(char *start, long long *res, int size) 4914 { 4915 char *end; 4916 long long number; 4917 4918 errno = 0; /* To distinguish success/failure after call */ 4919 4920 number = strtoll(start, &end, 10); 4921 4922 /* 4923 * check for strtoll underflow or overflow in conversion, and other 4924 * errors. 4925 */ 4926 if((errno == ERANGE && (number == LLONG_MIN || number == LLONG_MAX)) || 4927 (errno != 0 && number == 0)) 4928 return 0; 4929 4930 /* reject negative numbers as invalid */ 4931 if(number < 0) 4932 return 0; 4933 4934 if(size) { 4935 /* 4936 * Check for multiplier and trailing junk. 4937 * But first check that a number exists before the 4938 * multiplier 4939 */ 4940 if(end == start) 4941 return 0; 4942 4943 switch(end[0]) { 4944 case 'g': 4945 case 'G': 4946 if(multiply_overflowll(number, 1073741824)) 4947 return 0; 4948 number *= 1073741824; 4949 4950 if(end[1] != '\0') 4951 /* trailing junk after multiplier, but 4952 * allow it to be "bytes" */ 4953 if(strcmp(end + 1, "bytes")) 4954 return 0; 4955 4956 break; 4957 case 'm': 4958 case 'M': 4959 if(multiply_overflowll(number, 1048576)) 4960 return 0; 4961 number *= 1048576; 4962 4963 if(end[1] != '\0') 4964 /* trailing junk after multiplier, but 4965 * allow it to be "bytes" */ 4966 if(strcmp(end + 1, "bytes")) 4967 return 0; 4968 4969 break; 4970 case 'k': 4971 case 'K': 4972 if(multiply_overflowll(number, 1024)) 4973 return 0; 4974 number *= 1024; 4975 4976 if(end[1] != '\0') 4977 /* trailing junk after multiplier, but 4978 * allow it to be "bytes" */ 4979 if(strcmp(end + 1, "bytes")) 4980 return 0; 4981 4982 break; 4983 case '\0': 4984 break; 4985 default: 4986 /* trailing junk after number */ 4987 return 0; 4988 } 4989 } else if(end[0] != '\0') 4990 /* trailing junk after number */ 4991 return 0; 4992 4993 *res = number; 4994 return 1; 4995 } 4996 4997 4998 int parse_number(char *start, int *res, int size) 4999 { 5000 long long number; 5001 5002 if(!parse_numberll(start, &number, size)) 5003 return 0; 5004 5005 /* check if long result will overflow signed int */ 5006 if(number > INT_MAX) 5007 return 0; 5008 5009 *res = (int) number; 5010 return 1; 5011 } 5012 5013 5014 int parse_num(char *arg, int *res) 5015 { 5016 return parse_number(arg, res, 0); 5017 } 5018 5019 5020 int get_physical_memory() 5021 { 5022 /* 5023 * Long longs are used here because with PAE, a 32-bit 5024 * machine can have more than 4GB of physical memory 5025 * 5026 * sysconf(_SC_PHYS_PAGES) relies on /proc being mounted. 5027 * If it isn't fail. 5028 */ 5029 long long num_pages = sysconf(_SC_PHYS_PAGES); 5030 long long page_size = sysconf(_SC_PAGESIZE); 5031 int phys_mem = num_pages * page_size >> 20; 5032 5033 if(num_pages == -1 || page_size == -1) 5034 return 0; 5035 5036 if(phys_mem < SQUASHFS_LOWMEM) 5037 BAD_ERROR("Mksquashfs requires more physical memory than is " 5038 "available!\n"); 5039 5040 return phys_mem; 5041 } 5042 5043 5044 void check_usable_phys_mem(int total_mem) 5045 { 5046 /* 5047 * We want to allow users to use as much of their physical 5048 * memory as they wish. However, for practical reasons there are 5049 * limits which need to be imposed, to protect users from themselves 5050 * and to prevent people from using Mksquashfs as a DOS attack by using 5051 * all physical memory. Mksquashfs uses memory to cache data from disk 5052 * to optimise performance. It is pointless to ask it to use more 5053 * than 75% of physical memory, as this causes thrashing and it is thus 5054 * self-defeating. 5055 */ 5056 int mem = get_physical_memory(); 5057 5058 mem = (mem >> 1) + (mem >> 2); /* 75% */ 5059 5060 if(total_mem > mem && mem) { 5061 ERROR("Total memory requested is more than 75%% of physical " 5062 "memory.\n"); 5063 ERROR("Mksquashfs uses memory to cache data from disk to " 5064 "optimise performance.\n"); 5065 ERROR("It is pointless to ask it to use more than this amount " 5066 "of memory, as this\n"); 5067 ERROR("causes thrashing and it is thus self-defeating.\n"); 5068 BAD_ERROR("Requested memory size too large\n"); 5069 } 5070 5071 if(sizeof(void *) == 4 && total_mem > 2048) { 5072 /* 5073 * If we're running on a kernel with PAE or on a 64-bit kernel, 5074 * then the 75% physical memory limit can still easily exceed 5075 * the addressable memory by this process. 5076 * 5077 * Due to the typical kernel/user-space split (1GB/3GB, or 5078 * 2GB/2GB), we have to conservatively assume the 32-bit 5079 * processes can only address 2-3GB. So refuse if the user 5080 * tries to allocate more than 2GB. 5081 */ 5082 ERROR("Total memory requested may exceed maximum " 5083 "addressable memory by this process\n"); 5084 BAD_ERROR("Requested memory size too large\n"); 5085 } 5086 } 5087 5088 5089 int get_default_phys_mem() 5090 { 5091 /* 5092 * get_physical_memory() relies on /proc being mounted. 5093 * If it fails, issue a warning, and use 5094 * SQUASHFS_LOWMEM / SQUASHFS_TAKE as default, 5095 * and allow a larger value to be set with -mem. 5096 */ 5097 int mem = get_physical_memory(); 5098 5099 if(mem == 0) { 5100 mem = SQUASHFS_LOWMEM / SQUASHFS_TAKE; 5101 5102 ERROR("Warning: Cannot get size of physical memory, probably " 5103 "because /proc is missing.\n"); 5104 ERROR("Warning: Defaulting to minimal use of %d Mbytes, use " 5105 "-mem to set a better value,\n", mem); 5106 ERROR("Warning: or fix /proc.\n"); 5107 } else 5108 mem /= SQUASHFS_TAKE; 5109 5110 if(sizeof(void *) == 4 && mem > 640) { 5111 /* 5112 * If we're running on a kernel with PAE or on a 64-bit kernel, 5113 * the default memory usage can exceed the addressable 5114 * memory by this process. 5115 * Due to the typical kernel/user-space split (1GB/3GB, or 5116 * 2GB/2GB), we have to conservatively assume the 32-bit 5117 * processes can only address 2-3GB. So limit the default 5118 * usage to 640M, which gives room for other data. 5119 */ 5120 mem = 640; 5121 } 5122 5123 return mem; 5124 } 5125 5126 5127 void calculate_queue_sizes(int mem, int *readq, int *fragq, int *bwriteq, 5128 int *fwriteq) 5129 { 5130 *readq = mem / SQUASHFS_READQ_MEM; 5131 *bwriteq = mem / SQUASHFS_BWRITEQ_MEM; 5132 *fwriteq = mem / SQUASHFS_FWRITEQ_MEM; 5133 *fragq = mem - *readq - *bwriteq - *fwriteq; 5134 } 5135 5136 5137 #define VERSION() \ 5138 printf("mksquashfs version 4.3-git (2014/09/12)\n");\ 5139 printf("copyright (C) 2014 Phillip Lougher "\ 5140 "<phillip (at) squashfs.org.uk>\n\n"); \ 5141 printf("This program is free software; you can redistribute it and/or"\ 5142 "\n");\ 5143 printf("modify it under the terms of the GNU General Public License"\ 5144 "\n");\ 5145 printf("as published by the Free Software Foundation; either version "\ 5146 "2,\n");\ 5147 printf("or (at your option) any later version.\n\n");\ 5148 printf("This program is distributed in the hope that it will be "\ 5149 "useful,\n");\ 5150 printf("but WITHOUT ANY WARRANTY; without even the implied warranty "\ 5151 "of\n");\ 5152 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\ 5153 "\n");\ 5154 printf("GNU General Public License for more details.\n"); 5155 int main(int argc, char *argv[]) 5156 { 5157 struct stat buf, source_buf; 5158 int res, i; 5159 char *b, *root_name = NULL; 5160 int keep_as_directory = FALSE; 5161 squashfs_inode inode; 5162 int readq; 5163 int fragq; 5164 int bwriteq; 5165 int fwriteq; 5166 int total_mem = get_default_phys_mem(); 5167 int progress = TRUE; 5168 int force_progress = FALSE; 5169 struct file_buffer **fragment = NULL; 5170 5171 if(argc > 1 && strcmp(argv[1], "-version") == 0) { 5172 VERSION(); 5173 exit(0); 5174 } 5175 5176 block_log = slog(block_size); 5177 calculate_queue_sizes(total_mem, &readq, &fragq, &bwriteq, &fwriteq); 5178 5179 for(i = 1; i < argc && argv[i][0] != '-'; i++); 5180 if(i < 3) 5181 goto printOptions; 5182 source_path = argv + 1; 5183 source = i - 2; 5184 5185 /* 5186 * Scan the command line for -comp xxx option, this is to ensure 5187 * any -X compressor specific options are passed to the 5188 * correct compressor 5189 */ 5190 for(; i < argc; i++) { 5191 struct compressor *prev_comp = comp; 5192 5193 if(strcmp(argv[i], "-comp") == 0) { 5194 if(++i == argc) { 5195 ERROR("%s: -comp missing compression type\n", 5196 argv[0]); 5197 exit(1); 5198 } 5199 comp = lookup_compressor(argv[i]); 5200 if(!comp->supported) { 5201 ERROR("%s: Compressor \"%s\" is not supported!" 5202 "\n", argv[0], argv[i]); 5203 ERROR("%s: Compressors available:\n", argv[0]); 5204 display_compressors("", COMP_DEFAULT); 5205 exit(1); 5206 } 5207 if(prev_comp != NULL && prev_comp != comp) { 5208 ERROR("%s: -comp multiple conflicting -comp" 5209 " options specified on command line" 5210 ", previously %s, now %s\n", argv[0], 5211 prev_comp->name, comp->name); 5212 exit(1); 5213 } 5214 compressor_opt_parsed = 1; 5215 5216 } else if(strcmp(argv[i], "-e") == 0) 5217 break; 5218 else if(strcmp(argv[i], "-root-becomes") == 0 || 5219 strcmp(argv[i], "-ef") == 0 || 5220 strcmp(argv[i], "-pf") == 0 || 5221 strcmp(argv[i], "-vaf") == 0 || 5222 strcmp(argv[i], "-comp") == 0) 5223 i++; 5224 } 5225 5226 /* 5227 * if no -comp option specified lookup default compressor. Note the 5228 * Makefile ensures the default compressor has been built, and so we 5229 * don't need to to check for failure here 5230 */ 5231 if(comp == NULL) 5232 comp = lookup_compressor(COMP_DEFAULT); 5233 5234 for(i = source + 2; i < argc; i++) { 5235 if(strcmp(argv[i], "-action") == 0 || 5236 strcmp(argv[i], "-a") ==0) { 5237 if(++i == argc) { 5238 ERROR("%s: %s missing action\n", 5239 argv[0], argv[i - 1]); 5240 exit(1); 5241 } 5242 res = parse_action(argv[i], ACTION_LOG_NONE); 5243 if(res == 0) 5244 exit(1); 5245 5246 } else if(strcmp(argv[i], "-verbose-action") == 0 || 5247 strcmp(argv[i], "-va") ==0) { 5248 if(++i == argc) { 5249 ERROR("%s: %s missing action\n", 5250 argv[0], argv[i - 1]); 5251 exit(1); 5252 } 5253 res = parse_action(argv[i], ACTION_LOG_VERBOSE); 5254 if(res == 0) 5255 exit(1); 5256 5257 } else if(strcmp(argv[i], "-true-action") == 0 || 5258 strcmp(argv[i], "-ta") ==0) { 5259 if(++i == argc) { 5260 ERROR("%s: %s missing action\n", 5261 argv[0], argv[i - 1]); 5262 exit(1); 5263 } 5264 res = parse_action(argv[i], ACTION_LOG_TRUE); 5265 if(res == 0) 5266 exit(1); 5267 5268 } else if(strcmp(argv[i], "-false-action") == 0 || 5269 strcmp(argv[i], "-fa") ==0) { 5270 if(++i == argc) { 5271 ERROR("%s: %s missing action\n", 5272 argv[0], argv[i - 1]); 5273 exit(1); 5274 } 5275 res = parse_action(argv[i], ACTION_LOG_FALSE); 5276 if(res == 0) 5277 exit(1); 5278 5279 } else if(strcmp(argv[i], "-action-file") == 0 || 5280 strcmp(argv[i], "-af") ==0) { 5281 if(++i == argc) { 5282 ERROR("%s: %s missing filename\n", argv[0], 5283 argv[i - 1]); 5284 exit(1); 5285 } 5286 if(read_action_file(argv[i], ACTION_LOG_NONE) == FALSE) 5287 exit(1); 5288 5289 } else if(strcmp(argv[i], "-verbose-action-file") == 0 || 5290 strcmp(argv[i], "-vaf") ==0) { 5291 if(++i == argc) { 5292 ERROR("%s: %s missing filename\n", argv[0], 5293 argv[i - 1]); 5294 exit(1); 5295 } 5296 if(read_action_file(argv[i], ACTION_LOG_VERBOSE) == FALSE) 5297 exit(1); 5298 5299 } else if(strcmp(argv[i], "-true-action-file") == 0 || 5300 strcmp(argv[i], "-taf") ==0) { 5301 if(++i == argc) { 5302 ERROR("%s: %s missing filename\n", argv[0], 5303 argv[i - 1]); 5304 exit(1); 5305 } 5306 if(read_action_file(argv[i], ACTION_LOG_TRUE) == FALSE) 5307 exit(1); 5308 5309 } else if(strcmp(argv[i], "-false-action-file") == 0 || 5310 strcmp(argv[i], "-faf") ==0) { 5311 if(++i == argc) { 5312 ERROR("%s: %s missing filename\n", argv[0], 5313 argv[i - 1]); 5314 exit(1); 5315 } 5316 if(read_action_file(argv[i], ACTION_LOG_FALSE) == FALSE) 5317 exit(1); 5318 5319 } else if(strcmp(argv[i], "-comp") == 0) 5320 /* parsed previously */ 5321 i++; 5322 5323 else if(strncmp(argv[i], "-X", 2) == 0) { 5324 int args; 5325 5326 if(strcmp(argv[i] + 2, "help") == 0) 5327 goto print_compressor_options; 5328 5329 args = compressor_options(comp, argv + i, argc - i); 5330 if(args < 0) { 5331 if(args == -1) { 5332 ERROR("%s: Unrecognised compressor" 5333 " option %s\n", argv[0], 5334 argv[i]); 5335 if(!compressor_opt_parsed) 5336 ERROR("%s: Did you forget to" 5337 " specify -comp?\n", 5338 argv[0]); 5339 print_compressor_options: 5340 ERROR("%s: selected compressor \"%s\"" 5341 ". Options supported: %s\n", 5342 argv[0], comp->name, 5343 comp->usage ? "" : "none"); 5344 if(comp->usage) 5345 comp->usage(); 5346 } 5347 exit(1); 5348 } 5349 i += args; 5350 5351 } else if(strcmp(argv[i], "-pf") == 0) { 5352 if(++i == argc) { 5353 ERROR("%s: -pf missing filename\n", argv[0]); 5354 exit(1); 5355 } 5356 if(read_pseudo_file(argv[i]) == FALSE) 5357 exit(1); 5358 } else if(strcmp(argv[i], "-p") == 0) { 5359 if(++i == argc) { 5360 ERROR("%s: -p missing pseudo file definition\n", 5361 argv[0]); 5362 exit(1); 5363 } 5364 if(read_pseudo_def(argv[i]) == FALSE) 5365 exit(1); 5366 } else if(strcmp(argv[i], "-recover") == 0) { 5367 if(++i == argc) { 5368 ERROR("%s: -recover missing recovery file\n", 5369 argv[0]); 5370 exit(1); 5371 } 5372 read_recovery_data(argv[i], argv[source + 1]); 5373 } else if(strcmp(argv[i], "-no-recovery") == 0) 5374 recover = FALSE; 5375 else if(strcmp(argv[i], "-wildcards") == 0) { 5376 old_exclude = FALSE; 5377 use_regex = FALSE; 5378 } else if(strcmp(argv[i], "-regex") == 0) { 5379 old_exclude = FALSE; 5380 use_regex = TRUE; 5381 } else if(strcmp(argv[i], "-no-sparse") == 0) 5382 sparse_files = FALSE; 5383 else if(strcmp(argv[i], "-no-progress") == 0) 5384 progress = FALSE; 5385 else if(strcmp(argv[i], "-progress") == 0) 5386 force_progress = TRUE; 5387 else if(strcmp(argv[i], "-no-exports") == 0) 5388 exportable = FALSE; 5389 else if(strcmp(argv[i], "-processors") == 0) { 5390 if((++i == argc) || !parse_num(argv[i], &processors)) { 5391 ERROR("%s: -processors missing or invalid " 5392 "processor number\n", argv[0]); 5393 exit(1); 5394 } 5395 if(processors < 1) { 5396 ERROR("%s: -processors should be 1 or larger\n", 5397 argv[0]); 5398 exit(1); 5399 } 5400 } else if(strcmp(argv[i], "-read-queue") == 0) { 5401 if((++i == argc) || !parse_num(argv[i], &readq)) { 5402 ERROR("%s: -read-queue missing or invalid " 5403 "queue size\n", argv[0]); 5404 exit(1); 5405 } 5406 if(readq < 1) { 5407 ERROR("%s: -read-queue should be 1 megabyte or " 5408 "larger\n", argv[0]); 5409 exit(1); 5410 } 5411 } else if(strcmp(argv[i], "-write-queue") == 0) { 5412 if((++i == argc) || !parse_num(argv[i], &bwriteq)) { 5413 ERROR("%s: -write-queue missing or invalid " 5414 "queue size\n", argv[0]); 5415 exit(1); 5416 } 5417 if(bwriteq < 2) { 5418 ERROR("%s: -write-queue should be 2 megabytes " 5419 "or larger\n", argv[0]); 5420 exit(1); 5421 } 5422 fwriteq = bwriteq >> 1; 5423 bwriteq -= fwriteq; 5424 } else if(strcmp(argv[i], "-fragment-queue") == 0) { 5425 if((++i == argc) || !parse_num(argv[i], &fragq)) { 5426 ERROR("%s: -fragment-queue missing or invalid " 5427 "queue size\n", argv[0]); 5428 exit(1); 5429 } 5430 if(fragq < 1) { 5431 ERROR("%s: -fragment-queue should be 1 " 5432 "megabyte or larger\n", argv[0]); 5433 exit(1); 5434 } 5435 } else if(strcmp(argv[i], "-mem") == 0) { 5436 long long number; 5437 5438 if((++i == argc) || 5439 !parse_numberll(argv[i], &number, 1)) { 5440 ERROR("%s: -mem missing or invalid mem size\n", 5441 argv[0]); 5442 exit(1); 5443 } 5444 5445 /* 5446 * convert from bytes to Mbytes, ensuring the value 5447 * does not overflow a signed int 5448 */ 5449 if(number >= (1LL << 51)) { 5450 ERROR("%s: -mem invalid mem size\n", argv[0]); 5451 exit(1); 5452 } 5453 5454 total_mem = number / 1048576; 5455 if(total_mem < (SQUASHFS_LOWMEM / SQUASHFS_TAKE)) { 5456 ERROR("%s: -mem should be %d Mbytes or " 5457 "larger\n", argv[0], 5458 SQUASHFS_LOWMEM / SQUASHFS_TAKE); 5459 exit(1); 5460 } 5461 calculate_queue_sizes(total_mem, &readq, &fragq, 5462 &bwriteq, &fwriteq); 5463 } else if(strcmp(argv[i], "-b") == 0) { 5464 if(++i == argc) { 5465 ERROR("%s: -b missing block size\n", argv[0]); 5466 exit(1); 5467 } 5468 if(!parse_number(argv[i], &block_size, 1)) { 5469 ERROR("%s: -b invalid block size\n", argv[0]); 5470 exit(1); 5471 } 5472 if((block_log = slog(block_size)) == 0) { 5473 ERROR("%s: -b block size not power of two or " 5474 "not between 4096 and 1Mbyte\n", 5475 argv[0]); 5476 exit(1); 5477 } 5478 } else if(strcmp(argv[i], "-ef") == 0) { 5479 if(++i == argc) { 5480 ERROR("%s: -ef missing filename\n", argv[0]); 5481 exit(1); 5482 } 5483 } else if(strcmp(argv[i], "-no-duplicates") == 0) 5484 duplicate_checking = FALSE; 5485 5486 else if(strcmp(argv[i], "-no-fragments") == 0) 5487 no_fragments = TRUE; 5488 5489 else if(strcmp(argv[i], "-always-use-fragments") == 0) 5490 always_use_fragments = TRUE; 5491 5492 else if(strcmp(argv[i], "-sort") == 0) { 5493 if(++i == argc) { 5494 ERROR("%s: -sort missing filename\n", argv[0]); 5495 exit(1); 5496 } 5497 } else if(strcmp(argv[i], "-all-root") == 0 || 5498 strcmp(argv[i], "-root-owned") == 0) 5499 global_uid = global_gid = 0; 5500 5501 else if(strcmp(argv[i], "-force-uid") == 0) { 5502 if(++i == argc) { 5503 ERROR("%s: -force-uid missing uid or user\n", 5504 argv[0]); 5505 exit(1); 5506 } 5507 if((global_uid = strtoll(argv[i], &b, 10)), *b =='\0') { 5508 if(global_uid < 0 || global_uid > 5509 (((long long) 1 << 32) - 1)) { 5510 ERROR("%s: -force-uid uid out of range" 5511 "\n", argv[0]); 5512 exit(1); 5513 } 5514 } else { 5515 struct passwd *uid = getpwnam(argv[i]); 5516 if(uid) 5517 global_uid = uid->pw_uid; 5518 else { 5519 ERROR("%s: -force-uid invalid uid or " 5520 "unknown user\n", argv[0]); 5521 exit(1); 5522 } 5523 } 5524 } else if(strcmp(argv[i], "-force-gid") == 0) { 5525 if(++i == argc) { 5526 ERROR("%s: -force-gid missing gid or group\n", 5527 argv[0]); 5528 exit(1); 5529 } 5530 if((global_gid = strtoll(argv[i], &b, 10)), *b =='\0') { 5531 if(global_gid < 0 || global_gid > 5532 (((long long) 1 << 32) - 1)) { 5533 ERROR("%s: -force-gid gid out of range" 5534 "\n", argv[0]); 5535 exit(1); 5536 } 5537 } else { 5538 struct group *gid = getgrnam(argv[i]); 5539 if(gid) 5540 global_gid = gid->gr_gid; 5541 else { 5542 ERROR("%s: -force-gid invalid gid or " 5543 "unknown group\n", argv[0]); 5544 exit(1); 5545 } 5546 } 5547 } else if(strcmp(argv[i], "-noI") == 0 || 5548 strcmp(argv[i], "-noInodeCompression") == 0) 5549 noI = TRUE; 5550 5551 else if(strcmp(argv[i], "-noD") == 0 || 5552 strcmp(argv[i], "-noDataCompression") == 0) 5553 noD = TRUE; 5554 5555 else if(strcmp(argv[i], "-noF") == 0 || 5556 strcmp(argv[i], "-noFragmentCompression") == 0) 5557 noF = TRUE; 5558 5559 else if(strcmp(argv[i], "-noX") == 0 || 5560 strcmp(argv[i], "-noXattrCompression") == 0) 5561 noX = TRUE; 5562 5563 else if(strcmp(argv[i], "-no-xattrs") == 0) 5564 no_xattrs = TRUE; 5565 5566 else if(strcmp(argv[i], "-xattrs") == 0) 5567 no_xattrs = FALSE; 5568 5569 /* ANDROID CHANGES START*/ 5570 #ifdef ANDROID 5571 else if(strcmp(argv[i], "-context-file") == 0) { 5572 if(++i == argc) { 5573 ERROR("%s: -context-file: missing file name\n", 5574 argv[0]); 5575 exit(1); 5576 } 5577 context_file = argv[i]; 5578 } 5579 #endif 5580 /* ANDROID CHANGES END */ 5581 else if(strcmp(argv[i], "-nopad") == 0) 5582 nopad = TRUE; 5583 5584 else if(strcmp(argv[i], "-info") == 0) 5585 silent = FALSE; 5586 5587 else if(strcmp(argv[i], "-e") == 0) 5588 break; 5589 5590 else if(strcmp(argv[i], "-noappend") == 0) 5591 delete = TRUE; 5592 5593 else if(strcmp(argv[i], "-keep-as-directory") == 0) 5594 keep_as_directory = TRUE; 5595 /* ANDROID CHANGES START*/ 5596 #ifdef ANDROID 5597 else if(strcmp(argv[i], "-android-fs-config") == 0) 5598 android_config = TRUE; 5599 else if(strcmp(argv[i], "-mount-point") == 0) { 5600 if(++i == argc) { 5601 ERROR("%s: -mount-point: missing mount point name\n", 5602 argv[0]); 5603 exit(1); 5604 } 5605 mount_point = argv[i]; 5606 } 5607 else if(strcmp(argv[i], "-product-out") == 0) { 5608 if(++i == argc) { 5609 ERROR("%s: -product-out: missing path name\n", 5610 argv[0]); 5611 exit(1); 5612 } 5613 target_out_path = argv[i]; 5614 } 5615 #endif 5616 /* ANDROID CHANGES END */ 5617 5618 else if(strcmp(argv[i], "-exit-on-error") == 0) 5619 exit_on_error = TRUE; 5620 5621 else if(strcmp(argv[i], "-root-becomes") == 0) { 5622 if(++i == argc) { 5623 ERROR("%s: -root-becomes: missing name\n", 5624 argv[0]); 5625 exit(1); 5626 } 5627 root_name = argv[i]; 5628 } else if(strcmp(argv[i], "-version") == 0) { 5629 VERSION(); 5630 } else { 5631 ERROR("%s: invalid option\n\n", argv[0]); 5632 printOptions: 5633 ERROR("SYNTAX:%s source1 source2 ... dest [options] " 5634 "[-e list of exclude\ndirs/files]\n", argv[0]); 5635 ERROR("\nFilesystem build options:\n"); 5636 ERROR("-comp <comp>\t\tselect <comp> compression\n"); 5637 ERROR("\t\t\tCompressors available:\n"); 5638 display_compressors("\t\t\t", COMP_DEFAULT); 5639 ERROR("-b <block_size>\t\tset data block to " 5640 "<block_size>. Default 128 Kbytes\n"); 5641 ERROR("\t\t\tOptionally a suffix of K or M can be" 5642 " given to specify\n\t\t\tKbytes or Mbytes" 5643 " respectively\n"); 5644 ERROR("-no-exports\t\tdon't make the filesystem " 5645 "exportable via NFS\n"); 5646 ERROR("-no-sparse\t\tdon't detect sparse files\n"); 5647 ERROR("-no-xattrs\t\tdon't store extended attributes" 5648 NOXOPT_STR "\n"); 5649 ERROR("-xattrs\t\t\tstore extended attributes" XOPT_STR 5650 "\n"); 5651 /* ANDROID CHANGES START*/ 5652 #ifdef ANDROID 5653 ERROR("-context-file <file>\tApply selinux security " 5654 "xattrs from context-file instead\n\t\t\t" 5655 "of reading xattrs from file system\n"); 5656 #endif 5657 /* ANDROID CHANGES END */ 5658 ERROR("-noI\t\t\tdo not compress inode table\n"); 5659 ERROR("-noD\t\t\tdo not compress data blocks\n"); 5660 ERROR("-noF\t\t\tdo not compress fragment blocks\n"); 5661 ERROR("-noX\t\t\tdo not compress extended " 5662 "attributes\n"); 5663 ERROR("-no-fragments\t\tdo not use fragments\n"); 5664 ERROR("-always-use-fragments\tuse fragment blocks for " 5665 "files larger than block size\n"); 5666 ERROR("-no-duplicates\t\tdo not perform duplicate " 5667 "checking\n"); 5668 ERROR("-all-root\t\tmake all files owned by root\n"); 5669 ERROR("-force-uid uid\t\tset all file uids to uid\n"); 5670 ERROR("-force-gid gid\t\tset all file gids to gid\n"); 5671 ERROR("-nopad\t\t\tdo not pad filesystem to a multiple " 5672 "of 4K\n"); 5673 ERROR("-keep-as-directory\tif one source directory is " 5674 "specified, create a root\n"); 5675 ERROR("\t\t\tdirectory containing that directory, " 5676 "rather than the\n"); 5677 ERROR("\t\t\tcontents of the directory\n"); 5678 /* ANDROID CHANGES START*/ 5679 #ifdef ANDROID 5680 ERROR("-android-fs-config\tuse android fs config " 5681 "for mode, uid, and gids of inodes\n"); 5682 ERROR("-mount-point <name>\tNeed to be provided when " 5683 "android-fs-config or context-file\n\t\t\tare " 5684 "enabled and source directory is not mount point\n"); 5685 ERROR("-product-out <path>\tPRODUCT_OUT directory to " 5686 "read device specific FS rules files from\n"); 5687 #endif 5688 /* ANDROID CHANGES END */ 5689 ERROR("\nFilesystem filter options:\n"); 5690 ERROR("-p <pseudo-definition>\tAdd pseudo file " 5691 "definition\n"); 5692 ERROR("-pf <pseudo-file>\tAdd list of pseudo file " 5693 "definitions\n"); 5694 ERROR("-sort <sort_file>\tsort files according to " 5695 "priorities in <sort_file>. One\n"); 5696 ERROR("\t\t\tfile or dir with priority per line. " 5697 "Priority -32768 to\n"); 5698 ERROR("\t\t\t32767, default priority 0\n"); 5699 ERROR("-ef <exclude_file>\tlist of exclude dirs/files." 5700 " One per line\n"); 5701 ERROR("-wildcards\t\tAllow extended shell wildcards " 5702 "(globbing) to be used in\n\t\t\texclude " 5703 "dirs/files\n"); 5704 ERROR("-regex\t\t\tAllow POSIX regular expressions to " 5705 "be used in exclude\n\t\t\tdirs/files\n"); 5706 ERROR("\nFilesystem append options:\n"); 5707 ERROR("-noappend\t\tdo not append to existing " 5708 "filesystem\n"); 5709 ERROR("-root-becomes <name>\twhen appending source " 5710 "files/directories, make the\n"); 5711 ERROR("\t\t\toriginal root become a subdirectory in " 5712 "the new root\n"); 5713 ERROR("\t\t\tcalled <name>, rather than adding the new " 5714 "source items\n"); 5715 ERROR("\t\t\tto the original root\n"); 5716 ERROR("\nMksquashfs runtime options:\n"); 5717 ERROR("-version\t\tprint version, licence and " 5718 "copyright message\n"); 5719 ERROR("-exit-on-error\t\ttreat normally ignored errors " 5720 "as fatal\n"); 5721 ERROR("-recover <name>\t\trecover filesystem data " 5722 "using recovery file <name>\n"); 5723 ERROR("-no-recovery\t\tdon't generate a recovery " 5724 "file\n"); 5725 ERROR("-info\t\t\tprint files written to filesystem\n"); 5726 ERROR("-no-progress\t\tdon't display the progress " 5727 "bar\n"); 5728 ERROR("-progress\t\tdisplay progress bar when using " 5729 "the -info option\n"); 5730 ERROR("-processors <number>\tUse <number> processors." 5731 " By default will use number of\n"); 5732 ERROR("\t\t\tprocessors available\n"); 5733 ERROR("-mem <size>\t\tUse <size> physical memory. " 5734 "Currently set to %dM\n", total_mem); 5735 ERROR("\t\t\tOptionally a suffix of K, M or G can be" 5736 " given to specify\n\t\t\tKbytes, Mbytes or" 5737 " Gbytes respectively\n"); 5738 ERROR("\nMiscellaneous options:\n"); 5739 ERROR("-root-owned\t\talternative name for -all-root" 5740 "\n"); 5741 ERROR("-noInodeCompression\talternative name for -noI" 5742 "\n"); 5743 ERROR("-noDataCompression\talternative name for -noD" 5744 "\n"); 5745 ERROR("-noFragmentCompression\talternative name for " 5746 "-noF\n"); 5747 ERROR("-noXattrCompression\talternative name for " 5748 "-noX\n"); 5749 ERROR("\n-Xhelp\t\t\tprint compressor options for" 5750 " selected compressor\n"); 5751 ERROR("\nCompressors available and compressor specific " 5752 "options:\n"); 5753 display_compressor_usage(COMP_DEFAULT); 5754 exit(1); 5755 } 5756 } 5757 5758 /* 5759 * Some compressors may need the options to be checked for validity 5760 * once all the options have been processed 5761 */ 5762 res = compressor_options_post(comp, block_size); 5763 if(res) 5764 EXIT_MKSQUASHFS(); 5765 5766 /* 5767 * If the -info option has been selected then disable the 5768 * progress bar unless it has been explicitly enabled with 5769 * the -progress option 5770 */ 5771 if(!silent) 5772 progress = force_progress; 5773 5774 #ifdef SQUASHFS_TRACE 5775 /* 5776 * Disable progress bar if full debug tracing is enabled. 5777 * The progress bar in this case just gets in the way of the 5778 * debug trace output 5779 */ 5780 progress = FALSE; 5781 #endif 5782 5783 for(i = 0; i < source; i++) 5784 if(lstat(source_path[i], &source_buf) == -1) { 5785 fprintf(stderr, "Cannot stat source directory \"%s\" " 5786 "because %s\n", source_path[i], 5787 strerror(errno)); 5788 EXIT_MKSQUASHFS(); 5789 } 5790 5791 destination_file = argv[source + 1]; 5792 if(stat(argv[source + 1], &buf) == -1) { 5793 if(errno == ENOENT) { /* Does not exist */ 5794 fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR, 5795 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 5796 if(fd == -1) { 5797 perror("Could not create destination file"); 5798 exit(1); 5799 } 5800 delete = TRUE; 5801 } else { 5802 perror("Could not stat destination file"); 5803 exit(1); 5804 } 5805 5806 } else { 5807 if(S_ISBLK(buf.st_mode)) { 5808 if((fd = open(argv[source + 1], O_RDWR)) == -1) { 5809 perror("Could not open block device as " 5810 "destination"); 5811 exit(1); 5812 } 5813 block_device = 1; 5814 5815 } else if(S_ISREG(buf.st_mode)) { 5816 fd = open(argv[source + 1], (delete ? O_TRUNC : 0) | 5817 O_RDWR); 5818 if(fd == -1) { 5819 perror("Could not open regular file for " 5820 "writing as destination"); 5821 exit(1); 5822 } 5823 } 5824 else { 5825 ERROR("Destination not block device or regular file\n"); 5826 exit(1); 5827 } 5828 5829 } 5830 5831 /* 5832 * process the exclude files - must be done afer destination file has 5833 * been possibly created 5834 */ 5835 for(i = source + 2; i < argc; i++) 5836 if(strcmp(argv[i], "-ef") == 0) 5837 /* 5838 * Note presence of filename arg has already 5839 * been checked 5840 */ 5841 process_exclude_file(argv[++i]); 5842 else if(strcmp(argv[i], "-e") == 0) 5843 break; 5844 else if(strcmp(argv[i], "-root-becomes") == 0 || 5845 strcmp(argv[i], "-sort") == 0 || 5846 strcmp(argv[i], "-pf") == 0 || 5847 strcmp(argv[i], "-af") == 0 || 5848 strcmp(argv[i], "-vaf") == 0 || 5849 strcmp(argv[i], "-comp") == 0) 5850 i++; 5851 5852 if(i != argc) { 5853 if(++i == argc) { 5854 ERROR("%s: -e missing arguments\n", argv[0]); 5855 EXIT_MKSQUASHFS(); 5856 } 5857 while(i < argc) 5858 if(old_exclude) 5859 old_add_exclude(argv[i++]); 5860 else 5861 add_exclude(argv[i++]); 5862 } 5863 5864 /* process the sort files - must be done afer the exclude files */ 5865 for(i = source + 2; i < argc; i++) 5866 if(strcmp(argv[i], "-sort") == 0) { 5867 int res = read_sort_file(argv[++i], source, 5868 source_path); 5869 if(res == FALSE) 5870 BAD_ERROR("Failed to read sort file\n"); 5871 sorted ++; 5872 } else if(strcmp(argv[i], "-e") == 0) 5873 break; 5874 else if(strcmp(argv[i], "-root-becomes") == 0 || 5875 strcmp(argv[i], "-ef") == 0 || 5876 strcmp(argv[i], "-pf") == 0 || 5877 strcmp(argv[i], "-af") == 0 || 5878 strcmp(argv[i], "-vaf") == 0 || 5879 strcmp(argv[i], "-comp") == 0) 5880 i++; 5881 5882 if(!delete) { 5883 comp = read_super(fd, &sBlk, argv[source + 1]); 5884 if(comp == NULL) { 5885 ERROR("Failed to read existing filesystem - will not " 5886 "overwrite - ABORTING!\n"); 5887 ERROR("To force Mksquashfs to write to this block " 5888 "device or file use -noappend\n"); 5889 EXIT_MKSQUASHFS(); 5890 } 5891 5892 block_log = slog(block_size = sBlk.block_size); 5893 noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags); 5894 noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags); 5895 noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags); 5896 noX = SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.flags); 5897 no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags); 5898 always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags); 5899 duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags); 5900 exportable = SQUASHFS_EXPORTABLE(sBlk.flags); 5901 no_xattrs = SQUASHFS_NO_XATTRS(sBlk.flags); 5902 comp_opts = SQUASHFS_COMP_OPTS(sBlk.flags); 5903 } 5904 5905 initialise_threads(readq, fragq, bwriteq, fwriteq, delete, 5906 destination_file); 5907 5908 res = compressor_init(comp, &stream, SQUASHFS_METADATA_SIZE, 0); 5909 if(res) 5910 BAD_ERROR("compressor_init failed\n"); 5911 5912 if(delete) { 5913 int size; 5914 void *comp_data = compressor_dump_options(comp, block_size, 5915 &size); 5916 5917 printf("Creating %d.%d filesystem on %s, block size %d.\n", 5918 SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size); 5919 5920 /* 5921 * store any compressor specific options after the superblock, 5922 * and set the COMP_OPT flag to show that the filesystem has 5923 * compressor specfic options 5924 */ 5925 if(comp_data) { 5926 unsigned short c_byte = size | SQUASHFS_COMPRESSED_BIT; 5927 5928 SQUASHFS_INSWAP_SHORTS(&c_byte, 1); 5929 write_destination(fd, sizeof(struct squashfs_super_block), 5930 sizeof(c_byte), &c_byte); 5931 write_destination(fd, sizeof(struct squashfs_super_block) + 5932 sizeof(c_byte), size, comp_data); 5933 bytes = sizeof(struct squashfs_super_block) + sizeof(c_byte) 5934 + size; 5935 comp_opts = TRUE; 5936 } else 5937 bytes = sizeof(struct squashfs_super_block); 5938 } else { 5939 unsigned int last_directory_block, inode_dir_offset, 5940 inode_dir_file_size, root_inode_size, 5941 inode_dir_start_block, uncompressed_data, 5942 compressed_data, inode_dir_inode_number, 5943 inode_dir_parent_inode; 5944 unsigned int root_inode_start = 5945 SQUASHFS_INODE_BLK(sBlk.root_inode), 5946 root_inode_offset = 5947 SQUASHFS_INODE_OFFSET(sBlk.root_inode); 5948 5949 if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table, 5950 &data_cache, &directory_table, 5951 &directory_data_cache, &last_directory_block, 5952 &inode_dir_offset, &inode_dir_file_size, 5953 &root_inode_size, &inode_dir_start_block, 5954 &file_count, &sym_count, &dev_count, &dir_count, 5955 &fifo_count, &sock_count, &total_bytes, 5956 &total_inode_bytes, &total_directory_bytes, 5957 &inode_dir_inode_number, 5958 &inode_dir_parent_inode, add_old_root_entry, 5959 &fragment_table, &inode_lookup_table)) == 0) { 5960 ERROR("Failed to read existing filesystem - will not " 5961 "overwrite - ABORTING!\n"); 5962 ERROR("To force Mksquashfs to write to this block " 5963 "device or file use -noappend\n"); 5964 EXIT_MKSQUASHFS(); 5965 } 5966 if((append_fragments = fragments = sBlk.fragments)) { 5967 fragment_table = realloc((char *) fragment_table, 5968 ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1)) 5969 * sizeof(struct squashfs_fragment_entry)); 5970 if(fragment_table == NULL) 5971 BAD_ERROR("Out of memory in save filesystem state\n"); 5972 } 5973 5974 printf("Appending to existing %d.%d filesystem on %s, block " 5975 "size %d\n", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], 5976 block_size); 5977 printf("All -b, -noI, -noD, -noF, -noX, no-duplicates, no-fragments, " 5978 "-always-use-fragments,\n-exportable and -comp options " 5979 "ignored\n"); 5980 printf("\nIf appending is not wanted, please re-run with " 5981 "-noappend specified!\n\n"); 5982 5983 compressed_data = (inode_dir_offset + inode_dir_file_size) & 5984 ~(SQUASHFS_METADATA_SIZE - 1); 5985 uncompressed_data = (inode_dir_offset + inode_dir_file_size) & 5986 (SQUASHFS_METADATA_SIZE - 1); 5987 5988 /* save original filesystem state for restoring ... */ 5989 sfragments = fragments; 5990 sbytes = bytes; 5991 sinode_count = sBlk.inodes; 5992 scache_bytes = root_inode_offset + root_inode_size; 5993 sdirectory_cache_bytes = uncompressed_data; 5994 sdata_cache = malloc(scache_bytes); 5995 if(sdata_cache == NULL) 5996 BAD_ERROR("Out of memory in save filesystem state\n"); 5997 sdirectory_data_cache = malloc(sdirectory_cache_bytes); 5998 if(sdirectory_data_cache == NULL) 5999 BAD_ERROR("Out of memory in save filesystem state\n"); 6000 memcpy(sdata_cache, data_cache, scache_bytes); 6001 memcpy(sdirectory_data_cache, directory_data_cache + 6002 compressed_data, sdirectory_cache_bytes); 6003 sinode_bytes = root_inode_start; 6004 stotal_bytes = total_bytes; 6005 stotal_inode_bytes = total_inode_bytes; 6006 stotal_directory_bytes = total_directory_bytes + 6007 compressed_data; 6008 sfile_count = file_count; 6009 ssym_count = sym_count; 6010 sdev_count = dev_count; 6011 sdir_count = dir_count + 1; 6012 sfifo_count = fifo_count; 6013 ssock_count = sock_count; 6014 sdup_files = dup_files; 6015 sid_count = id_count; 6016 write_recovery_data(&sBlk); 6017 save_xattrs(); 6018 appending = TRUE; 6019 6020 /* 6021 * set the filesystem state up to be able to append to the 6022 * original filesystem. The filesystem state differs depending 6023 * on whether we're appending to the original root directory, or 6024 * if the original root directory becomes a sub-directory 6025 * (root-becomes specified on command line, here root_name != 6026 * NULL) 6027 */ 6028 inode_bytes = inode_size = root_inode_start; 6029 directory_size = last_directory_block; 6030 cache_size = root_inode_offset + root_inode_size; 6031 directory_cache_size = inode_dir_offset + inode_dir_file_size; 6032 if(root_name) { 6033 sdirectory_bytes = last_directory_block; 6034 sdirectory_compressed_bytes = 0; 6035 root_inode_number = inode_dir_parent_inode; 6036 inode_no = sBlk.inodes + 2; 6037 directory_bytes = last_directory_block; 6038 directory_cache_bytes = uncompressed_data; 6039 memmove(directory_data_cache, directory_data_cache + 6040 compressed_data, uncompressed_data); 6041 cache_bytes = root_inode_offset + root_inode_size; 6042 add_old_root_entry(root_name, sBlk.root_inode, 6043 inode_dir_inode_number, SQUASHFS_DIR_TYPE); 6044 total_directory_bytes += compressed_data; 6045 dir_count ++; 6046 } else { 6047 sdirectory_compressed_bytes = last_directory_block - 6048 inode_dir_start_block; 6049 sdirectory_compressed = 6050 malloc(sdirectory_compressed_bytes); 6051 if(sdirectory_compressed == NULL) 6052 BAD_ERROR("Out of memory in save filesystem " 6053 "state\n"); 6054 memcpy(sdirectory_compressed, directory_table + 6055 inode_dir_start_block, 6056 sdirectory_compressed_bytes); 6057 sdirectory_bytes = inode_dir_start_block; 6058 root_inode_number = inode_dir_inode_number; 6059 inode_no = sBlk.inodes + 1; 6060 directory_bytes = inode_dir_start_block; 6061 directory_cache_bytes = inode_dir_offset; 6062 cache_bytes = root_inode_offset; 6063 } 6064 6065 inode_count = file_count + dir_count + sym_count + dev_count + 6066 fifo_count + sock_count; 6067 } 6068 6069 if(path) 6070 paths = add_subdir(paths, path); 6071 6072 dump_actions(); 6073 dump_pseudos(); 6074 6075 if(delete && !keep_as_directory && source == 1 && 6076 S_ISDIR(source_buf.st_mode)) 6077 dir_scan(&inode, source_path[0], scan1_readdir, progress); 6078 else if(!keep_as_directory && source == 1 && 6079 S_ISDIR(source_buf.st_mode)) 6080 dir_scan(&inode, source_path[0], scan1_single_readdir, progress); 6081 else 6082 dir_scan(&inode, "", scan1_encomp_readdir, progress); 6083 sBlk.root_inode = inode; 6084 sBlk.inodes = inode_count; 6085 sBlk.s_magic = SQUASHFS_MAGIC; 6086 sBlk.s_major = SQUASHFS_MAJOR; 6087 sBlk.s_minor = SQUASHFS_MINOR; 6088 sBlk.block_size = block_size; 6089 sBlk.block_log = block_log; 6090 sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, noX, no_fragments, 6091 always_use_fragments, duplicate_checking, exportable, 6092 no_xattrs, comp_opts); 6093 sBlk.mkfs_time = time(NULL); 6094 6095 disable_info(); 6096 6097 while((fragment = get_frag_action(fragment))) 6098 write_fragment(*fragment); 6099 unlock_fragments(); 6100 pthread_cleanup_push((void *) pthread_mutex_unlock, &fragment_mutex); 6101 pthread_mutex_lock(&fragment_mutex); 6102 while(fragments_outstanding) { 6103 pthread_mutex_unlock(&fragment_mutex); 6104 sched_yield(); 6105 pthread_mutex_lock(&fragment_mutex); 6106 } 6107 pthread_cleanup_pop(1); 6108 6109 queue_put(to_writer, NULL); 6110 if(queue_get(from_writer) != 0) 6111 EXIT_MKSQUASHFS(); 6112 6113 set_progressbar_state(FALSE); 6114 write_filesystem_tables(&sBlk, nopad); 6115 6116 return 0; 6117 } 6118