2 * Unsquash a squashfs filesystem. This is a highly compressed read only
5 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019
6 * Phillip Lougher <phillip@squashfs.org.uk>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include "unsquashfs.h"
26 #include "squashfs_compat.h"
28 static squashfs_fragment_entry_3
*fragment_table
;
29 static unsigned int *uid_table
, *guid_table
;
30 static char *inode_table
, *directory_table
;
31 static squashfs_operations ops
;
33 static long long *salloc_index_table(int indexes
)
35 static long long *alloc_table
= NULL
;
36 static int alloc_size
= 0;
37 int length
= indexes
* sizeof(long long);
39 if(alloc_size
< length
|| length
== 0) {
40 long long *table
= realloc(alloc_table
, length
);
42 if(table
== NULL
&& length
!=0 )
43 EXIT_UNSQUASH("alloc_index_table: failed to allocate "
54 static void read_block_list(unsigned int *block_list
, char *block_ptr
, int blocks
)
56 TRACE("read_block_list: blocks %d\n", blocks
);
59 SQUASHFS_SWAP_INTS_3(block_list
, block_ptr
, blocks
);
61 memcpy(block_list
, block_ptr
, blocks
* sizeof(unsigned int));
65 static int read_fragment_table(long long *table_start
)
68 * Note on overflow limits:
69 * Size of SBlk.s.fragments is 2^32 (unsigned int)
70 * Max size of bytes is 2^32*16 or 2^36
71 * Max indexes is (2^32*16)/8K or 2^23
72 * Max length is ((2^32*16)/8K)*8 or 2^26 or 64M
75 long long bytes
= SQUASHFS_FRAGMENT_BYTES_3((long long) sBlk
.s
.fragments
);
76 int indexes
= SQUASHFS_FRAGMENT_INDEXES_3((long long) sBlk
.s
.fragments
);
77 int length
= SQUASHFS_FRAGMENT_INDEX_BYTES_3((long long) sBlk
.s
.fragments
);
78 long long *fragment_table_index
;
81 * The size of the index table (length bytes) should match the
82 * table start and end points
84 if(length
!= (*table_start
- sBlk
.s
.fragment_table_start
)) {
85 ERROR("read_fragment_table: Bad fragment count in super block\n");
89 TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
90 "from 0x%llx\n", sBlk
.s
.fragments
, indexes
,
91 sBlk
.s
.fragment_table_start
);
93 fragment_table_index
= alloc_index_table(indexes
);
94 fragment_table
= malloc(bytes
);
95 if(fragment_table
== NULL
)
96 EXIT_UNSQUASH("read_fragment_table: failed to allocate "
100 long long *sfragment_table_index
= salloc_index_table(indexes
);
102 res
= read_fs_bytes(fd
, sBlk
.s
.fragment_table_start
,
103 length
, sfragment_table_index
);
105 ERROR("read_fragment_table: failed to read fragment "
109 SQUASHFS_SWAP_FRAGMENT_INDEXES_3(fragment_table_index
,
110 sfragment_table_index
, indexes
);
112 res
= read_fs_bytes(fd
, sBlk
.s
.fragment_table_start
,
113 length
, fragment_table_index
);
115 ERROR("read_fragment_table: failed to read fragment "
121 for(i
= 0; i
< indexes
; i
++) {
122 int expected
= (i
+ 1) != indexes
? SQUASHFS_METADATA_SIZE
:
123 bytes
& (SQUASHFS_METADATA_SIZE
- 1);
124 int length
= read_block(fd
, fragment_table_index
[i
], NULL
,
125 expected
, ((char *) fragment_table
) + ((long long) i
*
126 SQUASHFS_METADATA_SIZE
));
127 TRACE("Read fragment table block %d, from 0x%llx, length %d\n",
128 i
, fragment_table_index
[i
], length
);
129 if(length
== FALSE
) {
130 ERROR("read_fragment_table: failed to read fragment "
137 squashfs_fragment_entry_3 sfragment
;
138 for(i
= 0; i
< sBlk
.s
.fragments
; i
++) {
139 SQUASHFS_SWAP_FRAGMENT_ENTRY_3((&sfragment
),
140 (&fragment_table
[i
]));
141 memcpy((char *) &fragment_table
[i
], (char *) &sfragment
,
142 sizeof(squashfs_fragment_entry_3
));
146 *table_start
= fragment_table_index
[0];
151 static void read_fragment(unsigned int fragment
, long long *start_block
, int *size
)
153 TRACE("read_fragment: reading fragment %d\n", fragment
);
155 squashfs_fragment_entry_3
*fragment_entry
= &fragment_table
[fragment
];
156 *start_block
= fragment_entry
->start_block
;
157 *size
= fragment_entry
->size
;
161 static struct inode
*read_inode(unsigned int start_block
, unsigned int offset
)
163 static union squashfs_inode_header_3 header
;
164 long long start
= sBlk
.s
.inode_table_start
+ start_block
;
165 int bytes
= lookup_entry(inode_table_hash
, start
);
166 char *block_ptr
= inode_table
+ bytes
+ offset
;
167 static struct inode i
;
169 TRACE("read_inode: reading inode [%d:%d]\n", start_block
, offset
);
172 EXIT_UNSQUASH("read_inode: inode table block %lld not found\n",
176 squashfs_base_inode_header_3 sinode
;
177 memcpy(&sinode
, block_ptr
, sizeof(header
.base
));
178 SQUASHFS_SWAP_BASE_INODE_HEADER_3(&header
.base
, &sinode
,
179 sizeof(squashfs_base_inode_header_3
));
181 memcpy(&header
.base
, block_ptr
, sizeof(header
.base
));
183 i
.xattr
= SQUASHFS_INVALID_XATTR
;
184 i
.uid
= (uid_t
) uid_table
[header
.base
.uid
];
185 i
.gid
= header
.base
.guid
== SQUASHFS_GUIDS
? i
.uid
:
186 (uid_t
) guid_table
[header
.base
.guid
];
187 i
.mode
= lookup_type
[header
.base
.inode_type
] | header
.base
.mode
;
188 i
.type
= header
.base
.inode_type
;
189 i
.time
= header
.base
.mtime
;
190 i
.inode_number
= header
.base
.inode_number
;
192 switch(header
.base
.inode_type
) {
193 case SQUASHFS_DIR_TYPE
: {
194 squashfs_dir_inode_header_3
*inode
= &header
.dir
;
197 squashfs_dir_inode_header_3 sinode
;
198 memcpy(&sinode
, block_ptr
, sizeof(header
.dir
));
199 SQUASHFS_SWAP_DIR_INODE_HEADER_3(&header
.dir
,
202 memcpy(&header
.dir
, block_ptr
,
205 i
.data
= inode
->file_size
;
206 i
.offset
= inode
->offset
;
207 i
.start
= inode
->start_block
;
210 case SQUASHFS_LDIR_TYPE
: {
211 squashfs_ldir_inode_header_3
*inode
= &header
.ldir
;
214 squashfs_ldir_inode_header_3 sinode
;
215 memcpy(&sinode
, block_ptr
, sizeof(header
.ldir
));
216 SQUASHFS_SWAP_LDIR_INODE_HEADER_3(&header
.ldir
,
219 memcpy(&header
.ldir
, block_ptr
,
220 sizeof(header
.ldir
));
222 i
.data
= inode
->file_size
;
223 i
.offset
= inode
->offset
;
224 i
.start
= inode
->start_block
;
227 case SQUASHFS_FILE_TYPE
: {
228 squashfs_reg_inode_header_3
*inode
= &header
.reg
;
231 squashfs_reg_inode_header_3 sinode
;
232 memcpy(&sinode
, block_ptr
, sizeof(sinode
));
233 SQUASHFS_SWAP_REG_INODE_HEADER_3(inode
,
236 memcpy(inode
, block_ptr
, sizeof(*inode
));
238 i
.data
= inode
->file_size
;
239 i
.frag_bytes
= inode
->fragment
== SQUASHFS_INVALID_FRAG
240 ? 0 : inode
->file_size
% sBlk
.s
.block_size
;
241 i
.fragment
= inode
->fragment
;
242 i
.offset
= inode
->offset
;
243 i
.blocks
= inode
->fragment
== SQUASHFS_INVALID_FRAG
?
244 (i
.data
+ sBlk
.s
.block_size
- 1) >>
246 i
.data
>> sBlk
.s
.block_log
;
247 i
.start
= inode
->start_block
;
249 i
.block_ptr
= block_ptr
+ sizeof(*inode
);
252 case SQUASHFS_LREG_TYPE
: {
253 squashfs_lreg_inode_header_3
*inode
= &header
.lreg
;
256 squashfs_lreg_inode_header_3 sinode
;
257 memcpy(&sinode
, block_ptr
, sizeof(sinode
));
258 SQUASHFS_SWAP_LREG_INODE_HEADER_3(inode
,
261 memcpy(inode
, block_ptr
, sizeof(*inode
));
263 i
.data
= inode
->file_size
;
264 i
.frag_bytes
= inode
->fragment
== SQUASHFS_INVALID_FRAG
265 ? 0 : inode
->file_size
% sBlk
.s
.block_size
;
266 i
.fragment
= inode
->fragment
;
267 i
.offset
= inode
->offset
;
268 i
.blocks
= inode
->fragment
== SQUASHFS_INVALID_FRAG
?
269 (inode
->file_size
+ sBlk
.s
.block_size
- 1) >>
271 inode
->file_size
>> sBlk
.s
.block_log
;
272 i
.start
= inode
->start_block
;
274 i
.block_ptr
= block_ptr
+ sizeof(*inode
);
277 case SQUASHFS_SYMLINK_TYPE
: {
278 squashfs_symlink_inode_header_3
*inodep
=
282 squashfs_symlink_inode_header_3 sinodep
;
283 memcpy(&sinodep
, block_ptr
, sizeof(sinodep
));
284 SQUASHFS_SWAP_SYMLINK_INODE_HEADER_3(inodep
,
287 memcpy(inodep
, block_ptr
, sizeof(*inodep
));
289 i
.symlink
= malloc(inodep
->symlink_size
+ 1);
290 if(i
.symlink
== NULL
)
291 EXIT_UNSQUASH("read_inode: failed to malloc "
293 strncpy(i
.symlink
, block_ptr
+
294 sizeof(squashfs_symlink_inode_header_3
),
295 inodep
->symlink_size
);
296 i
.symlink
[inodep
->symlink_size
] = '\0';
297 i
.data
= inodep
->symlink_size
;
300 case SQUASHFS_BLKDEV_TYPE
:
301 case SQUASHFS_CHRDEV_TYPE
: {
302 squashfs_dev_inode_header_3
*inodep
= &header
.dev
;
305 squashfs_dev_inode_header_3 sinodep
;
306 memcpy(&sinodep
, block_ptr
, sizeof(sinodep
));
307 SQUASHFS_SWAP_DEV_INODE_HEADER_3(inodep
,
310 memcpy(inodep
, block_ptr
, sizeof(*inodep
));
312 i
.data
= inodep
->rdev
;
315 case SQUASHFS_FIFO_TYPE
:
316 case SQUASHFS_SOCKET_TYPE
:
320 EXIT_UNSQUASH("Unknown inode type %d in read_inode!\n",
321 header
.base
.inode_type
);
327 static struct dir
*squashfs_opendir(unsigned int block_start
, unsigned int offset
,
330 squashfs_dir_header_3 dirh
;
331 char buffer
[sizeof(squashfs_dir_entry_3
) + SQUASHFS_NAME_LEN
+ 1]
332 __attribute__((aligned
));
333 squashfs_dir_entry_3
*dire
= (squashfs_dir_entry_3
*) buffer
;
337 struct dir_ent
*new_dir
;
340 TRACE("squashfs_opendir: inode start block %d, offset %d\n",
341 block_start
, offset
);
343 *i
= read_inode(block_start
, offset
);
345 dir
= malloc(sizeof(struct dir
));
347 EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");
351 dir
->mode
= (*i
)->mode
;
352 dir
->uid
= (*i
)->uid
;
353 dir
->guid
= (*i
)->gid
;
354 dir
->mtime
= (*i
)->time
;
355 dir
->xattr
= (*i
)->xattr
;
360 * if the directory is empty, skip the unnecessary
361 * lookup_entry, this fixes the corner case with
362 * completely empty filesystems where lookup_entry correctly
363 * returning -1 is incorrectly treated as an error
367 start
= sBlk
.s
.directory_table_start
+ (*i
)->start
;
368 bytes
= lookup_entry(directory_table_hash
, start
);
371 EXIT_UNSQUASH("squashfs_opendir: directory block %d not "
372 "found!\n", block_start
);
374 bytes
+= (*i
)->offset
;
375 size
= (*i
)->data
+ bytes
- 3;
377 while(bytes
< size
) {
379 squashfs_dir_header_3 sdirh
;
380 memcpy(&sdirh
, directory_table
+ bytes
, sizeof(sdirh
));
381 SQUASHFS_SWAP_DIR_HEADER_3(&dirh
, &sdirh
);
383 memcpy(&dirh
, directory_table
+ bytes
, sizeof(dirh
));
385 dir_count
= dirh
.count
+ 1;
386 TRACE("squashfs_opendir: Read directory header @ byte position "
387 "%d, %d directory entries\n", bytes
, dir_count
);
388 bytes
+= sizeof(dirh
);
390 /* dir_count should never be larger than SQUASHFS_DIR_COUNT */
391 if(dir_count
> SQUASHFS_DIR_COUNT
) {
392 ERROR("File system corrupted: too many entries in directory\n");
398 squashfs_dir_entry_3 sdire
;
399 memcpy(&sdire
, directory_table
+ bytes
,
401 SQUASHFS_SWAP_DIR_ENTRY_3(dire
, &sdire
);
403 memcpy(dire
, directory_table
+ bytes
,
405 bytes
+= sizeof(*dire
);
407 /* size should never be SQUASHFS_NAME_LEN or larger */
408 if(dire
->size
>= SQUASHFS_NAME_LEN
) {
409 ERROR("File system corrupted: filename too long\n");
413 memcpy(dire
->name
, directory_table
+ bytes
,
415 dire
->name
[dire
->size
+ 1] = '\0';
416 TRACE("squashfs_opendir: directory entry %s, inode "
417 "%d:%d, type %d\n", dire
->name
,
418 dirh
.start_block
, dire
->offset
, dire
->type
);
419 if((dir
->dir_count
% DIR_ENT_SIZE
) == 0) {
420 new_dir
= realloc(dir
->dirs
, (dir
->dir_count
+
421 DIR_ENT_SIZE
) * sizeof(struct dir_ent
));
423 EXIT_UNSQUASH("squashfs_opendir: "
424 "realloc failed!\n");
427 strcpy(dir
->dirs
[dir
->dir_count
].name
, dire
->name
);
428 dir
->dirs
[dir
->dir_count
].start_block
=
430 dir
->dirs
[dir
->dir_count
].offset
= dire
->offset
;
431 dir
->dirs
[dir
->dir_count
].type
= dire
->type
;
433 bytes
+= dire
->size
+ 1;
446 static int parse_exports_table(long long *table_start
)
449 * Note on overflow limits:
450 * Size of SBlk.s.inodes is 2^32 (unsigned int)
451 * Max indexes is (2^32*8)/8K or 2^22
452 * Max length is ((2^32*8)/8K)*8 or 2^25
455 int indexes
= SQUASHFS_LOOKUP_BLOCKS_3((long long) sBlk
.s
.inodes
);
456 int length
= SQUASHFS_LOOKUP_BLOCK_BYTES_3((long long) sBlk
.s
.inodes
);
457 long long *export_index_table
;
460 * The size of the index table (length bytes) should match the
461 * table start and end points
463 if(length
!= (*table_start
- sBlk
.s
.lookup_table_start
)) {
464 ERROR("parse_exports_table: Bad inode count in super block\n");
468 export_index_table
= alloc_index_table(indexes
);
471 long long *sexport_index_table
= salloc_index_table(indexes
);
473 res
= read_fs_bytes(fd
, sBlk
.s
.lookup_table_start
,
474 length
, sexport_index_table
);
476 ERROR("parse_exorts_table: failed to read export "
480 SQUASHFS_SWAP_LOOKUP_BLOCKS_3(export_index_table
,
481 sexport_index_table
, indexes
);
483 res
= read_fs_bytes(fd
, sBlk
.s
.lookup_table_start
, length
,
486 ERROR("parse_exorts_table: failed to read export "
493 * export_index_table[0] stores the start of the compressed export blocks.
494 * This by definition is also the end of the previous filesystem
495 * table - the fragment table.
497 *table_start
= export_index_table
[0];
503 squashfs_operations
*read_filesystem_tables_3()
505 long long table_start
;
507 /* Read uid and gid lookup tables */
509 /* Sanity check super block contents */
511 if(sBlk
.guid_start
>= sBlk
.s
.bytes_used
) {
512 ERROR("read_filesystem_tables: gid start too large in super block\n");
516 if(read_ids(sBlk
.no_guids
, sBlk
.guid_start
, sBlk
.s
.bytes_used
, &guid_table
) == FALSE
)
519 table_start
= sBlk
.guid_start
;
521 /* no guids, guid_start should be 0 */
522 if(sBlk
.guid_start
!= 0) {
523 ERROR("read_filesystem_tables: gid start too large in super block\n");
527 table_start
= sBlk
.s
.bytes_used
;
530 if(sBlk
.uid_start
>= table_start
) {
531 ERROR("read_filesystem_tables: uid start too large in super block\n");
535 /* There should be at least one uid */
536 if(sBlk
.no_uids
== 0) {
537 ERROR("read_filesystem_tables: uid count bad in super block\n");
541 if(read_ids(sBlk
.no_uids
, sBlk
.uid_start
, table_start
, &uid_table
) == FALSE
)
544 table_start
= sBlk
.uid_start
;
546 /* Read exports table */
547 if(sBlk
.s
.lookup_table_start
!= SQUASHFS_INVALID_BLK
) {
549 /* sanity check super block contents */
550 if(sBlk
.s
.lookup_table_start
>= table_start
) {
551 ERROR("read_filesystem_tables: lookup table start too large in super block\n");
555 if(parse_exports_table(&table_start
) == FALSE
)
559 /* Read fragment table */
560 if(sBlk
.s
.fragments
!= 0) {
562 /* Sanity check super block contents */
563 if(sBlk
.s
.fragment_table_start
>= table_start
) {
564 ERROR("read_filesystem_tables: fragment table start too large in super block\n");
568 /* The number of fragments should not exceed the number of inodes */
569 if(sBlk
.s
.fragments
> sBlk
.s
.inodes
) {
570 ERROR("read_filesystem_tables: Bad fragment count in super block\n");
574 if(read_fragment_table(&table_start
) == FALSE
)
578 * Sanity check super block contents - with 0 fragments,
579 * the fragment table should be empty
581 if(sBlk
.s
.fragment_table_start
!= table_start
) {
582 ERROR("read_filesystem_tables: fragment table start invalid in super block\n");
587 /* Read directory table */
589 /* Sanity check super block contents */
590 if(sBlk
.s
.directory_table_start
> table_start
) {
591 ERROR("read_filesystem_tables: directory table start too large in super block\n");
595 directory_table
= read_directory_table(sBlk
.s
.directory_table_start
,
597 if(directory_table
== NULL
)
600 /* Read inode table */
602 /* Sanity check super block contents */
603 if(sBlk
.s
.inode_table_start
>= sBlk
.s
.directory_table_start
) {
604 ERROR("read_filesystem_tables: inode table start too large in super block\n");
608 inode_table
= read_inode_table(sBlk
.s
.inode_table_start
,
609 sBlk
.s
.directory_table_start
);
610 if(inode_table
== NULL
)
613 alloc_index_table(0);
614 salloc_index_table(0);
619 ERROR("File system corruption detected\n");
620 alloc_index_table(0);
621 salloc_index_table(0);
627 static squashfs_operations ops
= {
628 .opendir
= squashfs_opendir
,
629 .read_fragment
= read_fragment
,
630 .read_block_list
= read_block_list
,
631 .read_inode
= read_inode