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
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
read_block(int fd,long long start,long long * next,int expected,void * block)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
scan_inode_table(int fd,long long start,long long end,long long root_inode_start,int root_inode_offset,struct squashfs_super_block * sBlk,union squashfs_inode_header * dir_inode,unsigned char ** inode_table,unsigned int * root_inode_block,unsigned int * root_inode_size,long long * uncompressed_file,unsigned int * uncompressed_directory,int * file_count,int * sym_count,int * dev_count,int * dir_count,int * fifo_count,int * sock_count,unsigned int * id_table)120 int 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 char **inode_table, unsigned int *root_inode_block,
124 unsigned int *root_inode_size, long long *uncompressed_file,
125 unsigned int *uncompressed_directory, int *file_count, int *sym_count,
126 int *dev_count, int *dir_count, int *fifo_count, int *sock_count,
127 unsigned int *id_table)
128 {
129 unsigned char *cur_ptr;
130 int byte, files = 0;
131 unsigned int directory_start_block, bytes = 0, size = 0;
132 struct squashfs_base_inode_header base;
133
134 TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start "
135 "0x%llx\n", start, end, root_inode_start);
136
137 *root_inode_block = UINT_MAX;
138 while(start < end) {
139 if(start == root_inode_start) {
140 TRACE("scan_inode_table: read compressed block 0x%llx "
141 "containing root inode\n", start);
142 *root_inode_block = bytes;
143 }
144 if(size - bytes < SQUASHFS_METADATA_SIZE) {
145 *inode_table = realloc(*inode_table, size
146 += SQUASHFS_METADATA_SIZE);
147 if(*inode_table == NULL)
148 MEM_ERROR();
149 }
150 TRACE("scan_inode_table: reading block 0x%llx\n", start);
151 byte = read_block(fd, start, &start, 0, *inode_table + bytes);
152 if(byte == 0)
153 goto corrupted;
154
155 bytes += byte;
156
157 /* If this is not the last metadata block in the inode table
158 * then it should be SQUASHFS_METADATA_SIZE in size.
159 * Note, we can't use expected in read_block() above for this
160 * because we don't know if this is the last block until
161 * after reading.
162 */
163 if(start != end && byte != SQUASHFS_METADATA_SIZE)
164 goto corrupted;
165 }
166
167 /*
168 * We expect to have found the metadata block containing the
169 * root inode in the above inode_table metadata block scan. If it
170 * hasn't been found then the filesystem is corrupted
171 */
172 if(*root_inode_block == UINT_MAX)
173 goto corrupted;
174
175 /*
176 * The number of bytes available after the root inode medata block
177 * should be at least the root inode offset + the size of a
178 * regular directory inode, if not the filesystem is corrupted
179 *
180 * +-----------------------+-----------------------+
181 * | | directory |
182 * | | inode |
183 * +-----------------------+-----------------------+
184 * ^ ^ ^
185 * *root_inode_block root_inode_offset bytes
186 */
187 if((bytes - *root_inode_block) < (root_inode_offset +
188 sizeof(struct squashfs_dir_inode_header)))
189 goto corrupted;
190
191 /*
192 * Read last inode entry which is the root directory inode, and obtain
193 * the last directory start block index. This is used when calculating
194 * the total uncompressed directory size. The directory bytes in the
195 * last * block will be counted as normal.
196 *
197 * Note, the previous check ensures the following calculation won't
198 * underflow, and we won't access beyond the buffer
199 */
200 *root_inode_size = bytes - (*root_inode_block + root_inode_offset);
201 bytes = *root_inode_block + root_inode_offset;
202 SQUASHFS_SWAP_DIR_INODE_HEADER(*inode_table + bytes, &dir_inode->dir);
203
204 if(dir_inode->base.inode_type == SQUASHFS_DIR_TYPE)
205 directory_start_block = dir_inode->dir.start_block;
206 else if(dir_inode->base.inode_type == SQUASHFS_LDIR_TYPE) {
207 if(*root_inode_size < sizeof(struct squashfs_ldir_inode_header))
208 /* corrupted filesystem */
209 goto corrupted;
210 SQUASHFS_SWAP_LDIR_INODE_HEADER(*inode_table + bytes,
211 &dir_inode->ldir);
212 directory_start_block = dir_inode->ldir.start_block;
213 } else
214 /* bad type, corrupted filesystem */
215 goto corrupted;
216
217 get_uid(id_table[dir_inode->base.uid], 0);
218 get_guid(id_table[dir_inode->base.guid], 0);
219
220 /* allocate fragment to file mapping table */
221 file_mapping = calloc(sBlk->fragments, sizeof(struct append_file *));
222 if(file_mapping == NULL)
223 MEM_ERROR();
224
225 for(cur_ptr = *inode_table; cur_ptr < *inode_table + bytes; files ++) {
226 if(NO_INODE_BYTES(squashfs_base_inode_header))
227 /* corrupted filesystem */
228 goto corrupted;
229
230 SQUASHFS_SWAP_BASE_INODE_HEADER(cur_ptr, &base);
231
232 TRACE("scan_inode_table: processing inode @ byte position "
233 "0x%x, type 0x%x\n",
234 (unsigned int) (cur_ptr - *inode_table),
235 base.inode_type);
236
237 get_uid(id_table[base.uid], 0);
238 get_guid(id_table[base.guid], 0);
239
240 switch(base.inode_type) {
241 case SQUASHFS_FILE_TYPE: {
242 struct squashfs_reg_inode_header inode;
243 int frag_bytes, blocks, i;
244 long long start, file_bytes = 0;
245 unsigned int *block_list;
246
247 if(NO_INODE_BYTES(squashfs_reg_inode_header))
248 /* corrupted filesystem */
249 goto corrupted;
250
251 SQUASHFS_SWAP_REG_INODE_HEADER(cur_ptr, &inode);
252
253 frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
254 0 : inode.file_size % sBlk->block_size;
255 blocks = inode.fragment == SQUASHFS_INVALID_FRAG ?
256 (inode.file_size + sBlk->block_size - 1) >>
257 sBlk->block_log : inode.file_size >>
258 sBlk->block_log;
259 start = inode.start_block;
260
261 TRACE("scan_inode_table: regular file, file_size %d, "
262 "blocks %d\n", inode.file_size, blocks);
263
264 if(NO_BYTES(blocks * sizeof(unsigned int)))
265 /* corrupted filesystem */
266 goto corrupted;
267
268 block_list = malloc(blocks * sizeof(unsigned int));
269 if(block_list == NULL)
270 MEM_ERROR();
271
272 cur_ptr += sizeof(inode);
273 SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
274
275 *uncompressed_file += inode.file_size;
276 (*file_count) ++;
277
278 for(i = 0; i < blocks; i++)
279 file_bytes +=
280 SQUASHFS_COMPRESSED_SIZE_BLOCK
281 (block_list[i]);
282
283 if(inode.fragment != SQUASHFS_INVALID_FRAG &&
284 inode.fragment >= sBlk->fragments) {
285 free(block_list);
286 goto corrupted;
287 }
288
289 add_file(start, inode.file_size, file_bytes,
290 block_list, blocks, inode.fragment,
291 inode.offset, frag_bytes);
292
293 cur_ptr += blocks * sizeof(unsigned int);
294 break;
295 }
296 case SQUASHFS_LREG_TYPE: {
297 struct squashfs_lreg_inode_header inode;
298 int frag_bytes, blocks, i;
299 long long start, file_bytes = 0;
300 unsigned int *block_list;
301
302 if(NO_INODE_BYTES(squashfs_lreg_inode_header))
303 /* corrupted filesystem */
304 goto corrupted;
305
306 SQUASHFS_SWAP_LREG_INODE_HEADER(cur_ptr, &inode);
307
308 frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ?
309 0 : inode.file_size % sBlk->block_size;
310 blocks = inode.fragment == SQUASHFS_INVALID_FRAG ?
311 (inode.file_size + sBlk->block_size - 1) >>
312 sBlk->block_log : inode.file_size >>
313 sBlk->block_log;
314 start = inode.start_block;
315
316 TRACE("scan_inode_table: extended regular "
317 "file, file_size %lld, blocks %d\n",
318 inode.file_size, blocks);
319
320 if(NO_BYTES(blocks * sizeof(unsigned int)))
321 /* corrupted filesystem */
322 goto corrupted;
323
324 block_list = malloc(blocks * sizeof(unsigned int));
325 if(block_list == NULL)
326 MEM_ERROR();
327
328 cur_ptr += sizeof(inode);
329 SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks);
330
331 *uncompressed_file += inode.file_size;
332 (*file_count) ++;
333
334 for(i = 0; i < blocks; i++)
335 file_bytes +=
336 SQUASHFS_COMPRESSED_SIZE_BLOCK
337 (block_list[i]);
338
339 if(inode.fragment != SQUASHFS_INVALID_FRAG &&
340 inode.fragment >= sBlk->fragments) {
341 free(block_list);
342 goto corrupted;
343 }
344
345 add_file(start, inode.file_size, file_bytes,
346 block_list, blocks, inode.fragment,
347 inode.offset, frag_bytes);
348
349 cur_ptr += blocks * sizeof(unsigned int);
350 break;
351 }
352 case SQUASHFS_SYMLINK_TYPE:
353 case SQUASHFS_LSYMLINK_TYPE: {
354 struct squashfs_symlink_inode_header inode;
355
356 if(NO_INODE_BYTES(squashfs_symlink_inode_header))
357 /* corrupted filesystem */
358 goto corrupted;
359
360 SQUASHFS_SWAP_SYMLINK_INODE_HEADER(cur_ptr, &inode);
361
362 (*sym_count) ++;
363
364 if (inode.inode_type == SQUASHFS_LSYMLINK_TYPE) {
365 if(NO_BYTES(inode.symlink_size +
366 sizeof(unsigned int)))
367 /* corrupted filesystem */
368 goto corrupted;
369 cur_ptr += sizeof(inode) + inode.symlink_size +
370 sizeof(unsigned int);
371 } else {
372 if(NO_BYTES(inode.symlink_size))
373 /* corrupted filesystem */
374 goto corrupted;
375 cur_ptr += sizeof(inode) + inode.symlink_size;
376 }
377 break;
378 }
379 case SQUASHFS_DIR_TYPE: {
380 struct squashfs_dir_inode_header dir_inode;
381
382 if(NO_INODE_BYTES(squashfs_dir_inode_header))
383 /* corrupted filesystem */
384 goto corrupted;
385
386 SQUASHFS_SWAP_DIR_INODE_HEADER(cur_ptr, &dir_inode);
387
388 if(dir_inode.start_block < directory_start_block)
389 *uncompressed_directory += dir_inode.file_size;
390
391 (*dir_count) ++;
392 cur_ptr += sizeof(struct squashfs_dir_inode_header);
393 break;
394 }
395 case SQUASHFS_LDIR_TYPE: {
396 struct squashfs_ldir_inode_header dir_inode;
397 int i;
398
399 if(NO_INODE_BYTES(squashfs_ldir_inode_header))
400 /* corrupted filesystem */
401 goto corrupted;
402
403 SQUASHFS_SWAP_LDIR_INODE_HEADER(cur_ptr, &dir_inode);
404
405 if(dir_inode.start_block < directory_start_block)
406 *uncompressed_directory += dir_inode.file_size;
407
408 (*dir_count) ++;
409 cur_ptr += sizeof(struct squashfs_ldir_inode_header);
410
411 for(i = 0; i < dir_inode.i_count; i++) {
412 struct squashfs_dir_index index;
413
414 if(NO_BYTES(sizeof(index)))
415 /* corrupted filesystem */
416 goto corrupted;
417
418 SQUASHFS_SWAP_DIR_INDEX(cur_ptr, &index);
419
420 if(NO_BYTES(index.size + 1))
421 /* corrupted filesystem */
422 goto corrupted;
423
424 cur_ptr += sizeof(index) + index.size + 1;
425 }
426 break;
427 }
428 case SQUASHFS_BLKDEV_TYPE:
429 case SQUASHFS_CHRDEV_TYPE:
430 if(NO_INODE_BYTES(squashfs_dev_inode_header))
431 /* corrupted filesystem */
432 goto corrupted;
433
434 (*dev_count) ++;
435 cur_ptr += sizeof(struct squashfs_dev_inode_header);
436 break;
437 case SQUASHFS_LBLKDEV_TYPE:
438 case SQUASHFS_LCHRDEV_TYPE:
439 if(NO_INODE_BYTES(squashfs_ldev_inode_header))
440 /* corrupted filesystem */
441 goto corrupted;
442
443 (*dev_count) ++;
444 cur_ptr += sizeof(struct squashfs_ldev_inode_header);
445 break;
446 case SQUASHFS_FIFO_TYPE:
447 if(NO_INODE_BYTES(squashfs_ipc_inode_header))
448 /* corrupted filesystem */
449 goto corrupted;
450
451 (*fifo_count) ++;
452 cur_ptr += sizeof(struct squashfs_ipc_inode_header);
453 break;
454 case SQUASHFS_LFIFO_TYPE:
455 if(NO_INODE_BYTES(squashfs_lipc_inode_header))
456 /* corrupted filesystem */
457 goto corrupted;
458
459 (*fifo_count) ++;
460 cur_ptr += sizeof(struct squashfs_lipc_inode_header);
461 break;
462 case SQUASHFS_SOCKET_TYPE:
463 if(NO_INODE_BYTES(squashfs_ipc_inode_header))
464 /* corrupted filesystem */
465 goto corrupted;
466
467 (*sock_count) ++;
468 cur_ptr += sizeof(struct squashfs_ipc_inode_header);
469 break;
470 case SQUASHFS_LSOCKET_TYPE:
471 if(NO_INODE_BYTES(squashfs_lipc_inode_header))
472 /* corrupted filesystem */
473 goto corrupted;
474
475 (*sock_count) ++;
476 cur_ptr += sizeof(struct squashfs_lipc_inode_header);
477 break;
478 default:
479 ERROR("Unknown inode type %d in scan_inode_table!\n",
480 base.inode_type);
481 goto corrupted;
482 }
483 }
484
485 printf("Read existing filesystem, %d inodes scanned\n", files);
486 return TRUE;
487
488 corrupted:
489 ERROR("scan_inode_table: filesystem corruption detected in "
490 "scanning metadata\n");
491 free(*inode_table);
492 return FALSE;
493 }
494
495
read_super(int fd,struct squashfs_super_block * sBlk,char * source)496 struct compressor *read_super(int fd, struct squashfs_super_block *sBlk, char *source)
497 {
498 int res, bytes = 0;
499 char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned));
500
501 res = read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block),
502 sBlk);
503 if(res == 0) {
504 ERROR("Can't find a SQUASHFS superblock on %s\n",
505 source);
506 ERROR("Wrong filesystem or filesystem is corrupted!\n");
507 goto failed_mount;
508 }
509
510 SQUASHFS_INSWAP_SUPER_BLOCK(sBlk);
511
512 if(sBlk->s_magic != SQUASHFS_MAGIC) {
513 if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP)
514 ERROR("Pre 4.0 big-endian filesystem on %s, appending"
515 " to this is unsupported\n", source);
516 else {
517 ERROR("Can't find a SQUASHFS superblock on %s\n",
518 source);
519 ERROR("Wrong filesystem or filesystem is corrupted!\n");
520 }
521 goto failed_mount;
522 }
523
524 /* Check the MAJOR & MINOR versions */
525 if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) {
526 if(sBlk->s_major < 4)
527 ERROR("Filesystem on %s is a SQUASHFS %d.%d filesystem."
528 " Appending\nto SQUASHFS %d.%d filesystems is "
529 "not supported. Please convert it to a "
530 "SQUASHFS 4 filesystem\n", source,
531 sBlk->s_major,
532 sBlk->s_minor, sBlk->s_major, sBlk->s_minor);
533 else
534 ERROR("Filesystem on %s is %d.%d, which is a later "
535 "filesystem version than I support\n",
536 source, sBlk->s_major, sBlk->s_minor);
537 goto failed_mount;
538 }
539
540 /* Check the compression type */
541 comp = lookup_compressor_id(sBlk->compression);
542 if(!comp->supported) {
543 ERROR("Filesystem on %s uses %s compression, this is "
544 "unsupported by this version\n", source, comp->name);
545 ERROR("Compressors available:\n");
546 display_compressors("", "");
547 goto failed_mount;
548 }
549
550 /*
551 * Read extended superblock information from disk.
552 *
553 * Read compressor specific options from disk if present, and pass
554 * to compressor to set compressor options.
555 *
556 * Note, if there's no compressor options present, the compressor
557 * is still called to set the default options (the defaults may have
558 * been changed by the user specifying options on the command
559 * line which need to be over-ridden).
560 *
561 * Compressor_extract_options is also used to ensure that
562 * we know how decompress a filesystem compressed with these
563 * compression options.
564 */
565 if(SQUASHFS_COMP_OPTS(sBlk->flags)) {
566 bytes = read_block(fd, sizeof(*sBlk), NULL, 0, buffer);
567
568 if(bytes == 0) {
569 ERROR("Failed to read compressor options from append "
570 "filesystem\n");
571 ERROR("Filesystem corrupted?\n");
572 goto failed_mount;
573 }
574 }
575
576 res = compressor_extract_options(comp, sBlk->block_size, buffer, bytes);
577 if(res == -1) {
578 ERROR("Compressor failed to set compressor options\n");
579 goto failed_mount;
580 }
581
582 printf("Found a valid %sSQUASHFS superblock on %s.\n",
583 SQUASHFS_EXPORTABLE(sBlk->flags) ? "exportable " : "", source);
584 printf("\tCompression used %s\n", comp->name);
585 printf("\tInodes are %scompressed\n",
586 SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : "");
587 printf("\tData is %scompressed\n",
588 SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : "");
589 printf("\tFragments are %scompressed\n",
590 SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : "");
591 printf("\tXattrs are %scompressed\n",
592 SQUASHFS_UNCOMPRESSED_XATTRS(sBlk->flags) ? "un" : "");
593 printf("\tFragments are %spresent in the filesystem\n",
594 SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not " : "");
595 printf("\tAlways-use-fragments option is %sspecified\n",
596 SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not ");
597 printf("\tDuplicates are %sremoved\n",
598 SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not ");
599 printf("\tXattrs are %sstored\n",
600 SQUASHFS_NO_XATTRS(sBlk->flags) ? "not " : "");
601 printf("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n",
602 sBlk->bytes_used / 1024.0, sBlk->bytes_used
603 / (1024.0 * 1024.0));
604 printf("\tBlock size %d\n", sBlk->block_size);
605 printf("\tNumber of fragments %d\n", sBlk->fragments);
606 printf("\tNumber of inodes %d\n", sBlk->inodes);
607 printf("\tNumber of ids %d\n", sBlk->no_ids);
608 TRACE("sBlk->inode_table_start %llx\n", sBlk->inode_table_start);
609 TRACE("sBlk->directory_table_start %llx\n",
610 sBlk->directory_table_start);
611 TRACE("sBlk->id_table_start %llx\n", sBlk->id_table_start);
612 TRACE("sBlk->fragment_table_start %llx\n", sBlk->fragment_table_start);
613 TRACE("sBlk->lookup_table_start %llx\n", sBlk->lookup_table_start);
614 TRACE("sBlk->xattr_id_table_start %llx\n", sBlk->xattr_id_table_start);
615 printf("\n");
616
617 return comp;
618
619 failed_mount:
620 return NULL;
621 }
622
623
squashfs_readdir(int fd,int root_entries,unsigned int directory_start_block,int offset,int size,unsigned int * last_directory_block,struct squashfs_super_block * sBlk,void (push_directory_entry)(char *,squashfs_inode,int,int))624 unsigned char *squashfs_readdir(int fd, int root_entries,
625 unsigned int directory_start_block, int offset, int size,
626 unsigned int *last_directory_block, struct squashfs_super_block *sBlk,
627 void (push_directory_entry)(char *, squashfs_inode, int, int))
628 {
629 struct squashfs_dir_header dirh;
630 char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]
631 __attribute__ ((aligned));
632 struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
633 unsigned char *directory_table = NULL;
634 int byte, bytes = 0, dir_count;
635 long long start = sBlk->directory_table_start + directory_start_block,
636 last_start_block = start;
637
638 size += offset;
639 directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) &
640 ~(SQUASHFS_METADATA_SIZE - 1));
641 if(directory_table == NULL)
642 MEM_ERROR();
643
644 while(bytes < size) {
645 int expected = (size - bytes) >= SQUASHFS_METADATA_SIZE ?
646 SQUASHFS_METADATA_SIZE : 0;
647
648 TRACE("squashfs_readdir: reading block 0x%llx, bytes read so "
649 "far %d\n", start, bytes);
650
651 last_start_block = start;
652 byte = read_block(fd, start, &start, expected, directory_table + bytes);
653 if(byte == 0) {
654 ERROR("Failed to read directory\n");
655 ERROR("Filesystem corrupted?\n");
656 free(directory_table);
657 return NULL;
658 }
659 bytes += byte;
660 }
661
662 if(!root_entries)
663 goto all_done;
664
665 bytes = offset;
666 while(bytes < size) {
667 SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh);
668
669 dir_count = dirh.count + 1;
670 TRACE("squashfs_readdir: Read directory header @ byte position "
671 "0x%x, 0x%x directory entries\n", bytes, dir_count);
672 bytes += sizeof(dirh);
673
674 while(dir_count--) {
675 SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire);
676 bytes += sizeof(*dire);
677
678 memcpy(dire->name, directory_table + bytes,
679 dire->size + 1);
680 dire->name[dire->size + 1] = '\0';
681 TRACE("squashfs_readdir: pushing directory entry %s, "
682 "inode %x:%x, type 0x%x\n", dire->name,
683 dirh.start_block, dire->offset, dire->type);
684 push_directory_entry(dire->name,
685 SQUASHFS_MKINODE(dirh.start_block,
686 dire->offset), dirh.inode_number +
687 dire->inode_number, dire->type);
688 bytes += dire->size + 1;
689 }
690 }
691
692 all_done:
693 *last_directory_block = (unsigned int) last_start_block -
694 sBlk->directory_table_start;
695 return directory_table;
696 }
697
698
read_id_table(int fd,struct squashfs_super_block * sBlk)699 unsigned int *read_id_table(int fd, struct squashfs_super_block *sBlk)
700 {
701 int indexes = SQUASHFS_ID_BLOCKS(sBlk->no_ids);
702 long long index[indexes];
703 int bytes = SQUASHFS_ID_BYTES(sBlk->no_ids);
704 unsigned int *id_table;
705 int res, i;
706
707 id_table = malloc(bytes);
708 if(id_table == NULL)
709 MEM_ERROR();
710
711 res = read_fs_bytes(fd, sBlk->id_table_start,
712 SQUASHFS_ID_BLOCK_BYTES(sBlk->no_ids), index);
713 if(res == 0) {
714 ERROR("Failed to read id table index\n");
715 ERROR("Filesystem corrupted?\n");
716 free(id_table);
717 return NULL;
718 }
719
720 SQUASHFS_INSWAP_ID_BLOCKS(index, indexes);
721
722 for(i = 0; i < indexes; i++) {
723 int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
724 bytes & (SQUASHFS_METADATA_SIZE - 1);
725 int length = read_block(fd, index[i], NULL, expected,
726 ((unsigned char *) id_table) +
727 (i * SQUASHFS_METADATA_SIZE));
728 TRACE("Read id table block %d, from 0x%llx, length %d\n", i,
729 index[i], length);
730 if(length == 0) {
731 ERROR("Failed to read id table block %d, from 0x%llx, "
732 "length %d\n", i, index[i], length);
733 ERROR("Filesystem corrupted?\n");
734 free(id_table);
735 return NULL;
736 }
737 }
738
739 SQUASHFS_INSWAP_INTS(id_table, sBlk->no_ids);
740
741 for(i = 0; i < sBlk->no_ids; i++) {
742 TRACE("Adding id %d to id tables\n", id_table[i]);
743 create_id(id_table[i]);
744 }
745
746 return id_table;
747 }
748
749
read_fragment_table(int fd,struct squashfs_super_block * sBlk,struct squashfs_fragment_entry ** fragment_table)750 int read_fragment_table(int fd, struct squashfs_super_block *sBlk,
751 struct squashfs_fragment_entry **fragment_table)
752 {
753 int res, i;
754 int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk->fragments);
755 int indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments);
756 long long fragment_table_index[indexes];
757
758 TRACE("read_fragment_table: %d fragments, reading %d fragment indexes "
759 "from 0x%llx\n", sBlk->fragments, indexes,
760 sBlk->fragment_table_start);
761
762 if(sBlk->fragments == 0)
763 return 1;
764
765 *fragment_table = malloc(bytes);
766 if(*fragment_table == NULL)
767 MEM_ERROR();
768
769 res = read_fs_bytes(fd, sBlk->fragment_table_start,
770 SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments),
771 fragment_table_index);
772 if(res == 0) {
773 ERROR("Failed to read fragment table index\n");
774 ERROR("Filesystem corrupted?\n");
775 free(*fragment_table);
776 return 0;
777 }
778
779 SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index, indexes);
780
781 for(i = 0; i < indexes; i++) {
782 int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
783 bytes & (SQUASHFS_METADATA_SIZE - 1);
784 int length = read_block(fd, fragment_table_index[i], NULL,
785 expected, ((unsigned char *) *fragment_table) +
786 (i * SQUASHFS_METADATA_SIZE));
787 TRACE("Read fragment table block %d, from 0x%llx, length %d\n",
788 i, fragment_table_index[i], length);
789 if(length == 0) {
790 ERROR("Failed to read fragment table block %d, from "
791 "0x%llx, length %d\n", i,
792 fragment_table_index[i], length);
793 ERROR("Filesystem corrupted?\n");
794 free(*fragment_table);
795 return 0;
796 }
797 }
798
799 for(i = 0; i < sBlk->fragments; i++)
800 SQUASHFS_INSWAP_FRAGMENT_ENTRY(&(*fragment_table)[i]);
801
802 return 1;
803 }
804
805
read_inode_lookup_table(int fd,struct squashfs_super_block * sBlk,squashfs_inode ** inode_lookup_table)806 int read_inode_lookup_table(int fd, struct squashfs_super_block *sBlk,
807 squashfs_inode **inode_lookup_table)
808 {
809 int lookup_bytes = SQUASHFS_LOOKUP_BYTES(sBlk->inodes);
810 int indexes = SQUASHFS_LOOKUP_BLOCKS(sBlk->inodes);
811 long long index[indexes];
812 int res, i;
813
814 if(sBlk->lookup_table_start == SQUASHFS_INVALID_BLK)
815 return 1;
816
817 *inode_lookup_table = malloc(lookup_bytes);
818 if(*inode_lookup_table == NULL)
819 MEM_ERROR();
820
821 res = read_fs_bytes(fd, sBlk->lookup_table_start,
822 SQUASHFS_LOOKUP_BLOCK_BYTES(sBlk->inodes), index);
823 if(res == 0) {
824 ERROR("Failed to read inode lookup table index\n");
825 ERROR("Filesystem corrupted?\n");
826 free(*inode_lookup_table);
827 return 0;
828 }
829
830 SQUASHFS_INSWAP_LONG_LONGS(index, indexes);
831
832 for(i = 0; i < indexes; i++) {
833 int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE :
834 lookup_bytes & (SQUASHFS_METADATA_SIZE - 1);
835 int length = read_block(fd, index[i], NULL, expected,
836 ((unsigned char *) *inode_lookup_table) +
837 (i * SQUASHFS_METADATA_SIZE));
838 TRACE("Read inode lookup table block %d, from 0x%llx, length "
839 "%d\n", i, index[i], length);
840 if(length == 0) {
841 ERROR("Failed to read inode lookup table block %d, "
842 "from 0x%llx, length %d\n", i, index[i],
843 length);
844 ERROR("Filesystem corrupted?\n");
845 free(*inode_lookup_table);
846 return 0;
847 }
848 }
849
850 SQUASHFS_INSWAP_LONG_LONGS(*inode_lookup_table, sBlk->inodes);
851
852 return 1;
853 }
854
855
read_filesystem(char * root_name,int fd,struct squashfs_super_block * sBlk,char ** cinode_table,char ** data_cache,char ** cdirectory_table,char ** directory_data_cache,unsigned int * last_directory_block,unsigned int * inode_dir_offset,unsigned int * inode_dir_file_size,unsigned int * root_inode_size,unsigned int * inode_dir_start_block,int * file_count,int * sym_count,int * dev_count,int * dir_count,int * fifo_count,int * sock_count,long long * uncompressed_file,unsigned int * uncompressed_inode,unsigned int * uncompressed_directory,unsigned int * inode_dir_inode_number,unsigned int * inode_dir_parent_inode,void (push_directory_entry)(char *,squashfs_inode,int,int),struct squashfs_fragment_entry ** fragment_table,squashfs_inode ** inode_lookup_table)856 long long read_filesystem(char *root_name, int fd, struct squashfs_super_block *sBlk,
857 char **cinode_table, char **data_cache, char **cdirectory_table,
858 char **directory_data_cache, unsigned int *last_directory_block,
859 unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size,
860 unsigned int *root_inode_size, unsigned int *inode_dir_start_block,
861 int *file_count, int *sym_count, int *dev_count, int *dir_count,
862 int *fifo_count, int *sock_count, long long *uncompressed_file,
863 unsigned int *uncompressed_inode, unsigned int *uncompressed_directory,
864 unsigned int *inode_dir_inode_number,
865 unsigned int *inode_dir_parent_inode,
866 void (push_directory_entry)(char *, squashfs_inode, int, int),
867 struct squashfs_fragment_entry **fragment_table,
868 squashfs_inode **inode_lookup_table)
869 {
870 unsigned char *inode_table = NULL, *directory_table = NULL;
871 long long start = sBlk->inode_table_start;
872 long long end = sBlk->directory_table_start;
873 long long root_inode_start = start +
874 SQUASHFS_INODE_BLK(sBlk->root_inode);
875 unsigned int root_inode_offset =
876 SQUASHFS_INODE_OFFSET(sBlk->root_inode);
877 unsigned int root_inode_block;
878 union squashfs_inode_header inode;
879 unsigned int *id_table = NULL;
880 int res;
881
882 printf("Scanning existing filesystem...\n");
883
884 if(get_xattrs(fd, sBlk) == 0)
885 goto error;
886
887 if(read_fragment_table(fd, sBlk, fragment_table) == 0)
888 goto error;
889
890 if(read_inode_lookup_table(fd, sBlk, inode_lookup_table) == 0)
891 goto error;
892
893 id_table = read_id_table(fd, sBlk);
894 if(id_table == NULL)
895 goto error;
896
897 res = scan_inode_table(fd, start, end, root_inode_start,
898 root_inode_offset, sBlk, &inode, &inode_table,
899 &root_inode_block, root_inode_size, uncompressed_file,
900 uncompressed_directory, file_count, sym_count, dev_count,
901 dir_count, fifo_count, sock_count, id_table);
902 if(res == 0)
903 goto error;
904
905 *uncompressed_inode = root_inode_block;
906
907 if(inode.base.inode_type == SQUASHFS_DIR_TYPE ||
908 inode.base.inode_type == SQUASHFS_LDIR_TYPE) {
909 if(inode.base.inode_type == SQUASHFS_DIR_TYPE) {
910 *inode_dir_start_block = inode.dir.start_block;
911 *inode_dir_offset = inode.dir.offset;
912 *inode_dir_file_size = inode.dir.file_size - 3;
913 *inode_dir_inode_number = inode.dir.inode_number;
914 *inode_dir_parent_inode = inode.dir.parent_inode;
915 } else {
916 *inode_dir_start_block = inode.ldir.start_block;
917 *inode_dir_offset = inode.ldir.offset;
918 *inode_dir_file_size = inode.ldir.file_size - 3;
919 *inode_dir_inode_number = inode.ldir.inode_number;
920 *inode_dir_parent_inode = inode.ldir.parent_inode;
921 }
922
923 directory_table = squashfs_readdir(fd, !root_name,
924 *inode_dir_start_block, *inode_dir_offset,
925 *inode_dir_file_size, last_directory_block, sBlk,
926 push_directory_entry);
927 if(directory_table == NULL)
928 goto error;
929
930 root_inode_start -= start;
931 *cinode_table = malloc(root_inode_start);
932 if(*cinode_table == NULL)
933 MEM_ERROR();
934
935 res = read_fs_bytes(fd, start, root_inode_start, *cinode_table);
936 if(res == 0) {
937 ERROR("Failed to read inode table\n");
938 ERROR("Filesystem corrupted?\n");
939 goto error;
940 }
941
942 *cdirectory_table = malloc(*last_directory_block);
943 if(*cdirectory_table == NULL)
944 MEM_ERROR();
945
946 res = read_fs_bytes(fd, sBlk->directory_table_start,
947 *last_directory_block, *cdirectory_table);
948 if(res == 0) {
949 ERROR("Failed to read directory table\n");
950 ERROR("Filesystem corrupted?\n");
951 goto error;
952 }
953
954 *data_cache = malloc(root_inode_offset + *root_inode_size);
955 if(*data_cache == NULL)
956 MEM_ERROR();
957
958 memcpy(*data_cache, inode_table + root_inode_block,
959 root_inode_offset + *root_inode_size);
960
961 *directory_data_cache = malloc(*inode_dir_offset +
962 *inode_dir_file_size);
963 if(*directory_data_cache == NULL)
964 MEM_ERROR();
965
966 memcpy(*directory_data_cache, directory_table,
967 *inode_dir_offset + *inode_dir_file_size);
968
969 free(id_table);
970 free(inode_table);
971 free(directory_table);
972 return sBlk->inode_table_start;
973 }
974
975 error:
976 free(id_table);
977 free(inode_table);
978 free(directory_table);
979 return 0;
980 }
981