2 * Read a squashfs filesystem. This is a highly compressed read only
5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
6 * 2012, 2013, 2014, 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.
29 #include <sys/types.h>
39 #define __BYTE_ORDER BYTE_ORDER
40 #define __BIG_ENDIAN BIG_ENDIAN
41 #define __LITTLE_ENDIAN LITTLE_ENDIAN
48 #include "squashfs_fs.h"
49 #include "squashfs_swap.h"
50 #include "compressor.h"
53 #include "mksquashfs.h"
55 int read_block(int fd
, long long start
, long long *next
, int expected
,
58 unsigned short c_byte
;
60 int outlen
= expected
? expected
: SQUASHFS_METADATA_SIZE
;
63 res
= read_fs_bytes(fd
, start
, 2, &c_byte
);
67 SQUASHFS_INSWAP_SHORTS(&c_byte
, 1);
68 compressed
= SQUASHFS_COMPRESSED(c_byte
);
69 c_byte
= SQUASHFS_COMPRESSED_SIZE(c_byte
);
72 * The block size should not be larger than
73 * the uncompressed size (or max uncompressed size if
83 res
= read_fs_bytes(fd
, start
+ 2, c_byte
, buffer
);
87 res
= compressor_uncompress(comp
, block
, buffer
, c_byte
,
90 ERROR("%s uncompress failed with error code %d\n",
95 res
= read_fs_bytes(fd
, start
+ 2, c_byte
, block
);
102 *next
= start
+ 2 + c_byte
;
105 * if expected, then check the (uncompressed) return data
106 * is of the expected size
108 if(expected
&& expected
!= res
)
115 #define NO_BYTES(SIZE) \
116 (bytes - (cur_ptr - inode_table) < (SIZE))
118 #define NO_INODE_BYTES(INODE) NO_BYTES(sizeof(struct INODE))
120 unsigned char *scan_inode_table(int fd
, long long start
, long long end
,
121 long long root_inode_start
, int root_inode_offset
,
122 struct squashfs_super_block
*sBlk
, union squashfs_inode_header
123 *dir_inode
, unsigned int *root_inode_block
, unsigned int
124 *root_inode_size
, long long *uncompressed_file
, unsigned int
125 *uncompressed_directory
, int *file_count
, int *sym_count
, int
126 *dev_count
, int *dir_count
, int *fifo_count
, int *sock_count
,
127 unsigned int *id_table
)
129 unsigned char *cur_ptr
;
130 unsigned char *inode_table
= NULL
;
132 unsigned int directory_start_block
, bytes
= 0, size
= 0;
133 struct squashfs_base_inode_header base
;
135 TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start "
136 "0x%llx\n", start
, end
, root_inode_start
);
138 *root_inode_block
= UINT_MAX
;
140 if(start
== root_inode_start
) {
141 TRACE("scan_inode_table: read compressed block 0x%llx "
142 "containing root inode\n", start
);
143 *root_inode_block
= bytes
;
145 if(size
- bytes
< SQUASHFS_METADATA_SIZE
) {
146 inode_table
= realloc(inode_table
, size
147 += SQUASHFS_METADATA_SIZE
);
148 if(inode_table
== NULL
)
151 TRACE("scan_inode_table: reading block 0x%llx\n", start
);
152 byte
= read_block(fd
, start
, &start
, 0, inode_table
+ bytes
);
158 /* If this is not the last metadata block in the inode table
159 * then it should be SQUASHFS_METADATA_SIZE in size.
160 * Note, we can't use expected in read_block() above for this
161 * because we don't know if this is the last block until
164 if(start
!= end
&& byte
!= SQUASHFS_METADATA_SIZE
)
169 * We expect to have found the metadata block containing the
170 * root inode in the above inode_table metadata block scan. If it
171 * hasn't been found then the filesystem is corrupted
173 if(*root_inode_block
== UINT_MAX
)
177 * The number of bytes available after the root inode medata block
178 * should be at least the root inode offset + the size of a
179 * regular directory inode, if not the filesystem is corrupted
181 * +-----------------------+-----------------------+
184 * +-----------------------+-----------------------+
186 * *root_inode_block root_inode_offset bytes
188 if((bytes
- *root_inode_block
) < (root_inode_offset
+
189 sizeof(struct squashfs_dir_inode_header
)))
193 * Read last inode entry which is the root directory inode, and obtain
194 * the last directory start block index. This is used when calculating
195 * the total uncompressed directory size. The directory bytes in the
196 * last * block will be counted as normal.
198 * Note, the previous check ensures the following calculation won't
199 * underflow, and we won't access beyond the buffer
201 *root_inode_size
= bytes
- (*root_inode_block
+ root_inode_offset
);
202 bytes
= *root_inode_block
+ root_inode_offset
;
203 SQUASHFS_SWAP_DIR_INODE_HEADER(inode_table
+ bytes
, &dir_inode
->dir
);
205 if(dir_inode
->base
.inode_type
== SQUASHFS_DIR_TYPE
)
206 directory_start_block
= dir_inode
->dir
.start_block
;
207 else if(dir_inode
->base
.inode_type
== SQUASHFS_LDIR_TYPE
) {
208 if(*root_inode_size
< sizeof(struct squashfs_ldir_inode_header
))
209 /* corrupted filesystem */
211 SQUASHFS_SWAP_LDIR_INODE_HEADER(inode_table
+ bytes
,
213 directory_start_block
= dir_inode
->ldir
.start_block
;
215 /* bad type, corrupted filesystem */
218 get_uid(id_table
[dir_inode
->base
.uid
]);
219 get_guid(id_table
[dir_inode
->base
.guid
]);
221 /* allocate fragment to file mapping table */
222 file_mapping
= calloc(sBlk
->fragments
, sizeof(struct append_file
*));
223 if(file_mapping
== NULL
)
226 for(cur_ptr
= inode_table
; cur_ptr
< inode_table
+ bytes
; files
++) {
227 if(NO_INODE_BYTES(squashfs_base_inode_header
))
228 /* corrupted filesystem */
231 SQUASHFS_SWAP_BASE_INODE_HEADER(cur_ptr
, &base
);
233 TRACE("scan_inode_table: processing inode @ byte position "
235 (unsigned int) (cur_ptr
- inode_table
),
238 get_uid(id_table
[base
.uid
]);
239 get_guid(id_table
[base
.guid
]);
241 switch(base
.inode_type
) {
242 case SQUASHFS_FILE_TYPE
: {
243 struct squashfs_reg_inode_header inode
;
244 int frag_bytes
, blocks
, i
;
245 long long start
, file_bytes
= 0;
246 unsigned int *block_list
;
248 if(NO_INODE_BYTES(squashfs_reg_inode_header
))
249 /* corrupted filesystem */
252 SQUASHFS_SWAP_REG_INODE_HEADER(cur_ptr
, &inode
);
254 frag_bytes
= inode
.fragment
== SQUASHFS_INVALID_FRAG
?
255 0 : inode
.file_size
% sBlk
->block_size
;
256 blocks
= inode
.fragment
== SQUASHFS_INVALID_FRAG
?
257 (inode
.file_size
+ sBlk
->block_size
- 1) >>
258 sBlk
->block_log
: inode
.file_size
>>
260 start
= inode
.start_block
;
262 TRACE("scan_inode_table: regular file, file_size %d, "
263 "blocks %d\n", inode
.file_size
, blocks
);
265 if(NO_BYTES(blocks
* sizeof(unsigned int)))
266 /* corrupted filesystem */
269 block_list
= malloc(blocks
* sizeof(unsigned int));
270 if(block_list
== NULL
)
273 cur_ptr
+= sizeof(inode
);
274 SQUASHFS_SWAP_INTS(cur_ptr
, block_list
, blocks
);
276 *uncompressed_file
+= inode
.file_size
;
279 for(i
= 0; i
< blocks
; i
++)
281 SQUASHFS_COMPRESSED_SIZE_BLOCK
284 if(inode
.fragment
!= SQUASHFS_INVALID_FRAG
&&
285 inode
.fragment
>= sBlk
->fragments
) {
290 add_file(start
, inode
.file_size
, file_bytes
,
291 block_list
, blocks
, inode
.fragment
,
292 inode
.offset
, frag_bytes
);
294 cur_ptr
+= blocks
* sizeof(unsigned int);
297 case SQUASHFS_LREG_TYPE
: {
298 struct squashfs_lreg_inode_header inode
;
299 int frag_bytes
, blocks
, i
;
300 long long start
, file_bytes
= 0;
301 unsigned int *block_list
;
303 if(NO_INODE_BYTES(squashfs_lreg_inode_header
))
304 /* corrupted filesystem */
307 SQUASHFS_SWAP_LREG_INODE_HEADER(cur_ptr
, &inode
);
309 frag_bytes
= inode
.fragment
== SQUASHFS_INVALID_FRAG
?
310 0 : inode
.file_size
% sBlk
->block_size
;
311 blocks
= inode
.fragment
== SQUASHFS_INVALID_FRAG
?
312 (inode
.file_size
+ sBlk
->block_size
- 1) >>
313 sBlk
->block_log
: inode
.file_size
>>
315 start
= inode
.start_block
;
317 TRACE("scan_inode_table: extended regular "
318 "file, file_size %lld, blocks %d\n",
319 inode
.file_size
, blocks
);
321 if(NO_BYTES(blocks
* sizeof(unsigned int)))
322 /* corrupted filesystem */
325 block_list
= malloc(blocks
* sizeof(unsigned int));
326 if(block_list
== NULL
)
329 cur_ptr
+= sizeof(inode
);
330 SQUASHFS_SWAP_INTS(cur_ptr
, block_list
, blocks
);
332 *uncompressed_file
+= inode
.file_size
;
335 for(i
= 0; i
< blocks
; i
++)
337 SQUASHFS_COMPRESSED_SIZE_BLOCK
340 if(inode
.fragment
!= SQUASHFS_INVALID_FRAG
&&
341 inode
.fragment
>= sBlk
->fragments
) {
346 add_file(start
, inode
.file_size
, file_bytes
,
347 block_list
, blocks
, inode
.fragment
,
348 inode
.offset
, frag_bytes
);
350 cur_ptr
+= blocks
* sizeof(unsigned int);
353 case SQUASHFS_SYMLINK_TYPE
:
354 case SQUASHFS_LSYMLINK_TYPE
: {
355 struct squashfs_symlink_inode_header inode
;
357 if(NO_INODE_BYTES(squashfs_symlink_inode_header
))
358 /* corrupted filesystem */
361 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(cur_ptr
, &inode
);
365 if (inode
.inode_type
== SQUASHFS_LSYMLINK_TYPE
) {
366 if(NO_BYTES(inode
.symlink_size
+
367 sizeof(unsigned int)))
368 /* corrupted filesystem */
370 cur_ptr
+= sizeof(inode
) + inode
.symlink_size
+
371 sizeof(unsigned int);
373 if(NO_BYTES(inode
.symlink_size
))
374 /* corrupted filesystem */
376 cur_ptr
+= sizeof(inode
) + inode
.symlink_size
;
380 case SQUASHFS_DIR_TYPE
: {
381 struct squashfs_dir_inode_header dir_inode
;
383 if(NO_INODE_BYTES(squashfs_dir_inode_header
))
384 /* corrupted filesystem */
387 SQUASHFS_SWAP_DIR_INODE_HEADER(cur_ptr
, &dir_inode
);
389 if(dir_inode
.start_block
< directory_start_block
)
390 *uncompressed_directory
+= dir_inode
.file_size
;
393 cur_ptr
+= sizeof(struct squashfs_dir_inode_header
);
396 case SQUASHFS_LDIR_TYPE
: {
397 struct squashfs_ldir_inode_header dir_inode
;
400 if(NO_INODE_BYTES(squashfs_ldir_inode_header
))
401 /* corrupted filesystem */
404 SQUASHFS_SWAP_LDIR_INODE_HEADER(cur_ptr
, &dir_inode
);
406 if(dir_inode
.start_block
< directory_start_block
)
407 *uncompressed_directory
+= dir_inode
.file_size
;
410 cur_ptr
+= sizeof(struct squashfs_ldir_inode_header
);
412 for(i
= 0; i
< dir_inode
.i_count
; i
++) {
413 struct squashfs_dir_index index
;
415 if(NO_BYTES(sizeof(index
)))
416 /* corrupted filesystem */
419 SQUASHFS_SWAP_DIR_INDEX(cur_ptr
, &index
);
421 if(NO_BYTES(index
.size
+ 1))
422 /* corrupted filesystem */
425 cur_ptr
+= sizeof(index
) + index
.size
+ 1;
429 case SQUASHFS_BLKDEV_TYPE
:
430 case SQUASHFS_CHRDEV_TYPE
:
431 if(NO_INODE_BYTES(squashfs_dev_inode_header
))
432 /* corrupted filesystem */
436 cur_ptr
+= sizeof(struct squashfs_dev_inode_header
);
438 case SQUASHFS_LBLKDEV_TYPE
:
439 case SQUASHFS_LCHRDEV_TYPE
:
440 if(NO_INODE_BYTES(squashfs_ldev_inode_header
))
441 /* corrupted filesystem */
445 cur_ptr
+= sizeof(struct squashfs_ldev_inode_header
);
447 case SQUASHFS_FIFO_TYPE
:
448 if(NO_INODE_BYTES(squashfs_ipc_inode_header
))
449 /* corrupted filesystem */
453 cur_ptr
+= sizeof(struct squashfs_ipc_inode_header
);
455 case SQUASHFS_LFIFO_TYPE
:
456 if(NO_INODE_BYTES(squashfs_lipc_inode_header
))
457 /* corrupted filesystem */
461 cur_ptr
+= sizeof(struct squashfs_lipc_inode_header
);
463 case SQUASHFS_SOCKET_TYPE
:
464 if(NO_INODE_BYTES(squashfs_ipc_inode_header
))
465 /* corrupted filesystem */
469 cur_ptr
+= sizeof(struct squashfs_ipc_inode_header
);
471 case SQUASHFS_LSOCKET_TYPE
:
472 if(NO_INODE_BYTES(squashfs_lipc_inode_header
))
473 /* corrupted filesystem */
477 cur_ptr
+= sizeof(struct squashfs_lipc_inode_header
);
480 ERROR("Unknown inode type %d in scan_inode_table!\n",
486 printf("Read existing filesystem, %d inodes scanned\n", files
);
490 ERROR("scan_inode_table: filesystem corruption detected in "
491 "scanning metadata\n");
497 struct compressor
*read_super(int fd
, struct squashfs_super_block
*sBlk
, char *source
)
500 char buffer
[SQUASHFS_METADATA_SIZE
] __attribute__ ((aligned
));
502 res
= read_fs_bytes(fd
, SQUASHFS_START
, sizeof(struct squashfs_super_block
),
505 ERROR("Can't find a SQUASHFS superblock on %s\n",
507 ERROR("Wrong filesystem or filesystem is corrupted!\n");
511 SQUASHFS_INSWAP_SUPER_BLOCK(sBlk
);
513 if(sBlk
->s_magic
!= SQUASHFS_MAGIC
) {
514 if(sBlk
->s_magic
== SQUASHFS_MAGIC_SWAP
)
515 ERROR("Pre 4.0 big-endian filesystem on %s, appending"
516 " to this is unsupported\n", source
);
518 ERROR("Can't find a SQUASHFS superblock on %s\n",
520 ERROR("Wrong filesystem or filesystem is corrupted!\n");
525 /* Check the MAJOR & MINOR versions */
526 if(sBlk
->s_major
!= SQUASHFS_MAJOR
|| sBlk
->s_minor
> SQUASHFS_MINOR
) {
527 if(sBlk
->s_major
< 4)
528 ERROR("Filesystem on %s is a SQUASHFS %d.%d filesystem."
529 " Appending\nto SQUASHFS %d.%d filesystems is "
530 "not supported. Please convert it to a "
531 "SQUASHFS 4 filesystem\n", source
,
533 sBlk
->s_minor
, sBlk
->s_major
, sBlk
->s_minor
);
535 ERROR("Filesystem on %s is %d.%d, which is a later "
536 "filesystem version than I support\n",
537 source
, sBlk
->s_major
, sBlk
->s_minor
);
541 /* Check the compression type */
542 comp
= lookup_compressor_id(sBlk
->compression
);
543 if(!comp
->supported
) {
544 ERROR("Filesystem on %s uses %s compression, this is "
545 "unsupported by this version\n", source
, comp
->name
);
546 ERROR("Compressors available:\n");
547 display_compressors("", "");
552 * Read extended superblock information from disk.
554 * Read compressor specific options from disk if present, and pass
555 * to compressor to set compressor options.
557 * Note, if there's no compressor options present, the compressor
558 * is still called to set the default options (the defaults may have
559 * been changed by the user specifying options on the command
560 * line which need to be over-ridden).
562 * Compressor_extract_options is also used to ensure that
563 * we know how decompress a filesystem compressed with these
564 * compression options.
566 if(SQUASHFS_COMP_OPTS(sBlk
->flags
)) {
567 bytes
= read_block(fd
, sizeof(*sBlk
), NULL
, 0, buffer
);
570 ERROR("Failed to read compressor options from append "
572 ERROR("Filesystem corrupted?\n");
577 res
= compressor_extract_options(comp
, sBlk
->block_size
, buffer
, bytes
);
579 ERROR("Compressor failed to set compressor options\n");
583 printf("Found a valid %sSQUASHFS superblock on %s.\n",
584 SQUASHFS_EXPORTABLE(sBlk
->flags
) ? "exportable " : "", source
);
585 printf("\tCompression used %s\n", comp
->name
);
586 printf("\tInodes are %scompressed\n",
587 SQUASHFS_UNCOMPRESSED_INODES(sBlk
->flags
) ? "un" : "");
588 printf("\tData is %scompressed\n",
589 SQUASHFS_UNCOMPRESSED_DATA(sBlk
->flags
) ? "un" : "");
590 printf("\tFragments are %scompressed\n",
591 SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk
->flags
) ? "un" : "");
592 printf("\tXattrs are %scompressed\n",
593 SQUASHFS_UNCOMPRESSED_XATTRS(sBlk
->flags
) ? "un" : "");
594 printf("\tFragments are %spresent in the filesystem\n",
595 SQUASHFS_NO_FRAGMENTS(sBlk
->flags
) ? "not " : "");
596 printf("\tAlways-use-fragments option is %sspecified\n",
597 SQUASHFS_ALWAYS_FRAGMENTS(sBlk
->flags
) ? "" : "not ");
598 printf("\tDuplicates are %sremoved\n",
599 SQUASHFS_DUPLICATES(sBlk
->flags
) ? "" : "not ");
600 printf("\tXattrs are %sstored\n",
601 SQUASHFS_NO_XATTRS(sBlk
->flags
) ? "not " : "");
602 printf("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n",
603 sBlk
->bytes_used
/ 1024.0, sBlk
->bytes_used
604 / (1024.0 * 1024.0));
605 printf("\tBlock size %d\n", sBlk
->block_size
);
606 printf("\tNumber of fragments %d\n", sBlk
->fragments
);
607 printf("\tNumber of inodes %d\n", sBlk
->inodes
);
608 printf("\tNumber of ids %d\n", sBlk
->no_ids
);
609 TRACE("sBlk->inode_table_start %llx\n", sBlk
->inode_table_start
);
610 TRACE("sBlk->directory_table_start %llx\n",
611 sBlk
->directory_table_start
);
612 TRACE("sBlk->id_table_start %llx\n", sBlk
->id_table_start
);
613 TRACE("sBlk->fragment_table_start %llx\n", sBlk
->fragment_table_start
);
614 TRACE("sBlk->lookup_table_start %llx\n", sBlk
->lookup_table_start
);
615 TRACE("sBlk->xattr_id_table_start %llx\n", sBlk
->xattr_id_table_start
);
625 unsigned char *squashfs_readdir(int fd
, int root_entries
,
626 unsigned int directory_start_block
, int offset
, int size
,
627 unsigned int *last_directory_block
, struct squashfs_super_block
*sBlk
,
628 void (push_directory_entry
)(char *, squashfs_inode
, int, int))
630 struct squashfs_dir_header dirh
;
631 char buffer
[sizeof(struct squashfs_dir_entry
) + SQUASHFS_NAME_LEN
+ 1]
632 __attribute__ ((aligned
));
633 struct squashfs_dir_entry
*dire
= (struct squashfs_dir_entry
*) buffer
;
634 unsigned char *directory_table
= NULL
;
635 int byte
, bytes
= 0, dir_count
;
636 long long start
= sBlk
->directory_table_start
+ directory_start_block
,
637 last_start_block
= start
;
640 directory_table
= malloc((size
+ SQUASHFS_METADATA_SIZE
* 2 - 1) &
641 ~(SQUASHFS_METADATA_SIZE
- 1));
642 if(directory_table
== NULL
)
645 while(bytes
< size
) {
646 int expected
= (size
- bytes
) >= SQUASHFS_METADATA_SIZE
?
647 SQUASHFS_METADATA_SIZE
: 0;
649 TRACE("squashfs_readdir: reading block 0x%llx, bytes read so "
650 "far %d\n", start
, bytes
);
652 last_start_block
= start
;
653 byte
= read_block(fd
, start
, &start
, expected
, directory_table
+ bytes
);
655 ERROR("Failed to read directory\n");
656 ERROR("Filesystem corrupted?\n");
657 free(directory_table
);
667 while(bytes
< size
) {
668 SQUASHFS_SWAP_DIR_HEADER(directory_table
+ bytes
, &dirh
);
670 dir_count
= dirh
.count
+ 1;
672 /* dir_count should never be larger than SQUASHFS_DIR_COUNT */
673 if(dir_count
> SQUASHFS_DIR_COUNT
) {
674 ERROR("File system corrupted: too many entries in directory\n");
675 free(directory_table
);
679 TRACE("squashfs_readdir: Read directory header @ byte position "
680 "0x%x, 0x%x directory entries\n", bytes
, dir_count
);
681 bytes
+= sizeof(dirh
);
684 SQUASHFS_SWAP_DIR_ENTRY(directory_table
+ bytes
, dire
);
685 bytes
+= sizeof(*dire
);
687 /* size should never be SQUASHFS_NAME_LEN or larger */
688 if(dire
->size
>= SQUASHFS_NAME_LEN
) {
689 ERROR("File system corrupted: filename too long\n");
690 free(directory_table
);
694 memcpy(dire
->name
, directory_table
+ bytes
,
696 dire
->name
[dire
->size
+ 1] = '\0';
697 TRACE("squashfs_readdir: pushing directory entry %s, "
698 "inode %x:%x, type 0x%x\n", dire
->name
,
699 dirh
.start_block
, dire
->offset
, dire
->type
);
700 push_directory_entry(dire
->name
,
701 SQUASHFS_MKINODE(dirh
.start_block
,
702 dire
->offset
), dirh
.inode_number
+
703 dire
->inode_number
, dire
->type
);
704 bytes
+= dire
->size
+ 1;
709 *last_directory_block
= (unsigned int) last_start_block
-
710 sBlk
->directory_table_start
;
711 return directory_table
;
715 unsigned int *read_id_table(int fd
, struct squashfs_super_block
*sBlk
)
717 int indexes
= SQUASHFS_ID_BLOCKS(sBlk
->no_ids
);
718 long long index
[indexes
];
719 int bytes
= SQUASHFS_ID_BYTES(sBlk
->no_ids
);
720 unsigned int *id_table
;
723 id_table
= malloc(bytes
);
727 res
= read_fs_bytes(fd
, sBlk
->id_table_start
,
728 SQUASHFS_ID_BLOCK_BYTES(sBlk
->no_ids
), index
);
730 ERROR("Failed to read id table index\n");
731 ERROR("Filesystem corrupted?\n");
736 SQUASHFS_INSWAP_ID_BLOCKS(index
, indexes
);
738 for(i
= 0; i
< indexes
; i
++) {
739 int expected
= (i
+ 1) != indexes
? SQUASHFS_METADATA_SIZE
:
740 bytes
& (SQUASHFS_METADATA_SIZE
- 1);
741 int length
= read_block(fd
, index
[i
], NULL
, expected
,
742 ((unsigned char *) id_table
) +
743 (i
* SQUASHFS_METADATA_SIZE
));
744 TRACE("Read id table block %d, from 0x%llx, length %d\n", i
,
747 ERROR("Failed to read id table block %d, from 0x%llx, "
748 "length %d\n", i
, index
[i
], length
);
749 ERROR("Filesystem corrupted?\n");
755 SQUASHFS_INSWAP_INTS(id_table
, sBlk
->no_ids
);
757 for(i
= 0; i
< sBlk
->no_ids
; i
++) {
758 TRACE("Adding id %d to id tables\n", id_table
[i
]);
759 create_id(id_table
[i
]);
766 struct squashfs_fragment_entry
*read_fragment_table(int fd
, struct squashfs_super_block
*sBlk
)
769 int bytes
= SQUASHFS_FRAGMENT_BYTES(sBlk
->fragments
);
770 int indexes
= SQUASHFS_FRAGMENT_INDEXES(sBlk
->fragments
);
771 long long fragment_table_index
[indexes
];
772 struct squashfs_fragment_entry
*fragment_table
;
774 TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
775 "from 0x%llx\n", sBlk
->fragments
, indexes
,
776 sBlk
->fragment_table_start
);
778 fragment_table
= malloc(bytes
);
779 if(fragment_table
== NULL
)
782 res
= read_fs_bytes(fd
, sBlk
->fragment_table_start
,
783 SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk
->fragments
),
784 fragment_table_index
);
786 ERROR("Failed to read fragment table index\n");
787 ERROR("Filesystem corrupted?\n");
788 free(fragment_table
);
792 SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index
, indexes
);
794 for(i
= 0; i
< indexes
; i
++) {
795 int expected
= (i
+ 1) != indexes
? SQUASHFS_METADATA_SIZE
:
796 bytes
& (SQUASHFS_METADATA_SIZE
- 1);
797 int length
= read_block(fd
, fragment_table_index
[i
], NULL
,
798 expected
, ((unsigned char *) fragment_table
) +
799 (i
* SQUASHFS_METADATA_SIZE
));
800 TRACE("Read fragment table block %d, from 0x%llx, length %d\n",
801 i
, fragment_table_index
[i
], length
);
803 ERROR("Failed to read fragment table block %d, from "
804 "0x%llx, length %d\n", i
,
805 fragment_table_index
[i
], length
);
806 ERROR("Filesystem corrupted?\n");
807 free(fragment_table
);
812 for(i
= 0; i
< sBlk
->fragments
; i
++)
813 SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table
[i
]);
815 return fragment_table
;
819 squashfs_inode
*read_inode_lookup_table(int fd
, struct squashfs_super_block
*sBlk
)
821 int lookup_bytes
= SQUASHFS_LOOKUP_BYTES(sBlk
->inodes
);
822 int indexes
= SQUASHFS_LOOKUP_BLOCKS(sBlk
->inodes
);
823 long long index
[indexes
];
825 squashfs_inode
*inode_lookup_table
;
827 inode_lookup_table
= malloc(lookup_bytes
);
828 if(inode_lookup_table
== NULL
)
831 res
= read_fs_bytes(fd
, sBlk
->lookup_table_start
,
832 SQUASHFS_LOOKUP_BLOCK_BYTES(sBlk
->inodes
), index
);
834 ERROR("Failed to read inode lookup table index\n");
835 ERROR("Filesystem corrupted?\n");
836 free(inode_lookup_table
);
840 SQUASHFS_INSWAP_LONG_LONGS(index
, indexes
);
842 for(i
= 0; i
< indexes
; i
++) {
843 int expected
= (i
+ 1) != indexes
? SQUASHFS_METADATA_SIZE
:
844 lookup_bytes
& (SQUASHFS_METADATA_SIZE
- 1);
845 int length
= read_block(fd
, index
[i
], NULL
, expected
,
846 ((unsigned char *) inode_lookup_table
) +
847 (i
* SQUASHFS_METADATA_SIZE
));
848 TRACE("Read inode lookup table block %d, from 0x%llx, length "
849 "%d\n", i
, index
[i
], length
);
851 ERROR("Failed to read inode lookup table block %d, "
852 "from 0x%llx, length %d\n", i
, index
[i
],
854 ERROR("Filesystem corrupted?\n");
855 free(inode_lookup_table
);
860 SQUASHFS_INSWAP_LONG_LONGS(inode_lookup_table
, sBlk
->inodes
);
862 return inode_lookup_table
;
866 long long read_filesystem(char *root_name
, int fd
, struct squashfs_super_block
*sBlk
,
867 char **cinode_table
, char **data_cache
, char **cdirectory_table
,
868 char **directory_data_cache
, unsigned int *last_directory_block
,
869 unsigned int *inode_dir_offset
, unsigned int *inode_dir_file_size
,
870 unsigned int *root_inode_size
, unsigned int *inode_dir_start_block
,
871 int *file_count
, int *sym_count
, int *dev_count
, int *dir_count
,
872 int *fifo_count
, int *sock_count
, long long *uncompressed_file
,
873 unsigned int *uncompressed_inode
, unsigned int *uncompressed_directory
,
874 unsigned int *inode_dir_inode_number
,
875 unsigned int *inode_dir_parent_inode
,
876 void (push_directory_entry
)(char *, squashfs_inode
, int, int),
877 struct squashfs_fragment_entry
**fragment_table
,
878 squashfs_inode
**inode_lookup_table
)
880 unsigned char *inode_table
= NULL
, *directory_table
= NULL
;
881 long long start
= sBlk
->inode_table_start
;
882 long long end
= sBlk
->directory_table_start
;
883 long long root_inode_start
= start
+
884 SQUASHFS_INODE_BLK(sBlk
->root_inode
);
885 unsigned int root_inode_offset
=
886 SQUASHFS_INODE_OFFSET(sBlk
->root_inode
);
887 unsigned int root_inode_block
;
888 union squashfs_inode_header inode
;
889 unsigned int *id_table
= NULL
;
892 printf("Scanning existing filesystem...\n");
894 if(get_xattrs(fd
, sBlk
) == 0)
897 if(sBlk
->fragments
> 0) {
898 *fragment_table
= read_fragment_table(fd
, sBlk
);
899 if(*fragment_table
== NULL
)
903 if(sBlk
->lookup_table_start
!= SQUASHFS_INVALID_BLK
) {
904 *inode_lookup_table
= read_inode_lookup_table(fd
, sBlk
);
905 if(*inode_lookup_table
== NULL
)
909 id_table
= read_id_table(fd
, sBlk
);
913 inode_table
= scan_inode_table(fd
, start
, end
, root_inode_start
,
914 root_inode_offset
, sBlk
, &inode
, &root_inode_block
,
915 root_inode_size
, uncompressed_file
, uncompressed_directory
,
916 file_count
, sym_count
, dev_count
, dir_count
, fifo_count
,
917 sock_count
, id_table
);
918 if(inode_table
== NULL
)
921 *uncompressed_inode
= root_inode_block
;
923 if(inode
.base
.inode_type
== SQUASHFS_DIR_TYPE
||
924 inode
.base
.inode_type
== SQUASHFS_LDIR_TYPE
) {
925 if(inode
.base
.inode_type
== SQUASHFS_DIR_TYPE
) {
926 *inode_dir_start_block
= inode
.dir
.start_block
;
927 *inode_dir_offset
= inode
.dir
.offset
;
928 *inode_dir_file_size
= inode
.dir
.file_size
- 3;
929 *inode_dir_inode_number
= inode
.dir
.inode_number
;
930 *inode_dir_parent_inode
= inode
.dir
.parent_inode
;
932 *inode_dir_start_block
= inode
.ldir
.start_block
;
933 *inode_dir_offset
= inode
.ldir
.offset
;
934 *inode_dir_file_size
= inode
.ldir
.file_size
- 3;
935 *inode_dir_inode_number
= inode
.ldir
.inode_number
;
936 *inode_dir_parent_inode
= inode
.ldir
.parent_inode
;
939 directory_table
= squashfs_readdir(fd
, !root_name
,
940 *inode_dir_start_block
, *inode_dir_offset
,
941 *inode_dir_file_size
, last_directory_block
, sBlk
,
942 push_directory_entry
);
943 if(directory_table
== NULL
)
946 root_inode_start
-= start
;
947 *cinode_table
= malloc(root_inode_start
);
948 if(*cinode_table
== NULL
)
951 res
= read_fs_bytes(fd
, start
, root_inode_start
, *cinode_table
);
953 ERROR("Failed to read inode table\n");
954 ERROR("Filesystem corrupted?\n");
958 *cdirectory_table
= malloc(*last_directory_block
);
959 if(*cdirectory_table
== NULL
)
962 res
= read_fs_bytes(fd
, sBlk
->directory_table_start
,
963 *last_directory_block
, *cdirectory_table
);
965 ERROR("Failed to read directory table\n");
966 ERROR("Filesystem corrupted?\n");
970 *data_cache
= malloc(root_inode_offset
+ *root_inode_size
);
971 if(*data_cache
== NULL
)
974 memcpy(*data_cache
, inode_table
+ root_inode_block
,
975 root_inode_offset
+ *root_inode_size
);
977 *directory_data_cache
= malloc(*inode_dir_offset
+
978 *inode_dir_file_size
);
979 if(*directory_data_cache
== NULL
)
982 memcpy(*directory_data_cache
, directory_table
,
983 *inode_dir_offset
+ *inode_dir_file_size
);
987 free(directory_table
);
988 return sBlk
->inode_table_start
;
994 free(directory_table
);