]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - SQUASHFS/squashfs-tools-4.4/squashfs-tools/read_fs.c
1.1.07 release
[Ventoy.git] / SQUASHFS / squashfs-tools-4.4 / squashfs-tools / read_fs.c
1 /*
2 * Read a squashfs filesystem. This is a highly compressed read only
3 * filesystem.
4 *
5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
6 * 2012, 2013, 2014, 2019
7 * Phillip Lougher <phillip@squashfs.org.uk>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2,
12 * or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 * read_fs.c
24 */
25
26 #define TRUE 1
27 #define FALSE 0
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <sys/mman.h>
35 #include <limits.h>
36 #include <dirent.h>
37
38 #ifndef linux
39 #define __BYTE_ORDER BYTE_ORDER
40 #define __BIG_ENDIAN BIG_ENDIAN
41 #define __LITTLE_ENDIAN LITTLE_ENDIAN
42 #else
43 #include <endian.h>
44 #endif
45
46 #include <stdlib.h>
47
48 #include "squashfs_fs.h"
49 #include "squashfs_swap.h"
50 #include "compressor.h"
51 #include "xattr.h"
52 #include "error.h"
53 #include "mksquashfs.h"
54
55 int read_block(int fd, long long start, long long *next, int expected,
56 void *block)
57 {
58 unsigned short c_byte;
59 int res, compressed;
60 int outlen = expected ? expected : SQUASHFS_METADATA_SIZE;
61
62 /* Read block size */
63 res = read_fs_bytes(fd, start, 2, &c_byte);
64 if(res == 0)
65 return 0;
66
67 SQUASHFS_INSWAP_SHORTS(&c_byte, 1);
68 compressed = SQUASHFS_COMPRESSED(c_byte);
69 c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
70
71 /*
72 * The block size should not be larger than
73 * the uncompressed size (or max uncompressed size if
74 * expected is 0)
75 */
76 if (c_byte > outlen)
77 return 0;
78
79 if(compressed) {
80 char buffer[c_byte];
81 int error;
82
83 res = read_fs_bytes(fd, start + 2, c_byte, buffer);
84 if(res == 0)
85 return 0;
86
87 res = compressor_uncompress(comp, block, buffer, c_byte,
88 outlen, &error);
89 if(res == -1) {
90 ERROR("%s uncompress failed with error code %d\n",
91 comp->name, error);
92 return 0;
93 }
94 } else {
95 res = read_fs_bytes(fd, start + 2, c_byte, block);
96 if(res == 0)
97 return 0;
98 res = c_byte;
99 }
100
101 if(next)
102 *next = start + 2 + c_byte;
103
104 /*
105 * if expected, then check the (uncompressed) return data
106 * is of the expected size
107 */
108 if(expected && expected != res)
109 return 0;
110 else
111 return res;
112 }
113
114
115 #define NO_BYTES(SIZE) \
116 (bytes - (cur_ptr - inode_table) < (SIZE))
117
118 #define NO_INODE_BYTES(INODE) NO_BYTES(sizeof(struct INODE))
119
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)
128 {
129 unsigned char *cur_ptr;
130 unsigned char *inode_table = NULL;
131 int byte, files = 0;
132 unsigned int directory_start_block, bytes = 0, size = 0;
133 struct squashfs_base_inode_header base;
134
135 TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start "
136 "0x%llx\n", start, end, root_inode_start);
137
138 *root_inode_block = UINT_MAX;
139 while(start < end) {
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;
144 }
145 if(size - bytes < SQUASHFS_METADATA_SIZE) {
146 inode_table = realloc(inode_table, size
147 += SQUASHFS_METADATA_SIZE);
148 if(inode_table == NULL)
149 MEM_ERROR();
150 }
151 TRACE("scan_inode_table: reading block 0x%llx\n", start);
152 byte = read_block(fd, start, &start, 0, inode_table + bytes);
153 if(byte == 0)
154 goto corrupted;
155
156 bytes += byte;
157
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
162 * after reading.
163 */
164 if(start != end && byte != SQUASHFS_METADATA_SIZE)
165 goto corrupted;
166 }
167
168 /*
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
172 */
173 if(*root_inode_block == UINT_MAX)
174 goto corrupted;
175
176 /*
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
180 *
181 * +-----------------------+-----------------------+
182 * | | directory |
183 * | | inode |
184 * +-----------------------+-----------------------+
185 * ^ ^ ^
186 * *root_inode_block root_inode_offset bytes
187 */
188 if((bytes - *root_inode_block) < (root_inode_offset +
189 sizeof(struct squashfs_dir_inode_header)))
190 goto corrupted;
191
192 /*
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.
197 *
198 * Note, the previous check ensures the following calculation won't
199 * underflow, and we won't access beyond the buffer
200 */
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);
204
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 */
210 goto corrupted;
211 SQUASHFS_SWAP_LDIR_INODE_HEADER(inode_table + bytes,
212 &dir_inode->ldir);
213 directory_start_block = dir_inode->ldir.start_block;
214 } else
215 /* bad type, corrupted filesystem */
216 goto corrupted;
217
218 get_uid(id_table[dir_inode->base.uid]);
219 get_guid(id_table[dir_inode->base.guid]);
220
221 /* allocate fragment to file mapping table */
222 file_mapping = calloc(sBlk->fragments, sizeof(struct append_file *));
223 if(file_mapping == NULL)
224 MEM_ERROR();
225
226 for(cur_ptr = inode_table; cur_ptr < inode_table + bytes; files ++) {
227 if(NO_INODE_BYTES(squashfs_base_inode_header))
228 /* corrupted filesystem */
229 goto corrupted;
230
231 SQUASHFS_SWAP_BASE_INODE_HEADER(cur_ptr, &base);
232
233 TRACE("scan_inode_table: processing inode @ byte position "
234 "0x%x, type 0x%x\n",
235 (unsigned int) (cur_ptr - inode_table),
236 base.inode_type);
237
238 get_uid(id_table[base.uid]);
239 get_guid(id_table[base.guid]);
240
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;
247
248 if(NO_INODE_BYTES(squashfs_reg_inode_header))
249 /* corrupted filesystem */
250 goto corrupted;
251
252 SQUASHFS_SWAP_REG_INODE_HEADER(cur_ptr, &inode);
253
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 >>
259 sBlk->block_log;
260 start = inode.start_block;
261
262 TRACE("scan_inode_table: regular file, file_size %d, "
263 "blocks %d\n", inode.file_size, blocks);
264
265 if(NO_BYTES(blocks * sizeof(unsigned int)))
266 /* corrupted filesystem */
267 goto corrupted;
268
269 block_list = malloc(blocks * sizeof(unsigned int));
270 if(block_list == NULL)
271 MEM_ERROR();
272
273 cur_ptr += sizeof(inode);
274 SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
275
276 *uncompressed_file += inode.file_size;
277 (*file_count) ++;
278
279 for(i = 0; i < blocks; i++)
280 file_bytes +=
281 SQUASHFS_COMPRESSED_SIZE_BLOCK
282 (block_list[i]);
283
284 if(inode.fragment != SQUASHFS_INVALID_FRAG &&
285 inode.fragment >= sBlk->fragments) {
286 free(block_list);
287 goto corrupted;
288 }
289
290 add_file(start, inode.file_size, file_bytes,
291 block_list, blocks, inode.fragment,
292 inode.offset, frag_bytes);
293
294 cur_ptr += blocks * sizeof(unsigned int);
295 break;
296 }
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;
302
303 if(NO_INODE_BYTES(squashfs_lreg_inode_header))
304 /* corrupted filesystem */
305 goto corrupted;
306
307 SQUASHFS_SWAP_LREG_INODE_HEADER(cur_ptr, &inode);
308
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 >>
314 sBlk->block_log;
315 start = inode.start_block;
316
317 TRACE("scan_inode_table: extended regular "
318 "file, file_size %lld, blocks %d\n",
319 inode.file_size, blocks);
320
321 if(NO_BYTES(blocks * sizeof(unsigned int)))
322 /* corrupted filesystem */
323 goto corrupted;
324
325 block_list = malloc(blocks * sizeof(unsigned int));
326 if(block_list == NULL)
327 MEM_ERROR();
328
329 cur_ptr += sizeof(inode);
330 SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
331
332 *uncompressed_file += inode.file_size;
333 (*file_count) ++;
334
335 for(i = 0; i < blocks; i++)
336 file_bytes +=
337 SQUASHFS_COMPRESSED_SIZE_BLOCK
338 (block_list[i]);
339
340 if(inode.fragment != SQUASHFS_INVALID_FRAG &&
341 inode.fragment >= sBlk->fragments) {
342 free(block_list);
343 goto corrupted;
344 }
345
346 add_file(start, inode.file_size, file_bytes,
347 block_list, blocks, inode.fragment,
348 inode.offset, frag_bytes);
349
350 cur_ptr += blocks * sizeof(unsigned int);
351 break;
352 }
353 case SQUASHFS_SYMLINK_TYPE:
354 case SQUASHFS_LSYMLINK_TYPE: {
355 struct squashfs_symlink_inode_header inode;
356
357 if(NO_INODE_BYTES(squashfs_symlink_inode_header))
358 /* corrupted filesystem */
359 goto corrupted;
360
361 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(cur_ptr, &inode);
362
363 (*sym_count) ++;
364
365 if (inode.inode_type == SQUASHFS_LSYMLINK_TYPE) {
366 if(NO_BYTES(inode.symlink_size +
367 sizeof(unsigned int)))
368 /* corrupted filesystem */
369 goto corrupted;
370 cur_ptr += sizeof(inode) + inode.symlink_size +
371 sizeof(unsigned int);
372 } else {
373 if(NO_BYTES(inode.symlink_size))
374 /* corrupted filesystem */
375 goto corrupted;
376 cur_ptr += sizeof(inode) + inode.symlink_size;
377 }
378 break;
379 }
380 case SQUASHFS_DIR_TYPE: {
381 struct squashfs_dir_inode_header dir_inode;
382
383 if(NO_INODE_BYTES(squashfs_dir_inode_header))
384 /* corrupted filesystem */
385 goto corrupted;
386
387 SQUASHFS_SWAP_DIR_INODE_HEADER(cur_ptr, &dir_inode);
388
389 if(dir_inode.start_block < directory_start_block)
390 *uncompressed_directory += dir_inode.file_size;
391
392 (*dir_count) ++;
393 cur_ptr += sizeof(struct squashfs_dir_inode_header);
394 break;
395 }
396 case SQUASHFS_LDIR_TYPE: {
397 struct squashfs_ldir_inode_header dir_inode;
398 int i;
399
400 if(NO_INODE_BYTES(squashfs_ldir_inode_header))
401 /* corrupted filesystem */
402 goto corrupted;
403
404 SQUASHFS_SWAP_LDIR_INODE_HEADER(cur_ptr, &dir_inode);
405
406 if(dir_inode.start_block < directory_start_block)
407 *uncompressed_directory += dir_inode.file_size;
408
409 (*dir_count) ++;
410 cur_ptr += sizeof(struct squashfs_ldir_inode_header);
411
412 for(i = 0; i < dir_inode.i_count; i++) {
413 struct squashfs_dir_index index;
414
415 if(NO_BYTES(sizeof(index)))
416 /* corrupted filesystem */
417 goto corrupted;
418
419 SQUASHFS_SWAP_DIR_INDEX(cur_ptr, &index);
420
421 if(NO_BYTES(index.size + 1))
422 /* corrupted filesystem */
423 goto corrupted;
424
425 cur_ptr += sizeof(index) + index.size + 1;
426 }
427 break;
428 }
429 case SQUASHFS_BLKDEV_TYPE:
430 case SQUASHFS_CHRDEV_TYPE:
431 if(NO_INODE_BYTES(squashfs_dev_inode_header))
432 /* corrupted filesystem */
433 goto corrupted;
434
435 (*dev_count) ++;
436 cur_ptr += sizeof(struct squashfs_dev_inode_header);
437 break;
438 case SQUASHFS_LBLKDEV_TYPE:
439 case SQUASHFS_LCHRDEV_TYPE:
440 if(NO_INODE_BYTES(squashfs_ldev_inode_header))
441 /* corrupted filesystem */
442 goto corrupted;
443
444 (*dev_count) ++;
445 cur_ptr += sizeof(struct squashfs_ldev_inode_header);
446 break;
447 case SQUASHFS_FIFO_TYPE:
448 if(NO_INODE_BYTES(squashfs_ipc_inode_header))
449 /* corrupted filesystem */
450 goto corrupted;
451
452 (*fifo_count) ++;
453 cur_ptr += sizeof(struct squashfs_ipc_inode_header);
454 break;
455 case SQUASHFS_LFIFO_TYPE:
456 if(NO_INODE_BYTES(squashfs_lipc_inode_header))
457 /* corrupted filesystem */
458 goto corrupted;
459
460 (*fifo_count) ++;
461 cur_ptr += sizeof(struct squashfs_lipc_inode_header);
462 break;
463 case SQUASHFS_SOCKET_TYPE:
464 if(NO_INODE_BYTES(squashfs_ipc_inode_header))
465 /* corrupted filesystem */
466 goto corrupted;
467
468 (*sock_count) ++;
469 cur_ptr += sizeof(struct squashfs_ipc_inode_header);
470 break;
471 case SQUASHFS_LSOCKET_TYPE:
472 if(NO_INODE_BYTES(squashfs_lipc_inode_header))
473 /* corrupted filesystem */
474 goto corrupted;
475
476 (*sock_count) ++;
477 cur_ptr += sizeof(struct squashfs_lipc_inode_header);
478 break;
479 default:
480 ERROR("Unknown inode type %d in scan_inode_table!\n",
481 base.inode_type);
482 goto corrupted;
483 }
484 }
485
486 printf("Read existing filesystem, %d inodes scanned\n", files);
487 return inode_table;
488
489 corrupted:
490 ERROR("scan_inode_table: filesystem corruption detected in "
491 "scanning metadata\n");
492 free(inode_table);
493 return NULL;
494 }
495
496
497 struct compressor *read_super(int fd, struct squashfs_super_block *sBlk, char *source)
498 {
499 int res, bytes = 0;
500 char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned));
501
502 res = read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
503 sBlk);
504 if(res == 0) {
505 ERROR("Can't find a SQUASHFS superblock on %s\n",
506 source);
507 ERROR("Wrong filesystem or filesystem is corrupted!\n");
508 goto failed_mount;
509 }
510
511 SQUASHFS_INSWAP_SUPER_BLOCK(sBlk);
512
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);
517 else {
518 ERROR("Can't find a SQUASHFS superblock on %s\n",
519 source);
520 ERROR("Wrong filesystem or filesystem is corrupted!\n");
521 }
522 goto failed_mount;
523 }
524
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,
532 sBlk->s_major,
533 sBlk->s_minor, sBlk->s_major, sBlk->s_minor);
534 else
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);
538 goto failed_mount;
539 }
540
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("", "");
548 goto failed_mount;
549 }
550
551 /*
552 * Read extended superblock information from disk.
553 *
554 * Read compressor specific options from disk if present, and pass
555 * to compressor to set compressor options.
556 *
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).
561 *
562 * Compressor_extract_options is also used to ensure that
563 * we know how decompress a filesystem compressed with these
564 * compression options.
565 */
566 if(SQUASHFS_COMP_OPTS(sBlk->flags)) {
567 bytes = read_block(fd, sizeof(*sBlk), NULL, 0, buffer);
568
569 if(bytes == 0) {
570 ERROR("Failed to read compressor options from append "
571 "filesystem\n");
572 ERROR("Filesystem corrupted?\n");
573 goto failed_mount;
574 }
575 }
576
577 res = compressor_extract_options(comp, sBlk->block_size, buffer, bytes);
578 if(res == -1) {
579 ERROR("Compressor failed to set compressor options\n");
580 goto failed_mount;
581 }
582
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);
616 printf("\n");
617
618 return comp;
619
620 failed_mount:
621 return NULL;
622 }
623
624
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))
629 {
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;
638
639 size += offset;
640 directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) &
641 ~(SQUASHFS_METADATA_SIZE - 1));
642 if(directory_table == NULL)
643 MEM_ERROR();
644
645 while(bytes < size) {
646 int expected = (size - bytes) >= SQUASHFS_METADATA_SIZE ?
647 SQUASHFS_METADATA_SIZE : 0;
648
649 TRACE("squashfs_readdir: reading block 0x%llx, bytes read so "
650 "far %d\n", start, bytes);
651
652 last_start_block = start;
653 byte = read_block(fd, start, &start, expected, directory_table + bytes);
654 if(byte == 0) {
655 ERROR("Failed to read directory\n");
656 ERROR("Filesystem corrupted?\n");
657 free(directory_table);
658 return NULL;
659 }
660 bytes += byte;
661 }
662
663 if(!root_entries)
664 goto all_done;
665
666 bytes = offset;
667 while(bytes < size) {
668 SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh);
669
670 dir_count = dirh.count + 1;
671
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);
676 return NULL;
677 }
678
679 TRACE("squashfs_readdir: Read directory header @ byte position "
680 "0x%x, 0x%x directory entries\n", bytes, dir_count);
681 bytes += sizeof(dirh);
682
683 while(dir_count--) {
684 SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire);
685 bytes += sizeof(*dire);
686
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);
691 return NULL;
692 }
693
694 memcpy(dire->name, directory_table + bytes,
695 dire->size + 1);
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;
705 }
706 }
707
708 all_done:
709 *last_directory_block = (unsigned int) last_start_block -
710 sBlk->directory_table_start;
711 return directory_table;
712 }
713
714
715 unsigned int *read_id_table(int fd, struct squashfs_super_block *sBlk)
716 {
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;
721 int res, i;
722
723 id_table = malloc(bytes);
724 if(id_table == NULL)
725 MEM_ERROR();
726
727 res = read_fs_bytes(fd, sBlk->id_table_start,
728 SQUASHFS_ID_BLOCK_BYTES(sBlk->no_ids), index);
729 if(res == 0) {
730 ERROR("Failed to read id table index\n");
731 ERROR("Filesystem corrupted?\n");
732 free(id_table);
733 return NULL;
734 }
735
736 SQUASHFS_INSWAP_ID_BLOCKS(index, indexes);
737
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,
745 index[i], length);
746 if(length == 0) {
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");
750 free(id_table);
751 return NULL;
752 }
753 }
754
755 SQUASHFS_INSWAP_INTS(id_table, sBlk->no_ids);
756
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]);
760 }
761
762 return id_table;
763 }
764
765
766 struct squashfs_fragment_entry *read_fragment_table(int fd, struct squashfs_super_block *sBlk)
767 {
768 int res, i;
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;
773
774 TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
775 "from 0x%llx\n", sBlk->fragments, indexes,
776 sBlk->fragment_table_start);
777
778 fragment_table = malloc(bytes);
779 if(fragment_table == NULL)
780 MEM_ERROR();
781
782 res = read_fs_bytes(fd, sBlk->fragment_table_start,
783 SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments),
784 fragment_table_index);
785 if(res == 0) {
786 ERROR("Failed to read fragment table index\n");
787 ERROR("Filesystem corrupted?\n");
788 free(fragment_table);
789 return NULL;
790 }
791
792 SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index, indexes);
793
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);
802 if(length == 0) {
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);
808 return NULL;
809 }
810 }
811
812 for(i = 0; i < sBlk->fragments; i++)
813 SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]);
814
815 return fragment_table;
816 }
817
818
819 squashfs_inode *read_inode_lookup_table(int fd, struct squashfs_super_block *sBlk)
820 {
821 int lookup_bytes = SQUASHFS_LOOKUP_BYTES(sBlk->inodes);
822 int indexes = SQUASHFS_LOOKUP_BLOCKS(sBlk->inodes);
823 long long index[indexes];
824 int res, i;
825 squashfs_inode *inode_lookup_table;
826
827 inode_lookup_table = malloc(lookup_bytes);
828 if(inode_lookup_table == NULL)
829 MEM_ERROR();
830
831 res = read_fs_bytes(fd, sBlk->lookup_table_start,
832 SQUASHFS_LOOKUP_BLOCK_BYTES(sBlk->inodes), index);
833 if(res == 0) {
834 ERROR("Failed to read inode lookup table index\n");
835 ERROR("Filesystem corrupted?\n");
836 free(inode_lookup_table);
837 return NULL;
838 }
839
840 SQUASHFS_INSWAP_LONG_LONGS(index, indexes);
841
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);
850 if(length == 0) {
851 ERROR("Failed to read inode lookup table block %d, "
852 "from 0x%llx, length %d\n", i, index[i],
853 length);
854 ERROR("Filesystem corrupted?\n");
855 free(inode_lookup_table);
856 return NULL;
857 }
858 }
859
860 SQUASHFS_INSWAP_LONG_LONGS(inode_lookup_table, sBlk->inodes);
861
862 return inode_lookup_table;
863 }
864
865
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)
879 {
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;
890 int res;
891
892 printf("Scanning existing filesystem...\n");
893
894 if(get_xattrs(fd, sBlk) == 0)
895 goto error;
896
897 if(sBlk->fragments > 0) {
898 *fragment_table = read_fragment_table(fd, sBlk);
899 if(*fragment_table == NULL)
900 goto error;
901 }
902
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)
906 goto error;
907 }
908
909 id_table = read_id_table(fd, sBlk);
910 if(id_table == NULL)
911 goto error;
912
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)
919 goto error;
920
921 *uncompressed_inode = root_inode_block;
922
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;
931 } else {
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;
937 }
938
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)
944 goto error;
945
946 root_inode_start -= start;
947 *cinode_table = malloc(root_inode_start);
948 if(*cinode_table == NULL)
949 MEM_ERROR();
950
951 res = read_fs_bytes(fd, start, root_inode_start, *cinode_table);
952 if(res == 0) {
953 ERROR("Failed to read inode table\n");
954 ERROR("Filesystem corrupted?\n");
955 goto error;
956 }
957
958 *cdirectory_table = malloc(*last_directory_block);
959 if(*cdirectory_table == NULL)
960 MEM_ERROR();
961
962 res = read_fs_bytes(fd, sBlk->directory_table_start,
963 *last_directory_block, *cdirectory_table);
964 if(res == 0) {
965 ERROR("Failed to read directory table\n");
966 ERROR("Filesystem corrupted?\n");
967 goto error;
968 }
969
970 *data_cache = malloc(root_inode_offset + *root_inode_size);
971 if(*data_cache == NULL)
972 MEM_ERROR();
973
974 memcpy(*data_cache, inode_table + root_inode_block,
975 root_inode_offset + *root_inode_size);
976
977 *directory_data_cache = malloc(*inode_dir_offset +
978 *inode_dir_file_size);
979 if(*directory_data_cache == NULL)
980 MEM_ERROR();
981
982 memcpy(*directory_data_cache, directory_table,
983 *inode_dir_offset + *inode_dir_file_size);
984
985 free(id_table);
986 free(inode_table);
987 free(directory_table);
988 return sBlk->inode_table_start;
989 }
990
991 error:
992 free(id_table);
993 free(inode_table);
994 free(directory_table);
995 return 0;
996 }