2 * Unsquash a squashfs filesystem. This is a highly compressed read only
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>
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.
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.
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.
26 #include "unsquashfs.h"
27 #include "squashfs_swap.h"
28 #include "squashfs_compat.h"
29 #include "compressor.h"
31 #include "unsquashfs_info.h"
33 #include "fnmatch_compat.h"
35 #include <sys/sysinfo.h>
36 #include <sys/sysmacros.h>
37 #include <sys/types.h>
39 #include <sys/resource.h>
44 typedef unsigned long long uint64_t;
45 typedef unsigned int uint32_t;
47 static int verbose
= 0;
48 #define debug(fmt, ...) if(verbose) printf(fmt, ##__VA_ARGS__)
52 typedef struct fs_disk_region
58 typedef struct fs_disk_map
67 int g_fs_region_num
= 0;
68 fs_disk_region
*g_fs_region_list
= NULL
;
69 fs_disk_map g_fs_disk_map
;
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;
77 /* user options that control parallelisation */
80 struct super_block sBlk
;
81 squashfs_operations
*s_ops
;
82 squashfs_operations
*(*read_filesystem_tables
)();
83 struct compressor
*comp
;
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];
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
;
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
;
110 int lookup_type
[] = {
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' },
153 void progress_bar(long long current
, long long max
, int columns
);
155 #define MAX_LINE 16384
162 void sigwinch_handler()
164 struct winsize winsize
;
166 if(ioctl(1, TIOCGWINSZ
, &winsize
) == -1) {
167 if(isatty(STDOUT_FILENO
))
168 ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
172 columns
= winsize
.ws_col
;
176 void sigalrm_handler()
178 rotate
= (rotate
+ 1) % 4;
182 int add_overflow(int a
, int b
)
184 return (INT_MAX
- a
) < b
;
188 int shift_overflow(int a
, int shift
)
190 return (INT_MAX
>> shift
) < a
;
194 int multiply_overflow(int a
, int multiplier
)
196 return (INT_MAX
/ multiplier
) < a
;
200 struct queue
*queue_init(int size
)
202 struct queue
*queue
= malloc(sizeof(struct queue
));
205 EXIT_UNSQUASH("Out of memory in queue_init\n");
207 if(add_overflow(size
, 1) ||
208 multiply_overflow(size
+ 1, sizeof(void *)))
209 EXIT_UNSQUASH("Size too large in queue_init\n");
211 queue
->data
= malloc(sizeof(void *) * (size
+ 1));
212 if(queue
->data
== NULL
)
213 EXIT_UNSQUASH("Out of memory in queue_init\n");
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
);
225 void queue_put(struct queue
*queue
, void *data
)
229 pthread_mutex_lock(&queue
->mutex
);
231 while((nextp
= (queue
->writep
+ 1) % queue
->size
) == queue
->readp
)
232 pthread_cond_wait(&queue
->full
, &queue
->mutex
);
234 queue
->data
[queue
->writep
] = data
;
235 queue
->writep
= nextp
;
236 pthread_cond_signal(&queue
->empty
);
237 pthread_mutex_unlock(&queue
->mutex
);
241 void *queue_get(struct queue
*queue
)
244 pthread_mutex_lock(&queue
->mutex
);
246 while(queue
->readp
== queue
->writep
)
247 pthread_cond_wait(&queue
->empty
, &queue
->mutex
);
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
);
258 void dump_queue(struct queue
*queue
)
260 pthread_mutex_lock(&queue
->mutex
);
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
?
269 pthread_mutex_unlock(&queue
->mutex
);
273 /* Called with the cache mutex held */
274 void insert_hash_table(struct cache
*cache
, struct cache_entry
*entry
)
276 int hash
= CALCULATE_HASH(entry
->block
);
278 entry
->hash_next
= cache
->hash_table
[hash
];
279 cache
->hash_table
[hash
] = entry
;
280 entry
->hash_prev
= NULL
;
282 entry
->hash_next
->hash_prev
= entry
;
286 /* Called with the cache mutex held */
287 void remove_hash_table(struct cache
*cache
, struct cache_entry
*entry
)
290 entry
->hash_prev
->hash_next
= entry
->hash_next
;
292 cache
->hash_table
[CALCULATE_HASH(entry
->block
)] =
295 entry
->hash_next
->hash_prev
= entry
->hash_prev
;
297 entry
->hash_prev
= entry
->hash_next
= NULL
;
301 /* Called with the cache mutex held */
302 void insert_free_list(struct cache
*cache
, struct cache_entry
*entry
)
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
;
310 cache
->free_list
= entry
;
311 entry
->free_prev
= entry
->free_next
= entry
;
316 /* Called with the cache mutex held */
317 void remove_free_list(struct cache
*cache
, struct cache_entry
*entry
)
319 if(entry
->free_prev
== NULL
|| entry
->free_next
== NULL
)
320 /* not in free list */
322 else if(entry
->free_prev
== entry
&& entry
->free_next
== entry
) {
323 /* only this entry in the free list */
324 cache
->free_list
= NULL
;
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
;
333 entry
->free_prev
= entry
->free_next
= NULL
;
337 struct cache
*cache_init(int buffer_size
, int max_buffers
)
339 struct cache
*cache
= malloc(sizeof(struct cache
));
342 EXIT_UNSQUASH("Out of memory in cache_init\n");
344 cache
->max_buffers
= max_buffers
;
345 cache
->buffer_size
= buffer_size
;
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
);
360 struct cache_entry
*cache_get(struct cache
*cache
, long long block
, int size
)
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
369 int hash
= CALCULATE_HASH(block
);
370 struct cache_entry
*entry
;
372 pthread_mutex_lock(&cache
->mutex
);
374 for(entry
= cache
->hash_table
[hash
]; entry
; entry
= entry
->hash_next
)
375 if(entry
->block
== block
)
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.
383 if(entry
->used
== 0) {
385 remove_free_list(cache
, entry
);
388 pthread_mutex_unlock(&cache
->mutex
);
393 * first try to allocate new block
395 if(cache
->count
< cache
->max_buffers
) {
396 entry
= malloc(sizeof(struct cache_entry
));
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
;
407 * try to get from free list
409 while(cache
->free_list
== NULL
) {
410 cache
->wait_free
= TRUE
;
411 pthread_cond_wait(&cache
->wait_for_free
,
414 entry
= cache
->free_list
;
415 remove_free_list(cache
, entry
);
416 remove_hash_table(cache
, entry
);
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
426 entry
->block
= block
;
429 entry
->error
= FALSE
;
430 entry
->pending
= TRUE
;
431 insert_hash_table(cache
, entry
);
435 * queue to read thread to read and ultimately (via the
436 * decompress threads) decompress the buffer
438 pthread_mutex_unlock(&cache
->mutex
);
439 queue_put(to_reader
, entry
);
446 void cache_block_ready(struct cache_entry
*entry
, int error
)
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...
454 pthread_mutex_lock(&entry
->cache
->mutex
);
455 entry
->pending
= FALSE
;
456 entry
->error
= error
;
459 * if the wait_pending flag is set, one or more threads may be waiting
462 if(entry
->cache
->wait_pending
) {
463 entry
->cache
->wait_pending
= FALSE
;
464 pthread_cond_broadcast(&entry
->cache
->wait_for_pending
);
467 pthread_mutex_unlock(&entry
->cache
->mutex
);
471 void cache_block_wait(struct cache_entry
*entry
)
474 * wait for this cache entry to become ready, when reading and (if
475 * necessary) decompression has taken place
477 pthread_mutex_lock(&entry
->cache
->mutex
);
479 while(entry
->pending
) {
480 entry
->cache
->wait_pending
= TRUE
;
481 pthread_cond_wait(&entry
->cache
->wait_for_pending
,
482 &entry
->cache
->mutex
);
485 pthread_mutex_unlock(&entry
->cache
->mutex
);
489 void cache_block_put(struct cache_entry
*entry
)
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.
497 pthread_mutex_lock(&entry
->cache
->mutex
);
500 if(entry
->used
== 0) {
501 insert_free_list(entry
->cache
, entry
);
502 entry
->cache
->used
--;
505 * if the wait_free flag is set, one or more threads may be
506 * waiting on this buffer
508 if(entry
->cache
->wait_free
) {
509 entry
->cache
->wait_free
= FALSE
;
510 pthread_cond_broadcast(&entry
->cache
->wait_for_free
);
514 pthread_mutex_unlock(&entry
->cache
->mutex
);
518 void dump_cache(struct cache
*cache
)
520 pthread_mutex_lock(&cache
->mutex
);
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");
526 pthread_mutex_unlock(&cache
->mutex
);
530 char *modestr(char *str
, int mode
)
534 strcpy(str
, "----------");
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
;
545 #define TOTALCHARS 25
546 int print_filename(char *pathname
, struct inode
*inode
)
548 char str
[11], dummy
[12], dummy2
[12]; /* overflow safe */
549 char *userstr
, *groupstr
;
556 printf("%s\n", pathname
);
560 user
= numeric
? NULL
: getpwuid(inode
->uid
);
562 int res
= snprintf(dummy
, 12, "%d", inode
->uid
);
564 EXIT_UNSQUASH("snprintf failed in print_filename()\n");
566 /* unsigned int shouldn't ever need more than 11 bytes
567 * (including terminating '\0') to print in base 10 */
572 userstr
= user
->pw_name
;
574 group
= numeric
? NULL
: getgrgid(inode
->gid
);
576 int res
= snprintf(dummy2
, 12, "%d", inode
->gid
);
578 EXIT_UNSQUASH("snprintf failed in print_filename()\n");
580 /* unsigned int shouldn't ever need more than 11 bytes
581 * (including terminating '\0') to print in base 10 */
586 groupstr
= group
->gr_name
;
588 printf("%s %s/%s ", modestr(str
, inode
->mode
), userstr
, groupstr
);
590 switch(inode
->mode
& S_IFMT
) {
596 padchars
= TOTALCHARS
- strlen(userstr
) -
599 printf("%*lld ", padchars
> 0 ? padchars
: 0,
604 padchars
= TOTALCHARS
- strlen(userstr
) -
605 strlen(groupstr
) - 7;
607 printf("%*s%3d,%3d ", padchars
> 0 ? padchars
: 0, " ",
608 (int) inode
->data
>> 8, (int) inode
->data
&
613 t
= use_localtime
? localtime(&inode
->time
) : gmtime(&inode
->time
);
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
);
625 void add_entry(struct hash_table_entry
*hash_table
[], long long start
,
628 int hash
= CALCULATE_HASH(start
);
629 struct hash_table_entry
*hash_table_entry
;
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");
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
;
642 long long lookup_entry(struct hash_table_entry
*hash_table
[], long long start
)
644 int hash
= CALCULATE_HASH(start
);
645 struct hash_table_entry
*hash_table_entry
;
647 for(hash_table_entry
= hash_table
[hash
]; hash_table_entry
;
648 hash_table_entry
= hash_table_entry
->next
)
650 if(hash_table_entry
->start
== start
)
651 return hash_table_entry
->bytes
;
656 int read_fs_sectors(int fd
, uint32_t sector
, uint32_t count
, char *buf
)
662 uint32_t readcnt
= 0;
663 fs_disk_region
*region
;
665 for (i
= 0; i
< g_fs_region_num
&& count
> 0; i
++)
667 region
= g_fs_region_list
+ i
;
669 if (sector
>= total
&& sector
< total
+ region
->count
)
671 offset
= sector
- total
;
672 left
= region
->count
- offset
;
673 readcnt
= (count
<= left
) ? count
: left
;
675 lseek(fd
, (uint64_t)(offset
+ region
->sector
) * 512ULL, SEEK_SET
);
676 read(fd
, buf
, (uint64_t)readcnt
* 512ULL);
678 buf
+= (uint64_t)readcnt
* 512ULL;
683 total
+= region
->count
;
691 int read_fs_bytes(int fd
, long long byte
, int bytes
, void *buff
)
697 uint32_t leftsize
= 0;
698 uint64_t offset
= byte
;
699 char *buf
= (char *)buff
;
702 if (offset
>= g_fs_disk_map
.filesize
|| offset
+ bytes
> g_fs_disk_map
.filesize
)
708 sector
= offset
/ 512;
714 read_fs_sectors(fd
, sector
, 1, secbuf
);
716 if (leftsize
> align
)
718 memcpy(buf
, secbuf
+ mod
, align
);
726 memcpy(buf
, secbuf
+ mod
, leftsize
);
731 number
= leftsize
/ 512;
732 read_fs_sectors(fd
, sector
, number
, buf
);
735 mod
= leftsize
% 512;
738 read_fs_sectors(fd
, sector
+ number
, 1, secbuf
);
739 memcpy(buf
, secbuf
, mod
);
747 int read_fs_bytes(int fd
, long long byte
, int bytes
, void *buff
)
752 TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte
,
755 if(lseek(fd
, start_offset
+ off
, SEEK_SET
) == -1) {
756 ERROR("Lseek failed because %s\n", strerror(errno
));
760 for(count
= 0; count
< bytes
; count
+= res
) {
761 res
= read(fd
, buff
+ count
, bytes
- count
);
764 ERROR("Read on filesystem failed because "
767 } else if(errno
!= EINTR
) {
768 ERROR("Read on filesystem failed because %s\n",
780 int read_block(int fd
, long long start
, long long *next
, int expected
,
783 unsigned short c_byte
;
784 int offset
= 2, res
, compressed
;
785 int outlen
= expected
? expected
: SQUASHFS_METADATA_SIZE
;
786 static char *buffer
= NULL
;
788 if(outlen
> SQUASHFS_METADATA_SIZE
)
792 if(read_fs_bytes(fd
, start
, 2, &c_byte
) == FALSE
)
794 c_byte
= (c_byte
>> 8) | ((c_byte
& 0xff) << 8);
796 if(read_fs_bytes(fd
, start
, 2, &c_byte
) == FALSE
)
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");
803 if(SQUASHFS_CHECK_DATA(sBlk
.s
.flags
))
806 compressed
= SQUASHFS_COMPRESSED(c_byte
);
807 c_byte
= SQUASHFS_COMPRESSED_SIZE(c_byte
);
810 * The block size should not be larger than
811 * the uncompressed size (or max uncompressed size if
821 buffer
= malloc(SQUASHFS_METADATA_SIZE
);
824 EXIT_UNSQUASH("read_block: Failed to allocate buffer\n");
827 res
= read_fs_bytes(fd
, start
+ offset
, c_byte
, buffer
);
831 res
= compressor_uncompress(comp
, block
, buffer
, c_byte
,
835 ERROR("%s uncompress failed with error code %d\n",
840 res
= read_fs_bytes(fd
, start
+ offset
, c_byte
, block
);
847 *next
= start
+ offset
+ c_byte
;
850 * if expected, then check the (uncompressed) return data
851 * is of the expected size
853 if(expected
&& expected
!= res
)
859 ERROR("read_block: failed to read block @0x%llx\n", start
);
864 void *read_inode_table(long long start
, long long end
)
869 void *inode_table
= NULL
;
871 TRACE("read_inode_table: start %lld, end %lld\n", 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");
883 add_entry(inode_table_hash
, start
, bytes
);
885 res
= read_block(fd
, start
, &start
, 0, inode_table
+ bytes
);
887 ERROR("read_inode_table: failed to read block\n");
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
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
);
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
)
919 struct utimbuf times
= { time
, time
};
921 if(utime(pathname
, ×
) == -1) {
922 EXIT_UNSQUASH_STRICT("set_attributes: failed to set time on %s, because %s\n",
923 pathname
, strerror(errno
));
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
,
937 if((set_mode
|| (mode
& 07000)) && chmod(pathname
, (mode_t
) mode
) == -1) {
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.
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
));
952 return write_xattr(pathname
, xattr
);
956 int write_bytes(int fd
, char *buff
, int bytes
)
960 for(count
= 0; count
< bytes
; count
+= res
) {
961 res
= write(fd
, buff
+ count
, bytes
- count
);
964 ERROR("Write on output file failed because "
965 "%s\n", strerror(errno
));
976 int lseek_broken
= FALSE
;
977 char *zero_data
= NULL
;
979 int write_block(int file_fd
, char *buffer
, int size
, long long hole
, int sparse
)
984 if(sparse
&& lseek_broken
== FALSE
) {
985 int error
= lseek(file_fd
, off
, SEEK_CUR
);
987 /* failed to seek beyond end of file */
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
);
998 if(sparse
== FALSE
|| lseek_broken
) {
999 int blocks
= (hole
+ block_size
-1) / block_size
;
1001 for(i
= 0; i
< blocks
; i
++, hole
-= avail_bytes
) {
1002 avail_bytes
= hole
> block_size
? block_size
:
1004 if(write_bytes(file_fd
, zero_data
, avail_bytes
)
1011 if(write_bytes(file_fd
, buffer
, size
) == -1)
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
1027 void open_init(int count
)
1030 open_unlimited
= count
== -1;
1034 int open_wait(char *pathname
, int flags
, mode_t mode
)
1036 if (!open_unlimited
) {
1037 pthread_mutex_lock(&open_mutex
);
1038 while (open_count
== 0)
1039 pthread_cond_wait(&open_empty
, &open_mutex
);
1041 pthread_mutex_unlock(&open_mutex
);
1044 return open(pathname
, flags
, mode
);
1048 void close_wake(int fd
)
1052 if (!open_unlimited
) {
1053 pthread_mutex_lock(&open_mutex
);
1055 pthread_cond_signal(&open_empty
);
1056 pthread_mutex_unlock(&open_mutex
);
1061 void queue_file(char *pathname
, int file_fd
, struct inode
*inode
)
1063 struct squashfs_file
*file
= malloc(sizeof(struct squashfs_file
));
1065 EXIT_UNSQUASH("queue_file: unable to malloc file\n");
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
);
1081 void queue_dir(char *pathname
, struct dir
*dir
)
1083 struct squashfs_file
*file
= malloc(sizeof(struct squashfs_file
));
1085 EXIT_UNSQUASH("queue_dir: unable to malloc file\n");
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
);
1098 int write_file(struct inode
*inode
, char *pathname
)
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
;
1105 TRACE("write_file: regular file, blocks %d\n", inode
->blocks
);
1107 file_fd
= open_wait(pathname
, O_CREAT
| O_WRONLY
|
1108 (force
? O_TRUNC
: 0), (mode_t
) inode
->mode
& 0777);
1110 EXIT_UNSQUASH_IGNORE("write_file: failed to create file %s, because %s\n",
1111 pathname
, strerror(errno
));
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");
1119 s_ops
->read_block_list(block_list
, inode
->block_ptr
, inode
->blocks
);
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).
1126 queue_file(pathname
, file_fd
, inode
);
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
));
1133 EXIT_UNSQUASH("write_file: unable to malloc file\n");
1135 block
->size
= i
== file_end
? inode
->data
& (block_size
- 1) :
1137 if(block_list
[i
] == 0) /* sparse block */
1138 block
->buffer
= NULL
;
1140 block
->buffer
= cache_get(data_cache
, start
,
1144 queue_put(to_writer
, block
);
1147 if(inode
->frag_bytes
) {
1150 struct file_entry
*block
= malloc(sizeof(struct file_entry
));
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
);
1166 int create_inode(char *pathname
, struct inode
*i
)
1171 TRACE("create_inode: pathname %s\n", pathname
);
1173 if(created_inode
[i
->inode_number
- 1]) {
1174 TRACE("create_inode: hard link\n");
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
));
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
);
1193 res
= write_file(i
, pathname
);
1199 case SQUASHFS_SYMLINK_TYPE
:
1200 case SQUASHFS_LSYMLINK_TYPE
: {
1201 struct timespec times
[2] = {
1206 TRACE("create_inode: symlink, symlink_size %lld\n",
1212 res
= symlink(i
->symlink
, pathname
);
1214 EXIT_UNSQUASH_STRICT("create_inode: failed to create symlink "
1215 "%s, because %s\n", pathname
,
1220 res
= utimensat(AT_FDCWD
, pathname
, times
,
1221 AT_SYMLINK_NOFOLLOW
);
1223 EXIT_UNSQUASH_STRICT("create_inode: failed to set time on "
1224 "%s, because %s\n", pathname
,
1228 res
= write_xattr(pathname
, i
->xattr
);
1233 res
= lchown(pathname
, i
->uid
, i
->gid
);
1235 EXIT_UNSQUASH_STRICT("create_inode: failed to change "
1236 "uid and gids on %s, because "
1249 case SQUASHFS_BLKDEV_TYPE
:
1250 case SQUASHFS_CHRDEV_TYPE
:
1251 case SQUASHFS_LBLKDEV_TYPE
:
1252 case SQUASHFS_LCHRDEV_TYPE
: {
1254 if ( i
->type
== SQUASHFS_CHRDEV_TYPE
||
1255 i
->type
== SQUASHFS_LCHRDEV_TYPE
)
1258 TRACE("create_inode: dev, rdev 0x%llx\n", i
->data
);
1264 res
= mknod(pathname
, chrdev
? S_IFCHR
: S_IFBLK
,
1265 makedev((i
->data
>> 8) & 0xff,
1268 EXIT_UNSQUASH_STRICT("create_inode: failed to create "
1269 "%s device %s, because %s\n",
1270 chrdev
? "character" : "block",
1271 pathname
, strerror(errno
));
1274 res
= set_attributes(pathname
, i
->mode
, i
->uid
,
1275 i
->gid
, i
->time
, i
->xattr
, TRUE
);
1281 EXIT_UNSQUASH_STRICT("create_inode: could not create %s "
1282 "device %s, because you're not "
1283 "superuser!\n", chrdev
? "character" :
1289 case SQUASHFS_FIFO_TYPE
:
1290 case SQUASHFS_LFIFO_TYPE
:
1291 TRACE("create_inode: fifo\n");
1296 res
= mknod(pathname
, S_IFIFO
, 0);
1298 ERROR("create_inode: failed to create fifo %s, "
1299 "because %s\n", pathname
,
1303 res
= set_attributes(pathname
, i
->mode
, i
->uid
, i
->gid
,
1304 i
->time
, i
->xattr
, TRUE
);
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
);
1316 EXIT_UNSQUASH_STRICT("Unknown inode type %d in create_inode_table!\n",
1321 created_inode
[i
->inode_number
- 1] = strdup(pathname
);
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.
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.
1336 created_inode
[i
->inode_number
- 1] = strdup(pathname
);
1342 void *read_directory_table(long long start
, long long end
)
1345 long long bytes
= 0;
1347 void *directory_table
= malloc(1);
1349 TRACE("read_directory_table: start %lld, end %lld\n", start
, end
);
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");
1362 add_entry(directory_table_hash
, start
, bytes
);
1364 res
= read_block(fd
, start
, &start
, 0, directory_table
+ bytes
);
1366 ERROR("read_directory_table: failed to read block\n");
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
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
);
1387 return directory_table
;
1390 free(directory_table
);
1395 int squashfs_readdir(struct dir
*dir
, char **name
, unsigned int *start_block
,
1396 unsigned int *offset
, unsigned int *type
)
1398 if(dir
->cur_entry
== dir
->dir_count
)
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
;
1411 void squashfs_closedir(struct dir
*dir
)
1418 char *get_component(char *target
, char **targname
)
1422 while(*target
== '/')
1426 while(*target
!= '/' && *target
!= '\0')
1429 *targname
= strndup(start
, target
- start
);
1431 while(*target
== '/')
1438 void free_path(struct pathname
*paths
)
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
);
1456 struct pathname
*add_path(struct pathname
*paths
, char *target
, char *alltarget
)
1461 TRACE("add_path: adding \"%s\" extract file\n", target
);
1463 target
= get_component(target
, &targname
);
1466 paths
= malloc(sizeof(struct pathname
));
1468 EXIT_UNSQUASH("failed to allocate paths\n");
1474 for(i
= 0; i
< paths
->names
; i
++)
1475 if(strcmp(paths
->name
[i
].name
, targname
) == 0)
1478 if(i
== paths
->names
) {
1480 * allocate new name entry
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
;
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
);
1496 char str
[1024]; /* overflow safe */
1498 regerror(error
, paths
->name
[i
].preg
, str
, 1024);
1499 EXIT_UNSQUASH("invalid regex %s in export %s, "
1500 "because %s\n", targname
, alltarget
,
1504 paths
->name
[i
].preg
= NULL
;
1506 if(target
[0] == '\0')
1508 * at leaf pathname component
1510 paths
->name
[i
].paths
= NULL
;
1513 * recurse adding child components
1515 paths
->name
[i
].paths
= add_path(NULL
, target
, alltarget
);
1518 * existing matching entry
1522 if(paths
->name
[i
].paths
== NULL
) {
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
1529 } else if(target
[0] == '\0') {
1531 * at leaf pathname component and child components exist
1532 * from more specific extracts, delete as they're
1533 * subsumed by this extract
1535 free_path(paths
->name
[i
].paths
);
1536 paths
->name
[i
].paths
= NULL
;
1539 * recurse adding child components
1541 add_path(paths
->name
[i
].paths
, target
, alltarget
);
1548 struct pathnames
*init_subdir()
1550 struct pathnames
*new = malloc(sizeof(struct pathnames
));
1552 EXIT_UNSQUASH("Out of memory in init_subdir\n");
1558 struct pathnames
*add_subdir(struct pathnames
*paths
, struct pathname
*path
)
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
*));
1565 EXIT_UNSQUASH("Out of memory in add_subdir\n");
1568 paths
->path
[paths
->count
++] = path
;
1573 void free_subdir(struct pathnames
*paths
)
1579 int matches(struct pathnames
*paths
, char *name
, struct pathnames
**new)
1588 *new = init_subdir();
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
) ==
1598 if(match
&& path
->name
[i
].paths
== NULL
)
1600 * match on a leaf component, any subdirectories
1601 * will implicitly match, therefore return an
1602 * empty new search set
1608 * match on a non-leaf component, add any
1609 * subdirectories to the new set of
1610 * subdirectories to scan for this name
1612 *new = add_subdir(*new, path
->name
[i
].paths
);
1616 if((*new)->count
== 0) {
1618 * no matching names found, delete empty search set, and return
1627 * one or more matches with sub-directories found (no leaf matches),
1628 * return new search set and return TRUE
1634 * found matching leaf exclude, return empty search set and return TRUE
1642 int pre_scan(char *parent_name
, unsigned int start_block
, unsigned int offset
,
1643 struct pathnames
*paths
)
1646 int scan_res
= TRUE
;
1648 struct pathnames
*new;
1650 struct dir
*dir
= s_ops
->opendir(start_block
, offset
, &i
);
1655 while(squashfs_readdir(dir
, &name
, &start_block
, &offset
, &type
)) {
1660 TRACE("pre_scan: name %s, start_block %d, offset %d, type %d\n",
1661 name
, start_block
, offset
, type
);
1663 if(!matches(paths
, name
, &new))
1666 res
= asprintf(&pathname
, "%s/%s", parent_name
, name
);
1668 EXIT_UNSQUASH("asprintf failed in dir_scan\n");
1670 if(type
== SQUASHFS_DIR_TYPE
) {
1671 res
= pre_scan(parent_name
, start_block
, offset
, new);
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] =
1681 total_blocks
+= (i
->data
+
1682 (block_size
- 1)) >> block_log
;
1693 squashfs_closedir(dir
);
1699 int dir_scan(char *parent_name
, unsigned int start_block
, unsigned int offset
,
1700 struct pathnames
*paths
)
1703 int scan_res
= TRUE
;
1705 struct pathnames
*new;
1707 struct dir
*dir
= s_ops
->opendir(start_block
, offset
, &i
);
1710 EXIT_UNSQUASH_IGNORE("dir_scan: failed to read directory %s\n",
1715 if((lsonly
|| info
) && (!concise
|| dir
->dir_count
==0))
1716 print_filename(parent_name
, i
);
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
1725 int res
= mkdir(parent_name
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
1728 * Skip directory if mkdir fails, unless we're
1729 * forcing and the error is -EEXIST
1731 if(!force
|| errno
!= EEXIST
) {
1732 EXIT_UNSQUASH_IGNORE("dir_scan: failed to make directory %s, "
1733 "because %s\n", parent_name
,
1735 squashfs_closedir(dir
);
1740 * Try to change permissions of existing directory so
1741 * that we can write to it
1743 res
= chmod(parent_name
, S_IRUSR
|S_IWUSR
|S_IXUSR
);
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
);
1754 while(squashfs_readdir(dir
, &name
, &start_block
, &offset
, &type
)) {
1758 TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n",
1759 name
, start_block
, offset
, type
);
1762 if(!matches(paths
, name
, &new))
1765 res
= asprintf(&pathname
, "%s/%s", parent_name
, name
);
1767 EXIT_UNSQUASH("asprintf failed in dir_scan\n");
1769 if(type
== SQUASHFS_DIR_TYPE
) {
1770 res
= dir_scan(pathname
, start_block
, offset
, new);
1774 } else if(new == NULL
) {
1775 update_info(pathname
);
1777 i
= s_ops
->read_inode(start_block
, offset
);
1780 print_filename(pathname
, i
);
1783 res
= create_inode(pathname
, i
);
1788 if(i
->type
== SQUASHFS_SYMLINK_TYPE
||
1789 i
->type
== SQUASHFS_LSYMLINK_TYPE
)
1798 queue_dir(parent_name
, dir
);
1800 squashfs_closedir(dir
);
1807 void squashfs_stat(char *source
)
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
);
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
);
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
);
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));
1829 if(sBlk
.s
.s_major
== 4) {
1830 printf("Compression %s\n", comp
->name
);
1832 if(SQUASHFS_COMP_OPTS(sBlk
.s
.flags
)) {
1833 char buffer
[SQUASHFS_METADATA_SIZE
] __attribute__ ((aligned
));
1836 if(!comp
->supported
)
1837 printf("\tCould not display compressor options, because %s compression is not supported\n",
1840 bytes
= read_block(fd
, sizeof(sBlk
.s
), NULL
, 0, buffer
);
1842 ERROR("Failed to read compressor options\n");
1846 compressor_display_options(comp
, buffer
, bytes
);
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" : "");
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" : "");
1864 if(sBlk
.s
.s_major
> 1) {
1865 if(SQUASHFS_NO_FRAGMENTS(sBlk
.s
.flags
))
1866 printf("Fragments are not stored\n");
1868 printf("Fragments are %scompressed\n",
1869 SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk
.s
.flags
) ?
1871 printf("Always-use-fragments option is %sspecified\n",
1872 SQUASHFS_ALWAYS_FRAGMENTS(sBlk
.s
.flags
) ? "" :
1877 if(sBlk
.s
.s_major
== 4) {
1878 if(SQUASHFS_NO_XATTRS(sBlk
.s
.flags
))
1879 printf("Xattrs are not stored\n");
1881 printf("Xattrs are %scompressed\n",
1882 SQUASHFS_UNCOMPRESSED_XATTRS(sBlk
.s
.flags
) ?
1886 if(sBlk
.s
.s_major
< 4)
1887 printf("Check data is %spresent in the filesystem\n",
1888 SQUASHFS_CHECK_DATA(sBlk
.s
.flags
) ? "" :
1891 if(sBlk
.s
.s_major
> 1)
1892 printf("Duplicates are %sremoved\n",
1893 SQUASHFS_DUPLICATES(sBlk
.s
.flags
) ? "" : "not ");
1895 printf("Duplicates are removed\n");
1897 if(sBlk
.s
.s_major
> 1)
1898 printf("Number of fragments %d\n", sBlk
.s
.fragments
);
1900 printf("Number of inodes %d\n", sBlk
.s
.inodes
);
1902 if(sBlk
.s
.s_major
== 4)
1903 printf("Number of ids %d\n", sBlk
.s
.no_ids
);
1905 printf("Number of uids %d\n", sBlk
.no_uids
);
1906 printf("Number of gids %d\n", sBlk
.no_guids
);
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
);
1913 if(sBlk
.s
.s_major
> 1)
1914 TRACE("sBlk.s.fragment_table_start 0x%llx\n\n",
1915 sBlk
.s
.fragment_table_start
);
1917 if(sBlk
.s
.s_major
> 2)
1918 TRACE("sBlk.s.lookup_table_start 0x%llx\n\n",
1919 sBlk
.s
.lookup_table_start
);
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
);
1926 TRACE("sBlk.uid_start 0x%llx\n", sBlk
.uid_start
);
1927 TRACE("sBlk.guid_start 0x%llx\n", sBlk
.guid_start
);
1932 int check_compression(struct compressor
*comp
)
1935 char buffer
[SQUASHFS_METADATA_SIZE
] __attribute__ ((aligned
));
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("", "");
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.
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.
1954 if(SQUASHFS_COMP_OPTS(sBlk
.s
.flags
)) {
1955 bytes
= read_block(fd
, sizeof(sBlk
.s
), NULL
, 0, buffer
);
1957 ERROR("Failed to read compressor options\n");
1962 res
= compressor_check_options(comp
, sBlk
.s
.block_size
, buffer
, bytes
);
1968 int read_super(char *source
)
1970 squashfs_super_block_3 sBlk_3
;
1971 struct squashfs_super_block sBlk_4
;
1974 * Try to read a Squashfs 4 superblock
1976 read_fs_bytes(fd
, SQUASHFS_START
, sizeof(struct squashfs_super_block
),
1978 swap
= sBlk_4
.s_magic
!= SQUASHFS_MAGIC
;
1979 SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4
);
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
));
1987 * Check the compression type
1989 comp
= lookup_compressor_id(sBlk
.s
.compression
);
1994 * Not a Squashfs 4 superblock, try to read a squashfs 3 superblock
1995 * (compatible with 1 and 2 filesystems)
1997 read_fs_bytes(fd
, SQUASHFS_START
, sizeof(squashfs_super_block_3
),
2001 * Check it is a SQUASHFS superblock
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 "
2009 SQUASHFS_SWAP_SUPER_BLOCK_3(&sblk
, &sBlk_3
);
2010 memcpy(&sBlk_3
, &sblk
, sizeof(squashfs_super_block_3
));
2013 ERROR("Can't find a SQUASHFS superblock on %s\n",
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
;
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
;
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
;
2053 sBlk
.s
.fragment_table_start
=
2054 sBlk_3
.fragment_table_start_2
;
2055 read_filesystem_tables
= read_filesystem_tables_2
;
2057 } else if(sBlk
.s
.s_major
== 3) {
2058 read_filesystem_tables
= read_filesystem_tables_3
;
2060 ERROR("Filesystem on %s is (%d:%d), ", source
, sBlk
.s
.s_major
,
2062 ERROR("which is a later filesystem version than I support!\n");
2067 * 1.x, 2.x and 3.x filesystems use gzip compression.
2069 comp
= lookup_compressor("gzip");
2077 struct pathname
*process_extract_files(struct pathname
*path
, char *filename
)
2080 char buffer
[MAX_LINE
+ 1]; /* overflow safe */
2083 fd
= fopen(filename
, "r");
2085 EXIT_UNSQUASH("Failed to open extract file \"%s\" because %s\n",
2086 filename
, strerror(errno
));
2088 while(fgets(name
= buffer
, MAX_LINE
+ 1, fd
) != NULL
) {
2089 int len
= strlen(name
);
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
);
2098 * Remove '\n' terminator if it exists (the last line
2099 * in the file may not be '\n' terminated)
2101 if(len
&& name
[len
- 1] == '\n')
2102 name
[len
- 1] = '\0';
2104 /* Skip any leading whitespace */
2105 while(isspace(*name
))
2108 /* if comment line, skip */
2112 /* check for initial backslash, to accommodate
2113 * filenames with leading space or leading # character
2118 /* if line is now empty after skipping characters, skip it */
2122 path
= add_path(path
, name
, name
);
2126 EXIT_UNSQUASH("Reading extract file \"%s\" failed because %s\n",
2127 filename
, strerror(errno
));
2135 * reader thread. This thread processes read requests queued by the
2136 * cache_get() routine.
2138 void *reader(void *arg
)
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
),
2146 if(res
&& SQUASHFS_COMPRESSED_BLOCK(entry
->size
))
2148 * queue successfully read block to the inflate
2149 * thread(s) for further processing
2151 queue_put(to_inflate
, entry
);
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
2159 cache_block_ready(entry
, !res
);
2165 * writer thread. This processes file write requests queued by the
2166 * write_file() routine.
2168 void *writer(void *arg
)
2171 long failed
= FALSE
;
2174 struct squashfs_file
*file
= queue_get(to_writer
);
2180 queue_put(from_writer
, (void *) failed
);
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
);
2188 free(file
->pathname
);
2193 TRACE("writer: regular file, blocks %d\n", file
->blocks
);
2197 for(i
= 0; i
< file
->blocks
; i
++, cur_blocks
++) {
2198 struct file_entry
*block
= queue_get(to_writer
);
2200 if(block
->buffer
== 0) { /* sparse file */
2201 hole
+= block
->size
;
2206 cache_block_wait(block
->buffer
);
2208 if(block
->buffer
->error
) {
2209 EXIT_UNSQUASH_IGNORE("writer: failed to read/uncompress file %s\n", file
->pathname
);
2216 res
= write_block(file_fd
, block
->buffer
->data
+
2217 block
->offset
, block
->size
, hole
, file
->sparse
);
2220 EXIT_UNSQUASH_IGNORE("writer: failed to write file %s\n", file
->pathname
);
2225 cache_block_put(block
->buffer
);
2229 if(hole
&& failed
== FALSE
) {
2231 * corner case for hole extending to end of file
2233 if(file
->sparse
== FALSE
||
2234 lseek(file_fd
, hole
, SEEK_CUR
) == -1) {
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
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
);
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
);
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
);
2262 unlink(file
->pathname
);
2263 free(file
->pathname
);
2271 * decompress thread. This decompresses buffers queued by the read thread
2273 void *inflator(void *arg
)
2275 char *tmp
= malloc(block_size
);
2278 EXIT_UNSQUASH("inflator: Failed to allocate block buffer\n");
2281 struct cache_entry
*entry
= queue_get(to_inflate
);
2284 res
= compressor_uncompress(comp
, tmp
, entry
->data
,
2285 SQUASHFS_COMPRESSED_SIZE_BLOCK(entry
->size
), block_size
,
2289 ERROR("%s uncompress failed with error code %d\n",
2292 memcpy(entry
->data
, tmp
, res
);
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
2299 cache_block_ready(entry
, res
== -1);
2304 void *progress_thread(void *arg
)
2306 struct timespec requested_time
, remaining
;
2307 struct itimerval itimerval
;
2308 struct winsize winsize
;
2310 if(ioctl(1, TIOCGWINSZ
, &winsize
) == -1) {
2311 if(isatty(STDOUT_FILENO
))
2312 ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 "
2316 columns
= winsize
.ws_col
;
2317 signal(SIGWINCH
, sigwinch_handler
);
2318 signal(SIGALRM
, sigalrm_handler
);
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
);
2326 requested_time
.tv_sec
= 0;
2327 requested_time
.tv_nsec
= 250000000;
2330 int res
= nanosleep(&requested_time
, &remaining
);
2332 if(res
== -1 && errno
!= EINTR
)
2333 EXIT_UNSQUASH("nanosleep failed in progress thread\n");
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
);
2346 void initialise_threads(int fragment_buffer_size
, int data_buffer_size
)
2349 int i
, max_files
, res
;
2350 sigset_t sigmask
, old_mask
;
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"
2361 * temporarily block these signals so the created sub-threads will
2362 * ignore them, ensuring the main thread handles them
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"
2371 if(processors
== -1) {
2374 size_t len
= sizeof(processors
);
2378 mib
[1] = HW_AVAILCPU
;
2383 if(sysctl(mib
, 2, &processors
, &len
, NULL
, 0) == -1) {
2384 ERROR("Failed to get number of available processors. "
2385 "Defaulting to 1\n");
2389 processors
= sysconf(_SC_NPROCESSORS_ONLN
);
2393 if(add_overflow(processors
, 3) ||
2394 multiply_overflow(processors
+ 3, sizeof(pthread_t
)))
2395 EXIT_UNSQUASH("Processors too large\n");
2397 thread
= malloc((3 + processors
) * sizeof(pthread_t
));
2399 EXIT_UNSQUASH("Out of memory allocating thread descriptors\n");
2400 inflator_thread
= &thread
[3];
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)
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.
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
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.
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.
2441 res
= getrlimit(RLIMIT_NOFILE
, &rlim
);
2443 ERROR("failed to get open file limit! Defaulting to 1\n");
2447 if (rlim
.rlim_cur
!= RLIM_INFINITY
) {
2449 * leave OPEN_FILE_MARGIN free (rlim_cur includes fds used by
2450 * stdin, stdout, stderr and filesystem fd
2452 if (rlim
.rlim_cur
<= OPEN_FILE_MARGIN
)
2453 /* no margin, use minimum possible */
2456 max_files
= rlim
.rlim_cur
- OPEN_FILE_MARGIN
;
2460 /* set amount of available files for use by open_wait and close_wake */
2461 open_init(max_files
);
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
2468 * In doing so, check that the user supplied values do not overflow
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");
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
);
2480 int all_buffers_size
;
2482 if(add_overflow(fragment_buffer_size
, data_buffer_size
))
2483 EXIT_UNSQUASH("Data and fragment queues combined are"
2486 all_buffers_size
= fragment_buffer_size
+ data_buffer_size
;
2488 if(add_overflow(all_buffers_size
, all_buffers_size
))
2489 EXIT_UNSQUASH("Data and fragment queues combined are"
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);
2497 from_writer
= queue_init(1);
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
);
2505 pthread_mutex_init(&fragment_mutex
, NULL
);
2507 for(i
= 0; i
< processors
; i
++) {
2508 if(pthread_create(&inflator_thread
[i
], NULL
, inflator
, NULL
) !=
2510 EXIT_UNSQUASH("Failed to create thread\n");
2513 if(pthread_sigmask(SIG_SETMASK
, &old_mask
, NULL
) != 0)
2514 EXIT_UNSQUASH("Failed to set signal mask in initialise_threads"
2519 void enable_progress_bar()
2521 pthread_mutex_lock(&screen_mutex
);
2522 progress_enabled
= progress
;
2523 pthread_mutex_unlock(&screen_mutex
);
2527 void disable_progress_bar()
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
);
2535 progress_enabled
= FALSE
;
2536 pthread_mutex_unlock(&screen_mutex
);
2540 void progressbar_error(char *fmt
, ...)
2544 pthread_mutex_lock(&screen_mutex
);
2546 if(progress_enabled
)
2547 fprintf(stderr
, "\n");
2550 vfprintf(stderr
, fmt
, ap
);
2553 pthread_mutex_unlock(&screen_mutex
);
2557 void progressbar_info(char *fmt
, ...)
2561 pthread_mutex_lock(&screen_mutex
);
2563 if(progress_enabled
)
2570 pthread_mutex_unlock(&screen_mutex
);
2572 static int get_max_digits(long long max
)
2584 void progress_bar(long long current
, long long max
, int columns
)
2586 char rotate_list
[] = { '|', '/', '-', '\\' };
2587 int max_digits
, used
, hashes
, spaces
;
2588 static int tty
= -1;
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
;
2599 if((current
> max
) || (columns
- used
< 0))
2603 tty
= isatty(STDOUT_FILENO
);
2605 static long long previous
= -1;
2608 * Updating much more frequently than this results in huge
2611 if((current
% 100) != 0 && current
!= max
)
2613 /* Don't update just to rotate the spinner. */
2614 if(current
== previous
)
2624 putchar(rotate_list
[rotate
]);
2629 printf("] %*lld/%*lld", max_digits
, current
, max_digits
, max
);
2630 printf(" %3lld%%", current
* 100 / max
);
2635 int multiply_overflowll(long long a
, int multiplier
)
2637 return (LLONG_MAX
/ multiplier
) < a
;
2641 int parse_numberll(char *start
, long long *res
, int size
)
2646 errno
= 0; /* To distinguish success/failure after call */
2648 number
= strtoll(start
, &end
, 10);
2651 * check for strtoll underflow or overflow in conversion, and other
2654 if((errno
== ERANGE
&& (number
== LLONG_MIN
|| number
== LLONG_MAX
)) ||
2655 (errno
!= 0 && number
== 0))
2658 /* reject negative numbers as invalid */
2664 * Check for multiplier and trailing junk.
2665 * But first check that a number exists before the
2674 if(multiply_overflowll(number
, 1073741824))
2676 number
*= 1073741824;
2679 /* trailing junk after multiplier, but
2680 * allow it to be "bytes" */
2681 if(strcmp(end
+ 1, "bytes"))
2687 if(multiply_overflowll(number
, 1048576))
2692 /* trailing junk after multiplier, but
2693 * allow it to be "bytes" */
2694 if(strcmp(end
+ 1, "bytes"))
2700 if(multiply_overflowll(number
, 1024))
2705 /* trailing junk after multiplier, but
2706 * allow it to be "bytes" */
2707 if(strcmp(end
+ 1, "bytes"))
2714 /* trailing junk after number */
2717 } else if(end
[0] != '\0')
2718 /* trailing junk after number */
2726 int parse_number(char *start
, int *res
)
2730 if(!parse_numberll(start
, &number
, 0))
2733 /* check if long result will overflow signed int */
2734 if(number
> INT_MAX
)
2737 *res
= (int) number
;
2742 int ventoy_parse_disk_map(void)
2746 debug("ventoy_parse_disk_map\n");
2748 len
= (int)lseek(fd
, 0, SEEK_END
);
2749 lseek(fd
, 0, SEEK_SET
);
2751 if (len
< sizeof(fs_disk_map
) + sizeof(fs_disk_region
))
2756 read(fd
, &g_fs_disk_map
, sizeof(fs_disk_map
));
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
);
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
));
2767 fd
= open(g_fs_disk_map
.diskname
, O_RDONLY
);
2768 debug("ventoy_parse_disk_map end fd=%d\n", fd
);
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"\
2780 printf("modify it under the terms of the GNU General Public License"\
2782 printf("as published by the Free Software Foundation; either version "\
2784 printf("or (at your option) any later version.\n\n");\
2785 printf("This program is distributed in the hope that it will be "\
2787 printf("but WITHOUT ANY WARRANTY; without even the implied warranty of"\
2789 printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\
2791 printf("GNU General Public License for more details.\n");
2792 int main(int argc
, char *argv
[])
2794 char *dest
= "squashfs-root";
2795 int i
, stat_sys
= FALSE
, version
= FALSE
, mkfs_time_opt
= FALSE
;
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
;
2804 pthread_mutex_init(&screen_mutex
, NULL
);
2805 root_process
= geteuid() == 0;
2809 for(i
= 1; i
< argc
; i
++) {
2812 if(strcmp(argv
[i
], "-UTC") == 0)
2813 use_localtime
= FALSE
;
2814 else if (strcmp(argv
[i
], "-t") == 0)
2816 else if (strcmp(argv
[i
], "-v") == 0)
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)
2827 else if(strcmp(argv
[i
], "-version") == 0 ||
2828 strcmp(argv
[i
], "-v") == 0) {
2831 } else if(strcmp(argv
[i
], "-info") == 0 ||
2832 strcmp(argv
[i
], "-i") == 0)
2834 else if(strcmp(argv
[i
], "-ls") == 0 ||
2835 strcmp(argv
[i
], "-l") == 0)
2837 else if(strcmp(argv
[i
], "-lc") == 0) {
2840 } else if(strcmp(argv
[i
], "-no-progress") == 0 ||
2841 strcmp(argv
[i
], "-n") == 0)
2843 else if(strcmp(argv
[i
], "-no-xattrs") == 0 ||
2844 strcmp(argv
[i
], "-no") == 0)
2846 else if(strcmp(argv
[i
], "-xattrs") == 0 ||
2847 strcmp(argv
[i
], "-x") == 0)
2849 else if(strcmp(argv
[i
], "-user-xattrs") == 0 ||
2850 strcmp(argv
[i
], "-u") == 0) {
2853 } else if(strcmp(argv
[i
], "-dest") == 0 ||
2854 strcmp(argv
[i
], "-d") == 0) {
2856 fprintf(stderr
, "%s: -dest missing filename\n",
2861 } else if(strcmp(argv
[i
], "-processors") == 0 ||
2862 strcmp(argv
[i
], "-p") == 0) {
2864 !parse_number(argv
[i
],
2866 ERROR("%s: -processors missing or invalid "
2867 "processor number\n", argv
[0]);
2870 if(processors
< 1) {
2871 ERROR("%s: -processors should be 1 or larger\n",
2875 } else if(strcmp(argv
[i
], "-data-queue") == 0 ||
2876 strcmp(argv
[i
], "-da") == 0) {
2878 !parse_number(argv
[i
],
2879 &data_buffer_size
)) {
2880 ERROR("%s: -data-queue missing or invalid "
2881 "queue size\n", argv
[0]);
2884 if(data_buffer_size
< 1) {
2885 ERROR("%s: -data-queue should be 1 Mbyte or "
2886 "larger\n", argv
[0]);
2889 } else if(strcmp(argv
[i
], "-frag-queue") == 0 ||
2890 strcmp(argv
[i
], "-fr") == 0) {
2892 !parse_number(argv
[i
],
2893 &fragment_buffer_size
)) {
2894 ERROR("%s: -frag-queue missing or invalid "
2895 "queue size\n", argv
[0]);
2898 if(fragment_buffer_size
< 1) {
2899 ERROR("%s: -frag-queue should be 1 Mbyte or "
2900 "larger\n", argv
[0]);
2903 } else if(strcmp(argv
[i
], "-force") == 0 ||
2904 strcmp(argv
[i
], "-f") == 0)
2906 else if(strcmp(argv
[i
], "-stat") == 0 ||
2907 strcmp(argv
[i
], "-s") == 0)
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) {
2916 } else if(strcmp(argv
[i
], "-llnumeric") == 0 ||
2917 strcmp(argv
[i
], "-lln") == 0) {
2921 } else if(strcmp(argv
[i
], "-llc") == 0) {
2925 } else if(strcmp(argv
[i
], "-linfo") == 0 ||
2926 strcmp(argv
[i
], "-li") == 0) {
2929 } else if(strcmp(argv
[i
], "-ef") == 0 ||
2930 strcmp(argv
[i
], "-e") == 0) {
2932 fprintf(stderr
, "%s: -ef missing filename\n",
2936 path
= process_extract_files(path
, argv
[i
]);
2937 } else if(strcmp(argv
[i
], "-regex") == 0 ||
2938 strcmp(argv
[i
], "-r") == 0)
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]);
2952 if(strict_errors
&& ignore_errors
)
2953 EXIT_UNSQUASH("Both -strict-errors and -ignore-errors should not be set\n");
2955 #ifdef SQUASHFS_TRACE
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
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 "
2976 ERROR("\t-no[-xattrs]\t\tdon't extract xattrs in file system"
2978 ERROR("\t-x[attrs]\t\textract xattrs in file system"
2980 ERROR("\t-u[ser-xattrs]\t\tonly extract user xattrs in "
2981 "file system.\n\t\t\t\tEnables extracting "
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 "
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"
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 "
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 "
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("", "");
3034 for(n
= i
+ 1; n
< argc
; n
++)
3035 path
= add_path(path
, argv
[n
], argv
[n
]);
3037 if((fd
= open(argv
[i
], O_RDONLY
)) == -1) {
3038 ERROR("Could not open %s, because %s\n", argv
[i
],
3043 ventoy_parse_disk_map();
3045 if(read_super(argv
[i
]) == FALSE
)
3049 printf("%u\n", sBlk
.s
.mkfs_time
);
3054 squashfs_stat(argv
[i
]);
3058 if(!check_compression(comp
))
3061 block_size
= sBlk
.s
.block_size
;
3062 block_log
= sBlk
.s
.block_log
;
3065 * Sanity check block size and block log.
3067 * Check they're within correct limits
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");
3075 * Check block_size and block_log match
3077 if(block_size
!= (1 << block_log
))
3078 EXIT_UNSQUASH("Block size and block_log do not match."
3079 " File system is corrupt.\n");
3082 * convert from queue size in Mbytes to queue size in
3085 * In doing so, check that the user supplied values do not
3086 * overflow a signed int
3088 if(shift_overflow(fragment_buffer_size
, 20 - block_log
))
3089 EXIT_UNSQUASH("Fragment queue size is too large\n");
3091 fragment_buffer_size
<<= 20 - block_log
;
3093 if(shift_overflow(data_buffer_size
, 20 - block_log
))
3094 EXIT_UNSQUASH("Data queue size is too large\n");
3096 data_buffer_size
<<= 20 - block_log
;
3098 initialise_threads(fragment_buffer_size
, data_buffer_size
);
3100 created_inode
= malloc(sBlk
.s
.inodes
* sizeof(char *));
3101 if(created_inode
== NULL
)
3102 EXIT_UNSQUASH("failed to allocate created_inode\n");
3104 memset(created_inode
, 0, sBlk
.s
.inodes
* sizeof(char *));
3106 s_ops
= read_filesystem_tables();
3108 EXIT_UNSQUASH("failed to read file system tables\n");
3111 paths
= init_subdir();
3112 paths
= add_subdir(paths
, path
);
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
);
3121 memset(created_inode
, 0, sBlk
.s
.inodes
* sizeof(char *));
3125 printf("Parallel unsquashfs: Using %d processor%s\n", processors
,
3126 processors
== 1 ? "" : "s");
3128 printf("%d inodes (%d blocks) to write\n\n", total_inodes
,
3129 total_inodes
- total_files
+ total_blocks
);
3132 enable_progress_bar();
3135 res
= dir_scan(dest
, SQUASHFS_INODE_BLK(sBlk
.s
.root_inode
),
3136 SQUASHFS_INODE_OFFSET(sBlk
.s
.root_inode
), paths
);
3140 queue_put(to_writer
, NULL
);
3141 res
= (long) queue_get(from_writer
);
3145 disable_progress_bar();
3147 if(!quiet
&& !lsonly
) {
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
);