diff options
Diffstat (limited to 'release/src/linux/linux/scripts/squashfs/read_fs.c')
-rw-r--r-- | release/src/linux/linux/scripts/squashfs/read_fs.c | 344 |
1 files changed, 230 insertions, 114 deletions
diff --git a/release/src/linux/linux/scripts/squashfs/read_fs.c b/release/src/linux/linux/scripts/squashfs/read_fs.c index cdb62a75..46f4a4e4 100644 --- a/release/src/linux/linux/scripts/squashfs/read_fs.c +++ b/release/src/linux/linux/scripts/squashfs/read_fs.c @@ -1,7 +1,8 @@ /* * Read a squashfs filesystem. This is a highly compressed read only filesystem. * - * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,8 +21,8 @@ * read_fs.c */ -extern void read_bytes(int, unsigned int, int, char *); -extern int add_file(int, int, unsigned int *, int, unsigned int, int, int); +extern void read_bytes(int, long long, int, char *); +extern int add_file(long long, long long, unsigned int *, int, unsigned int, int, int); #define TRUE 1 #define FALSE 0 @@ -34,29 +35,41 @@ extern int add_file(int, int, unsigned int *, int, unsigned int, int, int); #include <zlib.h> #include <sys/mman.h> +#ifndef linux +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#else #include <endian.h> -#include "read_fs.h" +#endif + #include <squashfs_fs.h> +#include "read_fs.h" +#include "global.h" #include <stdlib.h> #ifdef SQUASHFS_TRACE -#define TRACE(s, args...) printf("mksquashfs: "s, ## args) +#define TRACE(s, args...) do { \ + printf("mksquashfs: "s, ## args); \ + } while(0) #else #define TRACE(s, args...) #endif -#define ERROR(s, args...) fprintf(stderr, s, ## args) +#define ERROR(s, args...) do { \ + fprintf(stderr, s, ## args); \ + } while(0) int swap; -int read_block(int fd, int start, int *next, unsigned char *block, squashfs_super_block *sBlk) +int read_block(int fd, long long start, long long *next, unsigned char *block, squashfs_super_block *sBlk) { unsigned short c_byte; int offset = 2; if(swap) { - read_bytes(fd, start, 2, block); + read_bytes(fd, start, 2, (char *) block); ((unsigned char *) &c_byte)[1] = block[0]; ((unsigned char *) &c_byte)[0] = block[1]; } else @@ -65,14 +78,14 @@ int read_block(int fd, int start, int *next, unsigned char *block, squashfs_supe if(SQUASHFS_CHECK_DATA(sBlk->flags)) offset = 3; if(SQUASHFS_COMPRESSED(c_byte)) { - unsigned char buffer[SQUASHFS_METADATA_SIZE]; + char buffer[SQUASHFS_METADATA_SIZE]; int res; - long bytes = SQUASHFS_METADATA_SIZE; + unsigned long bytes = SQUASHFS_METADATA_SIZE; c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); read_bytes(fd, start + offset, c_byte, buffer); - if((res = uncompress(block, &bytes, (const char *) buffer, c_byte)) != Z_OK) { + if((res = uncompress(block, &bytes, (const unsigned char *) buffer, c_byte)) != Z_OK) { if(res == Z_MEM_ERROR) ERROR("zlib::uncompress failed, not enough memory\n"); else if(res == Z_BUF_ERROR) @@ -86,7 +99,7 @@ int read_block(int fd, int start, int *next, unsigned char *block, squashfs_supe return bytes; } else { c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); - read_bytes(fd, start + offset, c_byte, block); + read_bytes(fd, start + offset, c_byte, (char *) block); if(next) *next = start + offset + c_byte; return c_byte; @@ -94,30 +107,32 @@ int read_block(int fd, int start, int *next, unsigned char *block, squashfs_supe } -int scan_inode_table(int fd, int start, int end, int root_inode_start, squashfs_super_block *sBlk, - squashfs_dir_inode_header *dir_inode, unsigned char **inode_table, unsigned int *root_inode_block, - unsigned int *uncompressed_file, unsigned int *uncompressed_directory, int *file_count, int *sym_count, - int *dev_count, int *dir_count, int *fifo_count, int *sock_count) +int scan_inode_table(int fd, long long start, long long end, long long root_inode_start, int root_inode_offset, + squashfs_super_block *sBlk, + 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 char *cur_ptr; - int bytes = 0, size = 0, files = 0; + int byte, bytes = 0, size = 0, files = 0; squashfs_reg_inode_header inode; unsigned int directory_start_block; - TRACE("scan_inode_table: start 0x%x, end 0x%x, root_inode_start 0x%x\n", start, end, root_inode_start); + TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start 0x%llx\n", start, end, root_inode_start); while(start < end) { if(start == root_inode_start) { - TRACE("scan_inode_table: read compressed block 0x%x containing root inode\n", start); + TRACE("scan_inode_table: read compressed block 0x%llx containing root inode\n", start); *root_inode_block = bytes; } if((size - bytes < SQUASHFS_METADATA_SIZE) && ((*inode_table = realloc(*inode_table, size += SQUASHFS_METADATA_SIZE)) == NULL)) return FALSE; - TRACE("scan_inode_table: reading block 0x%x\n", start); - if((bytes += read_block(fd, start, &start, *inode_table + bytes, sBlk)) == 0) { + TRACE("scan_inode_table: reading block 0x%llx\n", start); + if((byte = read_block(fd, start, &start, *inode_table + bytes, sBlk)) == 0) { free(*inode_table); return FALSE; } + bytes += byte; } /* @@ -128,43 +143,112 @@ int scan_inode_table(int fd, int start, int end, int root_inode_start, squashfs_ * The root inode is ignored in the inode scan. This ensures there is * always enough bytes left to read a regular file inode entry */ - bytes -= sizeof(squashfs_dir_inode_header); + *root_inode_size = bytes - (*root_inode_block + root_inode_offset); + bytes = *root_inode_block + root_inode_offset; if(swap) { - squashfs_dir_inode_header sinode; - memcpy((void *)&sinode, (void *)(*inode_table + bytes), sizeof(*dir_inode)); - SQUASHFS_SWAP_DIR_INODE_HEADER(dir_inode, &sinode); + squashfs_base_inode_header sinode; + memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->base)); + SQUASHFS_SWAP_BASE_INODE_HEADER(&dir_inode->base, &sinode, sizeof(squashfs_base_inode_header)); } else - memcpy((void *)dir_inode, (void *)(*inode_table + bytes), sizeof(*dir_inode)); - directory_start_block = dir_inode->start_block; + memcpy(&dir_inode->base, *inode_table + bytes, sizeof(dir_inode->base)); + if(dir_inode->base.inode_type == SQUASHFS_DIR_TYPE) { + if(swap) { + squashfs_dir_inode_header sinode; + memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->dir)); + SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode->dir, &sinode); + } else + memcpy(&dir_inode->dir, *inode_table + bytes, sizeof(dir_inode->dir)); + directory_start_block = dir_inode->dir.start_block; + } else { + if(swap) { + squashfs_ldir_inode_header sinode; + memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->ldir)); + SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode->ldir, &sinode); + } else + memcpy(&dir_inode->ldir, *inode_table + bytes, sizeof(dir_inode->ldir)); + directory_start_block = dir_inode->ldir.start_block; + } for(cur_ptr = *inode_table; cur_ptr < *inode_table + bytes; files ++) { if(swap) { squashfs_reg_inode_header sinode; - memcpy((void *)&sinode, (void *)cur_ptr, sizeof(inode)); + memcpy(&sinode, cur_ptr, sizeof(inode)); SQUASHFS_SWAP_REG_INODE_HEADER(&inode, &sinode); } else - memcpy((void *)&inode, (void *)cur_ptr, sizeof(inode)); + memcpy(&inode, cur_ptr, sizeof(inode)); TRACE("scan_inode_table: processing inode @ byte position 0x%x, type 0x%x\n", cur_ptr - *inode_table, inode.inode_type); switch(inode.inode_type) { case SQUASHFS_FILE_TYPE: { - int frag_bytes = inode.fragment == SQUASHFS_INVALID_BLK ? 0 : inode.file_size % sBlk->block_size; - int blocks = inode.fragment == SQUASHFS_INVALID_BLK ? (inode.file_size + int frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ? 0 : inode.file_size % sBlk->block_size; + int blocks = inode.fragment == SQUASHFS_INVALID_FRAG ? (inode.file_size + sBlk->block_size - 1) >> sBlk->block_log : inode.file_size >> sBlk->block_log; - int file_bytes = 0, i, start = inode.start_block; - unsigned int block_list[blocks]; + long long file_bytes = 0; + int i, start = inode.start_block; + unsigned int *block_list; + + TRACE("scan_inode_table: regular file, file_size %lld, blocks %d\n", inode.file_size, blocks); + + if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) { + ERROR("Out of memory in block list malloc\n"); + goto failed; + } + + cur_ptr += sizeof(inode); + if(swap) { + unsigned int sblock_list[blocks]; + memcpy(sblock_list, cur_ptr, blocks * sizeof(unsigned int)); + SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks); + } else + memcpy(block_list, cur_ptr, blocks * sizeof(unsigned int)); + + *uncompressed_file += inode.file_size; + (*file_count) ++; + + for(i = 0; i < blocks; i++) + file_bytes += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]); + + add_file(start, file_bytes, block_list, blocks, inode.fragment, inode.offset, frag_bytes); + cur_ptr += blocks * sizeof(unsigned int); + break; + } + case SQUASHFS_LREG_TYPE: { + squashfs_lreg_inode_header inode; + int frag_bytes; + int blocks; + long long file_bytes = 0; + int i, start; + unsigned int *block_list; - TRACE("scan_inode_table: regular file, file_size %d, blocks %d\n", inode.file_size, blocks); + if(swap) { + squashfs_lreg_inode_header sinodep; + memcpy(&sinodep, cur_ptr, sizeof(sinodep)); + SQUASHFS_SWAP_LREG_INODE_HEADER(&inode, &sinodep); + } else + memcpy(&inode, cur_ptr, sizeof(inode)); + + TRACE("scan_inode_table: extended regular file, file_size %lld, blocks %d\n", inode.file_size, blocks); cur_ptr += sizeof(inode); + frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ? 0 : inode.file_size % sBlk->block_size; + blocks = inode.fragment == SQUASHFS_INVALID_FRAG ? (inode.file_size + + sBlk->block_size - 1) >> sBlk->block_log : inode.file_size >> + sBlk->block_log; + start = inode.start_block; + + if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) { + ERROR("Out of memory in block list malloc\n"); + goto failed; + } + if(swap) { unsigned int sblock_list[blocks]; - memcpy((void *)sblock_list, (void *)cur_ptr, blocks * sizeof(unsigned int)); + memcpy(sblock_list, cur_ptr, blocks * sizeof(unsigned int)); SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks); } else - memcpy((void *)block_list, (void *)cur_ptr, blocks * sizeof(unsigned int)); + memcpy(block_list, cur_ptr, blocks * sizeof(unsigned int)); *uncompressed_file += inode.file_size; (*file_count) ++; @@ -181,10 +265,10 @@ int scan_inode_table(int fd, int start, int end, int root_inode_start, squashfs_ if(swap) { squashfs_symlink_inode_header sinodep; - memcpy((void *)&sinodep, (void *)cur_ptr, sizeof(sinodep)); + memcpy(&sinodep, cur_ptr, sizeof(sinodep)); SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inodep, &sinodep); } else - memcpy((void *)&inodep, (void *)cur_ptr, sizeof(inodep)); + memcpy(&inodep, cur_ptr, sizeof(inodep)); (*sym_count) ++; cur_ptr += sizeof(inodep) + inodep.symlink_size; break; @@ -194,16 +278,42 @@ int scan_inode_table(int fd, int start, int end, int root_inode_start, squashfs_ if(swap) { squashfs_dir_inode_header sinode; - memcpy((void *)&sinode, (void *)cur_ptr, sizeof(dir_inode)); + memcpy(&sinode, cur_ptr, sizeof(dir_inode)); SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode, &sinode); } else - memcpy((void *)&dir_inode, (void *)cur_ptr, sizeof(dir_inode)); + memcpy(&dir_inode, cur_ptr, sizeof(dir_inode)); if(dir_inode.start_block < directory_start_block) *uncompressed_directory += dir_inode.file_size; (*dir_count) ++; cur_ptr += sizeof(squashfs_dir_inode_header); break; } + case SQUASHFS_LDIR_TYPE: { + squashfs_ldir_inode_header dir_inode; + int i; + + if(swap) { + squashfs_ldir_inode_header sinode; + memcpy(&sinode, cur_ptr, sizeof(dir_inode)); + SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode, &sinode); + } else + memcpy(&dir_inode, cur_ptr, sizeof(dir_inode)); + if(dir_inode.start_block < directory_start_block) + *uncompressed_directory += dir_inode.file_size; + (*dir_count) ++; + cur_ptr += sizeof(squashfs_ldir_inode_header); + for(i = 0; i < dir_inode.i_count; i++) { + squashfs_dir_index index; + if(swap) { + squashfs_dir_index sindex; + memcpy(&sindex, cur_ptr, sizeof(squashfs_dir_index)); + SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); + } else + memcpy(&index, cur_ptr, sizeof(squashfs_dir_index)); + cur_ptr += sizeof(squashfs_dir_index) + index.size + 1; + } + break; + } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: (*dev_count) ++; @@ -220,12 +330,16 @@ int scan_inode_table(int fd, int start, int end, int root_inode_start, squashfs_ break; default: ERROR("Unknown inode type %d in scan_inode_table!\n", inode.inode_type); - free(*inode_table); - return FALSE; + goto failed; } } return files; + + +failed: + free(*inode_table); + return FALSE; } @@ -250,11 +364,11 @@ int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source) /* Check the MAJOR & MINOR versions */ if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { - if(sBlk->s_major == 1) - ERROR("Filesystem on %s is a SQUASHFS 1.x filesystem. Appending\nto SQUASHFS 1.x filesystems is not supported. Please convert it to a SQUASHFS 2.0 filesystem...n", source); + if(sBlk->s_major < 3) + ERROR("Filesystem on %s is a SQUASHFS %d.%d filesystem. Appending\nto SQUASHFS %d.%d filesystems is not supported. Please convert it to a SQUASHFS 3.0 filesystem\n", source, sBlk->s_major, sBlk->s_minor, sBlk->s_major, sBlk->s_minor); else - ERROR("Major/Minor mismatch, filesystem on %s is (%d:%d), I support (%d: <= %d)\n", - source, sBlk->s_major, sBlk->s_minor, SQUASHFS_MAJOR, SQUASHFS_MINOR); + ERROR("Major/Minor mismatch, filesystem on %s is %d.%d, I support 3.0\n", + source, sBlk->s_major, sBlk->s_minor); goto failed_mount; } @@ -272,16 +386,16 @@ int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source) printf("\tFragments are %s present in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not" : ""); printf("\tAlways_use_fragments option is %s specified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not"); printf("\tDuplicates are %s removed\n", SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not"); - printf("\tFilesystem size %d bytes\n", sBlk->bytes_used); + printf("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk->bytes_used / 1024.0, sBlk->bytes_used / (1024.0 * 1024.0)); printf("\tBlock size %d\n", sBlk->block_size); printf("\tNumber of fragments %d\n", sBlk->fragments); printf("\tNumber of inodes %d\n", sBlk->inodes); printf("\tNumber of uids %d\n", sBlk->no_uids); printf("\tNumber of gids %d\n", sBlk->no_guids); - TRACE("sBlk->inode_table_start %x\n", sBlk->inode_table_start); - TRACE("sBlk->directory_table_start %x\n", sBlk->directory_table_start); - TRACE("sBlk->uid_start %x\n", sBlk->uid_start); - TRACE("sBlk->fragment_table_start %x\n", sBlk->fragment_table_start); + TRACE("sBlk->inode_table_start %llx\n", sBlk->inode_table_start); + TRACE("sBlk->directory_table_start %llx\n", sBlk->directory_table_start); + TRACE("sBlk->uid_start %llx\n", sBlk->uid_start); + TRACE("sBlk->fragment_table_start %llx\n", sBlk->fragment_table_start); printf("\n"); return TRUE; @@ -291,24 +405,27 @@ failed_mount: } -unsigned char *squashfs_readdir(int fd, int root_entries, int start, int offset, int size, squashfs_super_block *sBlk, - void (push_directory_entry)(char *, squashfs_inode, int)) +unsigned char *squashfs_readdir(int fd, int root_entries, unsigned int directory_start_block, int offset, int size, + unsigned int *last_directory_block, squashfs_super_block *sBlk, void (push_directory_entry)(char *, squashfs_inode, int, int)) { squashfs_dir_header dirh; char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; unsigned char *directory_table = NULL; - int bytes = 0, dir_count; + int byte, bytes = 0, dir_count; + long long start = sBlk->directory_table_start + directory_start_block, last_start_block; size += offset; if((directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) & ~(SQUASHFS_METADATA_SIZE - 1))) == NULL) return NULL; while(bytes < size) { - TRACE("squashfs_readdir: reading block 0x%x, bytes read so far %d\n", start, bytes); - if((bytes += read_block(fd, start, &start, directory_table + bytes, sBlk)) == 0) { + TRACE("squashfs_readdir: reading block 0x%llx, bytes read so far %d\n", start, bytes); + last_start_block = start; + if((byte = read_block(fd, start, &start, directory_table + bytes, sBlk)) == 0) { free(directory_table); return NULL; } + bytes += byte; } if(!root_entries) @@ -318,10 +435,10 @@ unsigned char *squashfs_readdir(int fd, int root_entries, int start, int offset, while(bytes < size) { if(swap) { squashfs_dir_header sdirh; - memcpy((void *)&sdirh, directory_table + bytes, sizeof(sdirh)); + memcpy(&sdirh, directory_table + bytes, sizeof(sdirh)); SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); } else - memcpy((void *)&dirh, directory_table + bytes, sizeof(dirh)); + memcpy(&dirh, directory_table + bytes, sizeof(dirh)); dir_count = dirh.count + 1; TRACE("squashfs_readdir: Read directory header @ byte position 0x%x, 0x%x directory entries\n", bytes, dir_count); @@ -330,21 +447,22 @@ unsigned char *squashfs_readdir(int fd, int root_entries, int start, int offset, while(dir_count--) { if(swap) { squashfs_dir_entry sdire; - memcpy((void *)&sdire, directory_table + bytes, sizeof(sdire)); + memcpy(&sdire, directory_table + bytes, sizeof(sdire)); SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); } else - memcpy((void *)dire, directory_table + bytes, sizeof(dire)); + memcpy(dire, directory_table + bytes, sizeof(dire)); bytes += sizeof(*dire); - memcpy((void *)dire->name, directory_table + bytes, dire->size + 1); + memcpy(dire->name, directory_table + bytes, dire->size + 1); dire->name[dire->size + 1] = '\0'; TRACE("squashfs_readdir: pushing directory entry %s, inode %x:%x, type 0x%x\n", dire->name, dirh.start_block, dire->offset, dire->type); - push_directory_entry(dire->name, SQUASHFS_MKINODE(dirh.start_block, dire->offset), dire->type); + push_directory_entry(dire->name, SQUASHFS_MKINODE(dirh.start_block, dire->offset), dire->inode_number, dire->type); bytes += dire->size + 1; } } all_done: + *last_directory_block = (unsigned int) last_start_block - sBlk->directory_table_start; return directory_table; } @@ -354,7 +472,7 @@ int read_fragment_table(int fd, squashfs_super_block *sBlk, squashfs_fragment_en int i, indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments); squashfs_fragment_index fragment_table_index[indexes]; - TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%x\n", sBlk->fragments, indexes, sBlk->fragment_table_start); + TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk->fragments, indexes, sBlk->fragment_table_start); if(sBlk->fragments == 0) return 1; @@ -372,11 +490,10 @@ int read_fragment_table(int fd, squashfs_super_block *sBlk, squashfs_fragment_en read_bytes(fd, sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) fragment_table_index); for(i = 0; i < indexes; i++) { - int length = read_block(fd, fragment_table_index[i], NULL, ((char *) *fragment_table) + (i * SQUASHFS_METADATA_SIZE), sBlk); - TRACE("Read fragment table block %d, from 0x%x, length %d\n", i, fragment_table_index[i], length); + int length = read_block(fd, fragment_table_index[i], NULL, ((unsigned char *) *fragment_table) + (i * SQUASHFS_METADATA_SIZE), sBlk); + TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); } - if(swap) { squashfs_fragment_entry sfragment; for(i = 0; i < sBlk->fragments; i++) { @@ -389,29 +506,30 @@ int read_fragment_table(int fd, squashfs_super_block *sBlk, squashfs_fragment_en } -int read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **cinode_table, int *inode_bytes, - char **data_cache, int *cache_bytes, int *cache_size, - char **cdirectory_table, int *directory_bytes, - char **directory_data_cache, int *directory_cache_bytes, int *directory_cache_size, - int *file_count, int *sym_count, int *dev_count, int *dir_count, int *fifo_count, int *sock_count, - squashfs_uid *uids, unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count, - unsigned int *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory, - void (push_directory_entry)(char *, squashfs_inode, int), squashfs_fragment_entry **fragment_table) +long long read_filesystem(char *root_name, int fd, 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, squashfs_uid *uids, + unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_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), squashfs_fragment_entry **fragment_table) { unsigned char *inode_table = NULL, *directory_table; - unsigned int start = sBlk->inode_table_start, end = sBlk->directory_table_start, - root_inode_start = start + SQUASHFS_INODE_BLK(sBlk->root_inode), - root_inode_offset = SQUASHFS_INODE_OFFSET(sBlk->root_inode), root_directory_offset; - squashfs_dir_inode_header inode; - unsigned int files, root_inode_block; + long long start = sBlk->inode_table_start, end = sBlk->directory_table_start, root_inode_start = start + + SQUASHFS_INODE_BLK(sBlk->root_inode); + unsigned int root_inode_offset = SQUASHFS_INODE_OFFSET(sBlk->root_inode), root_inode_block, files; + squashfs_inode_header inode; printf("Scanning existing filesystem...\n"); - if(read_fragment_table(fd, sBlk, fragment_table) == 0) + if(read_fragment_table(fd, sBlk, fragment_table) == 0) goto error; - if((files = scan_inode_table(fd, start, end, root_inode_start, sBlk, &inode, &inode_table, &root_inode_block, - uncompressed_file, uncompressed_directory, file_count, sym_count, dev_count, dir_count, fifo_count, sock_count)) == 0) { + if((files = scan_inode_table(fd, start, end, root_inode_start, root_inode_offset, sBlk, &inode, &inode_table, + &root_inode_block, root_inode_size, uncompressed_file, uncompressed_directory, file_count, sym_count, + dev_count, dir_count, fifo_count, sock_count)) == 0) { ERROR("read_filesystem: inode table read failed\n"); goto error; } @@ -420,53 +538,51 @@ int read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char ** printf("Read existing filesystem, %d inodes scanned\n", files); - if(inode.inode_type == SQUASHFS_DIR_TYPE) { - if((directory_table = squashfs_readdir(fd, !root_name, sBlk->directory_table_start + inode.start_block, - inode.offset, inode.file_size, sBlk, push_directory_entry)) == NULL) { + if(inode.base.inode_type == SQUASHFS_DIR_TYPE || inode.base.inode_type == SQUASHFS_LDIR_TYPE) { + if(inode.base.inode_type == SQUASHFS_DIR_TYPE) { + *inode_dir_start_block = inode.dir.start_block; + *inode_dir_offset = inode.dir.offset; + *inode_dir_file_size = inode.dir.file_size - 3; + *inode_dir_inode_number = inode.dir.inode_number; + *inode_dir_parent_inode = inode.dir.parent_inode; + } else { + *inode_dir_start_block = inode.ldir.start_block; + *inode_dir_offset = inode.ldir.offset; + *inode_dir_file_size = inode.ldir.file_size - 3; + *inode_dir_inode_number = inode.ldir.inode_number; + *inode_dir_parent_inode = inode.ldir.parent_inode; + } + + if((directory_table = squashfs_readdir(fd, !root_name, *inode_dir_start_block, *inode_dir_offset, + *inode_dir_file_size, last_directory_block, sBlk, push_directory_entry)) == NULL) { ERROR("read_filesystem: Could not read root directory\n"); goto error; } - if((*cinode_table = (char *) malloc(root_inode_start - start)) == NULL) { + root_inode_start -= start; + if((*cinode_table = (char *) malloc(root_inode_start)) == NULL) { ERROR("read_filesystem: failed to alloc space for existing filesystem inode table\n"); goto error; } + read_bytes(fd, start, root_inode_start, *cinode_table); - read_bytes(fd, start, root_inode_start - start, *cinode_table); - - if((*cdirectory_table = (char *) malloc(inode.start_block)) == NULL) { - ERROR("read_filesystem: failed to alloc space for existing filesystem inode table\n"); + if((*cdirectory_table = (char *) malloc(*last_directory_block)) == NULL) { + ERROR("read_filesystem: failed to alloc space for existing filesystem directory table\n"); goto error; } + read_bytes(fd, sBlk->directory_table_start, *last_directory_block, *cdirectory_table); - read_bytes(fd, sBlk->directory_table_start, inode.start_block, *cdirectory_table); - - *inode_bytes = root_inode_start - start; - *directory_bytes = inode.start_block; - - root_inode_offset += sizeof(inode); - root_directory_offset = inode.offset + inode.file_size; - (*dir_count) ++; - - if(((*data_cache = (char *) malloc(root_inode_offset)) == NULL) || - ((*directory_data_cache = (char *) malloc(root_directory_offset)) == NULL)) { - ERROR("read_filesystem: failed to alloc inode/directory caches\n"); + if((*data_cache = (char *) malloc(root_inode_offset + *root_inode_size)) == NULL) { + ERROR("read_filesystem: failed to alloc inode cache\n"); goto error; } + memcpy(*data_cache, inode_table + root_inode_block, root_inode_offset + *root_inode_size); - memcpy(*data_cache, inode_table + root_inode_block, root_inode_offset); - memcpy(*directory_data_cache, directory_table, root_directory_offset); - *cache_size = root_inode_offset; - *directory_cache_size = root_directory_offset; - - if(root_name) { - push_directory_entry(root_name, sBlk->root_inode, SQUASHFS_DIR_TYPE); - *cache_bytes = root_inode_offset; - *directory_cache_bytes = root_directory_offset; - } else { - *cache_bytes = root_inode_offset - sizeof(inode); - *directory_cache_bytes = inode.offset; + if((*directory_data_cache = (char *) malloc(*inode_dir_offset + *inode_dir_file_size)) == NULL) { + ERROR("read_filesystem: failed to alloc directory cache\n"); + goto error; } + memcpy(*directory_data_cache, directory_table, *inode_dir_offset + *inode_dir_file_size); if(!swap) read_bytes(fd, sBlk->uid_start, sBlk->no_uids * sizeof(squashfs_uid), (char *) uids); |