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