int read_block(int fd, long long start, long long *next, int expected, void *block) { unsigned short c_byte; int res, compressed; int outlen = expected ? expected : SQUASHFS_METADATA_SIZE; /* Read block size */ res = read_fs_bytes(fd, start, 2, &c_byte); if(res == 0) return 0; SQUASHFS_INSWAP_SHORTS(&c_byte, 1); compressed = SQUASHFS_COMPRESSED(c_byte); c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); /* * The block size should not be larger than * the uncompressed size (or max uncompressed size if * expected is 0) */ if (c_byte > outlen) return 0; if(compressed) { char buffer[c_byte]; int error; res = read_fs_bytes(fd, start + 2, c_byte, buffer); if(res == 0) return 0; res = compressor_uncompress(comp, block, buffer, c_byte, outlen, &error); if(res == -1) { // CJH: Decompression errors are displayed elsewhere //ERROR("%s uncompress failed with error code %d\n", // comp->name, error); return 0; } } else { res = read_fs_bytes(fd, start + 2, c_byte, block); if(res == 0) return 0; res = c_byte; } if(next) *next = start + 2 + c_byte; /* * if expected, then check the (uncompressed) return data * is of the expected size */ if(expected && expected != res) return 0; else return res; }
static int read_metadata_block(const struct PkgData *pdata, const long long start, long long *next, void *buf, const size_t buf_size) { long long offset = start; unsigned short c_byte; int ret = read_fs_bytes(pdata->fd, offset, &c_byte, 2); if (ret) { goto failed; } offset += 2; int csize = SQUASHFS_COMPRESSED_SIZE(c_byte); TRACE("read_metadata_block: block @0x%llx, %d %s bytes\n", start, csize, SQUASHFS_COMPRESSED(c_byte) ? "compressed" : "uncompressed"); ret = SQUASHFS_COMPRESSED(c_byte) ? read_compressed(pdata, offset, csize, buf, buf_size) : read_uncompressed(pdata, offset, csize, buf, buf_size); if (ret < 0) { goto failed; } offset += csize; if (next) *next = offset; return ret; failed: ERROR("Failed to read metadata block @0x%llx\n", start); return ret; }
int read_uids_guids_4() { int res, i, indexes = SQUASHFS_ID_BLOCKS(sBlk.s.no_ids); long long id_index_table[indexes]; TRACE("read_uids_guids: no_ids %d\n", sBlk.s.no_ids); id_table = malloc(SQUASHFS_ID_BYTES(sBlk.s.no_ids)); if(id_table == NULL) { ERROR("read_uids_guids: failed to allocate id table\n"); return FALSE; } res = read_fs_bytes(fd, sBlk.s.id_table_start, SQUASHFS_ID_BLOCK_BYTES(sBlk.s.no_ids), id_index_table); if(res == FALSE) { ERROR("read_uids_guids: failed to read id index table\n"); return FALSE; } SQUASHFS_INSWAP_ID_BLOCKS(id_index_table, indexes); for(i = 0; i < indexes; i++) { res = read_block(fd, id_index_table[i], NULL, ((char *) id_table) + i * SQUASHFS_METADATA_SIZE); if(res == FALSE) { ERROR("read_uids_guids: failed to read id table block" "\n"); return FALSE; } } SQUASHFS_INSWAP_INTS(id_table, sBlk.s.no_ids); return TRUE; }
int read_fragment_table(int fd, struct squashfs_super_block *sBlk, struct squashfs_fragment_entry **fragment_table) { int res, i; int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk->fragments); int indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments); long long fragment_table_index[indexes]; 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; *fragment_table = malloc(bytes); if(*fragment_table == NULL) MEM_ERROR(); res = read_fs_bytes(fd, sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), fragment_table_index); if(res == 0) { ERROR("Failed to read fragment table index\n"); ERROR("Filesystem corrupted?\n"); free(*fragment_table); return 0; } SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index, indexes); for(i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, fragment_table_index[i], NULL, expected, ((unsigned char *) *fragment_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); if(length == 0) { ERROR("Failed to read fragment table block %d, from " "0x%llx, length %d\n", i, fragment_table_index[i], length); ERROR("Filesystem corrupted?\n"); free(*fragment_table); return 0; } } for(i = 0; i < sBlk->fragments; i++) SQUASHFS_INSWAP_FRAGMENT_ENTRY(&(*fragment_table)[i]); return 1; }
int read_uids_guids_1() { int res; TRACE("read_uids_guids: no_uids %d, no_guids %d\n", sBlk.no_uids, sBlk.no_guids); uid_table = malloc((sBlk.no_uids + sBlk.no_guids) * sizeof(unsigned int)); if(uid_table == NULL) { ERROR("read_uids_guids: failed to allocate uid/gid table\n"); return FALSE; } guid_table = uid_table + sBlk.no_uids; if(swap) { unsigned int suid_table[sBlk.no_uids + sBlk.no_guids]; res = read_fs_bytes(fd, sBlk.uid_start, (sBlk.no_uids + sBlk.no_guids) * sizeof(unsigned int), suid_table); if(res == FALSE) { ERROR("read_uids_guids: failed to read uid/gid table" "\n"); return FALSE; } SQUASHFS_SWAP_INTS_3(uid_table, suid_table, sBlk.no_uids + sBlk.no_guids); } else { res = read_fs_bytes(fd, sBlk.uid_start, (sBlk.no_uids + sBlk.no_guids) * sizeof(unsigned int), uid_table); if(res == FALSE) { ERROR("read_uids_guids: failed to read uid/gid table" "\n"); return FALSE; } } return TRUE; }
int read_fragment_table_4(long long *directory_table_end) { int res, i; int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk.s.fragments); int indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk.s.fragments); long long fragment_table_index[indexes]; TRACE("read_fragment_table: %d fragments, reading %d fragment indexes " "from 0x%llx\n", sBlk.s.fragments, indexes, sBlk.s.fragment_table_start); if(sBlk.s.fragments == 0) { *directory_table_end = sBlk.s.fragment_table_start; return TRUE; } fragment_table = malloc(bytes); if(fragment_table == NULL) EXIT_UNSQUASH("read_fragment_table: failed to allocate " "fragment table\n"); res = read_fs_bytes(fd, sBlk.s.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk.s.fragments), fragment_table_index); if(res == FALSE) { ERROR("read_fragment_table: failed to read fragment table " "index\n"); return FALSE; } SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index, indexes); for(i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, fragment_table_index[i], NULL, expected, ((char *) fragment_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); if(length == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table index\n"); return FALSE; } } for(i = 0; i < sBlk.s.fragments; i++) SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]); *directory_table_end = fragment_table_index[0]; return TRUE; }
unsigned int *read_id_table(int fd, struct squashfs_super_block *sBlk) { int indexes = SQUASHFS_ID_BLOCKS(sBlk->no_ids); long long index[indexes]; int bytes = SQUASHFS_ID_BYTES(sBlk->no_ids); unsigned int *id_table; int res, i; id_table = malloc(bytes); if(id_table == NULL) MEM_ERROR(); res = read_fs_bytes(fd, sBlk->id_table_start, SQUASHFS_ID_BLOCK_BYTES(sBlk->no_ids), index); if(res == 0) { ERROR("Failed to read id table index\n"); ERROR("Filesystem corrupted?\n"); free(id_table); return NULL; } SQUASHFS_INSWAP_ID_BLOCKS(index, indexes); for(i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, index[i], NULL, expected, ((unsigned char *) id_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read id table block %d, from 0x%llx, length %d\n", i, index[i], length); if(length == 0) { ERROR("Failed to read id table block %d, from 0x%llx, " "length %d\n", i, index[i], length); ERROR("Filesystem corrupted?\n"); free(id_table); return NULL; } } SQUASHFS_INSWAP_INTS(id_table, sBlk->no_ids); for(i = 0; i < sBlk->no_ids; i++) { TRACE("Adding id %d to id tables\n", id_table[i]); create_id(id_table[i]); } return id_table; }
int read_inode_lookup_table(int fd, struct squashfs_super_block *sBlk, squashfs_inode **inode_lookup_table) { int lookup_bytes = SQUASHFS_LOOKUP_BYTES(sBlk->inodes); int indexes = SQUASHFS_LOOKUP_BLOCKS(sBlk->inodes); long long index[indexes]; int res, i; if(sBlk->lookup_table_start == SQUASHFS_INVALID_BLK) return 1; *inode_lookup_table = malloc(lookup_bytes); if(*inode_lookup_table == NULL) MEM_ERROR(); res = read_fs_bytes(fd, sBlk->lookup_table_start, SQUASHFS_LOOKUP_BLOCK_BYTES(sBlk->inodes), index); if(res == 0) { ERROR("Failed to read inode lookup table index\n"); ERROR("Filesystem corrupted?\n"); free(*inode_lookup_table); return 0; } SQUASHFS_INSWAP_LONG_LONGS(index, indexes); for(i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : lookup_bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, index[i], NULL, expected, ((unsigned char *) *inode_lookup_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read inode lookup table block %d, from 0x%llx, length " "%d\n", i, index[i], length); if(length == 0) { ERROR("Failed to read inode lookup table block %d, " "from 0x%llx, length %d\n", i, index[i], length); ERROR("Filesystem corrupted?\n"); free(*inode_lookup_table); return 0; } } SQUASHFS_INSWAP_LONG_LONGS(*inode_lookup_table, sBlk->inodes); return 1; }
static int read_uncompressed(const struct PkgData *pdata, const long long offset, const size_t csize, void *buf, const size_t buf_size) { if (csize > buf_size) { ERROR("Refusing to load oversized uncompressed block\n"); return -EIO; } int err = read_fs_bytes(pdata->fd, offset, buf, csize); if (err < 0) { return err; } return (int) csize; }
static int read_compressed(const struct PkgData *pdata, const long long offset, const size_t csize, void *buf, const size_t buf_size) { if (csize >= buf_size) { // In the case compression doesn't make a block smaller, // mksquashfs will store the block uncompressed. ERROR("Refusing to load too-large compressed block\n"); return -EIO; } // Load compressed data into temporary buffer. char tmp[csize]; int err = read_fs_bytes(pdata->fd, offset, tmp, csize); if (err < 0) { return err; } #if USE_GZIP if (pdata->sBlk.compression == ZLIB_COMPRESSION) { unsigned long bytes_zlib = buf_size; int error = uncompress(buf, &bytes_zlib, (const Bytef *) tmp, csize); if (error == Z_OK) { return (int) bytes_zlib; } ERROR("GZIP uncompress failed with error code %d\n", error); return -EIO; } #endif #if USE_LZO if (pdata->sBlk.compression == LZO_COMPRESSION) { lzo_uint bytes_lzo = buf_size; int error = lzo1x_decompress_safe((const lzo_bytep) tmp, csize, buf, &bytes_lzo, NULL); if (error == LZO_E_OK) { return (int) bytes_lzo; } ERROR("LZO uncompress failed with error code %d\n", error); return -EIO; } #endif ERROR("Unsupported compression algorithm (id: %hu)\n", pdata->sBlk.compression); return -EINVAL; }
int read_fragment_table_4() { int res, i, indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk.s.fragments); long long fragment_table_index[indexes]; TRACE("read_fragment_table: %d fragments, reading %d fragment indexes " "from 0x%llx\n", sBlk.s.fragments, indexes, sBlk.s.fragment_table_start); if(sBlk.s.fragments == 0) return TRUE; fragment_table = malloc(sBlk.s.fragments * sizeof(struct squashfs_fragment_entry)); if(fragment_table == NULL) EXIT_UNSQUASH("read_fragment_table: failed to allocate " "fragment table\n"); res = read_fs_bytes(fd, sBlk.s.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk.s.fragments), fragment_table_index); if(res == FALSE) { ERROR("read_fragment_table: failed to read fragment table " "index\n"); return FALSE; } SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index, indexes); for(i = 0; i < indexes; i++) { int length = read_block(fd, fragment_table_index[i], NULL, ((char *) fragment_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); if(length == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table index\n"); return FALSE; } } for(i = 0; i < sBlk.s.fragments; i++) SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]); return TRUE; }
long long 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) { unsigned char *inode_table = NULL, *directory_table = NULL; long long start = sBlk->inode_table_start; long long end = sBlk->directory_table_start; long long root_inode_start = start + SQUASHFS_INODE_BLK(sBlk->root_inode); unsigned int root_inode_offset = SQUASHFS_INODE_OFFSET(sBlk->root_inode); unsigned int root_inode_block; union squashfs_inode_header inode; unsigned int *id_table = NULL; int res; printf("Scanning existing filesystem...\n"); if(get_xattrs(fd, sBlk) == 0) goto error; if(read_fragment_table(fd, sBlk, fragment_table) == 0) goto error; if(read_inode_lookup_table(fd, sBlk, inode_lookup_table) == 0) goto error; id_table = read_id_table(fd, sBlk); if(id_table == NULL) goto error; res = 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, id_table); if(res == 0) goto error; *uncompressed_inode = root_inode_block; 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; } 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); if(directory_table == NULL) goto error; root_inode_start -= start; *cinode_table = malloc(root_inode_start); if(*cinode_table == NULL) MEM_ERROR(); res = read_fs_bytes(fd, start, root_inode_start, *cinode_table); if(res == 0) { ERROR("Failed to read inode table\n"); ERROR("Filesystem corrupted?\n"); goto error; } *cdirectory_table = malloc(*last_directory_block); if(*cdirectory_table == NULL) MEM_ERROR(); res = read_fs_bytes(fd, sBlk->directory_table_start, *last_directory_block, *cdirectory_table); if(res == 0) { ERROR("Failed to read directory table\n"); ERROR("Filesystem corrupted?\n"); goto error; } *data_cache = malloc(root_inode_offset + *root_inode_size); if(*data_cache == NULL) MEM_ERROR(); memcpy(*data_cache, inode_table + root_inode_block, root_inode_offset + *root_inode_size); *directory_data_cache = malloc(*inode_dir_offset + *inode_dir_file_size); if(*directory_data_cache == NULL) MEM_ERROR(); memcpy(*directory_data_cache, directory_table, *inode_dir_offset + *inode_dir_file_size); free(id_table); free(inode_table); free(directory_table); return sBlk->inode_table_start; } error: free(id_table); free(inode_table); free(directory_table); return 0; }
struct compressor *read_super(int fd, struct squashfs_super_block *sBlk, char *source) { int res, bytes = 0; char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned)); res = read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block), sBlk); if(res == 0) { ERROR("Can't find a SQUASHFS superblock on %s\n", source); ERROR("Wrong filesystem or filesystem is corrupted!\n"); goto failed_mount; } SQUASHFS_INSWAP_SUPER_BLOCK(sBlk); if(sBlk->s_magic != SQUASHFS_MAGIC) { if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) ERROR("Pre 4.0 big-endian filesystem on %s, appending" " to this is unsupported\n", source); else { ERROR("Can't find a SQUASHFS superblock on %s\n", source); ERROR("Wrong filesystem or filesystem is corrupted!\n"); } goto failed_mount; } /* Check the MAJOR & MINOR versions */ if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { if(sBlk->s_major < 4) 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 4 filesystem\n", source, sBlk->s_major, sBlk->s_minor, sBlk->s_major, sBlk->s_minor); else ERROR("Filesystem on %s is %d.%d, which is a later " "filesystem version than I support\n", source, sBlk->s_major, sBlk->s_minor); goto failed_mount; } /* Check the compression type */ comp = lookup_compressor_id(sBlk->compression); if(!comp->supported) { ERROR("Filesystem on %s uses %s compression, this is " "unsupported by this version\n", source, comp->name); ERROR("Compressors available:\n"); display_compressors("", ""); goto failed_mount; } /* * Read extended superblock information from disk. * * Read compressor specific options from disk if present, and pass * to compressor to set compressor options. * * Note, if there's no compressor options present, the compressor * is still called to set the default options (the defaults may have * been changed by the user specifying options on the command * line which need to be over-ridden). * * Compressor_extract_options is also used to ensure that * we know how decompress a filesystem compressed with these * compression options. */ if(SQUASHFS_COMP_OPTS(sBlk->flags)) { bytes = read_block(fd, sizeof(*sBlk), NULL, 0, buffer); if(bytes == 0) { ERROR("Failed to read compressor options from append " "filesystem\n"); ERROR("Filesystem corrupted?\n"); goto failed_mount; } } res = compressor_extract_options(comp, sBlk->block_size, buffer, bytes); if(res == -1) { ERROR("Compressor failed to set compressor options\n"); goto failed_mount; } printf("Found a valid %sSQUASHFS superblock on %s.\n", SQUASHFS_EXPORTABLE(sBlk->flags) ? "exportable " : "", source); printf("\tCompression used %s\n", comp->name); printf("\tInodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : ""); printf("\tData is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : ""); printf("\tFragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : ""); printf("\tXattrs are %scompressed\n", SQUASHFS_UNCOMPRESSED_XATTRS(sBlk->flags) ? "un" : ""); printf("\tFragments are %spresent in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not " : ""); printf("\tAlways-use-fragments option is %sspecified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not "); printf("\tDuplicates are %sremoved\n", SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not "); printf("\tXattrs are %sstored\n", SQUASHFS_NO_XATTRS(sBlk->flags) ? "not " : ""); 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 ids %d\n", sBlk->no_ids); TRACE("sBlk->inode_table_start %llx\n", sBlk->inode_table_start); TRACE("sBlk->directory_table_start %llx\n", sBlk->directory_table_start); TRACE("sBlk->id_table_start %llx\n", sBlk->id_table_start); TRACE("sBlk->fragment_table_start %llx\n", sBlk->fragment_table_start); TRACE("sBlk->lookup_table_start %llx\n", sBlk->lookup_table_start); TRACE("sBlk->xattr_id_table_start %llx\n", sBlk->xattr_id_table_start); printf("\n"); return comp; failed_mount: return NULL; }
/* * Read and decompress the xattr id table and the xattr metadata. * This is cached in memory for later use by get_xattr() */ int read_xattrs_from_disk(int fd, struct squashfs_super_block *sBlk) { int res, bytes, i, indexes, index_bytes, ids; long long *index, start, end; struct squashfs_xattr_table id_table; TRACE("read_xattrs_from_disk\n"); if (sBlk->xattr_id_table_start == SQUASHFS_INVALID_BLK) return SQUASHFS_INVALID_BLK; /* * Read xattr id table, containing start of xattr metadata and the * number of xattrs in the file system */ res = read_fs_bytes(fd, sBlk->xattr_id_table_start, sizeof(id_table), &id_table); if (res == 0) return 0; SQUASHFS_INSWAP_XATTR_TABLE(&id_table); /* * Allocate and read the index to the xattr id table metadata * blocks */ ids = id_table.xattr_ids; xattr_table_start = id_table.xattr_table_start; index_bytes = SQUASHFS_XATTR_BLOCK_BYTES(ids); indexes = SQUASHFS_XATTR_BLOCKS(ids); index = malloc(index_bytes); if (index == NULL) MEM_ERROR(); res = read_fs_bytes(fd, sBlk->xattr_id_table_start + sizeof(id_table), index_bytes, index); if (res == 0) goto failed1; SQUASHFS_INSWAP_LONG_LONGS(index, indexes); /* * Allocate enough space for the uncompressed xattr id table, and * read and decompress it */ bytes = SQUASHFS_XATTR_BYTES(ids); xattr_ids = malloc(bytes); if (xattr_ids == NULL) MEM_ERROR(); for (i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, index[i], NULL, expected, ((unsigned char *)xattr_ids) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read xattr id table block %d, from 0x%llx, length " "%d\n", i, index[i], length); if (length == 0) { ERROR("Failed to read xattr id table block %d, " "from 0x%llx, length %d\n", i, index[i], length); goto failed2; } } /* * Read and decompress the xattr metadata * * Note the first xattr id table metadata block is immediately after * the last xattr metadata block, so we can use index[0] to work out * the end of the xattr metadata */ start = xattr_table_start; end = index[0]; for (i = 0; start < end; i++) { int length; xattrs = realloc(xattrs, (i + 1) * SQUASHFS_METADATA_SIZE); if (xattrs == NULL) MEM_ERROR(); /* store mapping from location of compressed block in fs -> * location of uncompressed block in memory */ save_xattr_block(start, i * SQUASHFS_METADATA_SIZE); length = read_block(fd, start, &start, 0, ((unsigned char *)xattrs) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read xattr block %d, length %d\n", i, length); if (length == 0) { ERROR("Failed to read xattr block %d\n", i); goto failed3; } /* * If this is not the last metadata block in the xattr metadata * then it should be SQUASHFS_METADATA_SIZE in size. * Note, we can't use expected in read_block() above for this * because we don't know if this is the last block until * after reading. */ if (start != end && length != SQUASHFS_METADATA_SIZE) { ERROR("Xattr block %d should be %d bytes in length, " "it is %d bytes\n", i, SQUASHFS_METADATA_SIZE, length); goto failed3; } } /* swap if necessary the xattr id entries */ for (i = 0; i < ids; i++) SQUASHFS_INSWAP_XATTR_ID(&xattr_ids[i]); free(index); return ids; failed3: free(xattrs); failed2: free(xattr_ids); failed1: free(index); return 0; }
int read_fragment_table_3() { int res, i, indexes = SQUASHFS_FRAGMENT_INDEXES_3(sBlk.s.fragments); squashfs_fragment_index fragment_table_index[indexes]; TRACE("read_fragment_table: %d fragments, reading %d fragment indexes " "from 0x%llx\n", sBlk.s.fragments, indexes, sBlk.s.fragment_table_start); if(sBlk.s.fragments == 0) return TRUE; if((fragment_table = malloc(sBlk.s.fragments * sizeof(squashfs_fragment_entry_3))) == NULL) EXIT_UNSQUASH("read_fragment_table: failed to allocate " "fragment table\n"); if(swap) { squashfs_fragment_index sfragment_table_index[indexes]; res = read_fs_bytes(fd, sBlk.s.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES_3(sBlk.s.fragments), sfragment_table_index); if(res == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table index\n"); return FALSE; } SQUASHFS_SWAP_FRAGMENT_INDEXES_3(fragment_table_index, sfragment_table_index, indexes); } else { res = read_fs_bytes(fd, sBlk.s.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES_3(sBlk.s.fragments), fragment_table_index); if(res == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table index\n"); return FALSE; } } for(i = 0; i < indexes; i++) { int length = read_block(fd, fragment_table_index[i], NULL, ((char *) fragment_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); if(length == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table block\n"); return FALSE; } } if(swap) { squashfs_fragment_entry_3 sfragment; for(i = 0; i < sBlk.s.fragments; i++) { SQUASHFS_SWAP_FRAGMENT_ENTRY_3((&sfragment), (&fragment_table[i])); memcpy((char *) &fragment_table[i], (char *) &sfragment, sizeof(squashfs_fragment_entry_3)); } } return TRUE; }
/* * Read and decompress the xattr id table and the xattr metadata. * This is cached in memory for later use by get_xattr() */ int read_xattrs_from_disk(int fd, struct squashfs_super_block *sBlk) { int res, bytes, i, indexes, index_bytes, ids; long long *index, start, end; struct squashfs_xattr_table id_table; TRACE("read_xattrs_from_disk\n"); if(sBlk->xattr_id_table_start == SQUASHFS_INVALID_BLK) return SQUASHFS_INVALID_BLK; /* * Read xattr id table, containing start of xattr metadata and the * number of xattrs in the file system */ res = read_fs_bytes(fd, sBlk->xattr_id_table_start, sizeof(id_table), &id_table); if(res == 0) return 0; SQUASHFS_INSWAP_XATTR_TABLE(&id_table); /* * Allocate and read the index to the xattr id table metadata * blocks */ ids = id_table.xattr_ids; xattr_table_start = id_table.xattr_table_start; index_bytes = SQUASHFS_XATTR_BLOCK_BYTES(ids); indexes = SQUASHFS_XATTR_BLOCKS(ids); index = malloc(index_bytes); if(index == NULL) { ERROR("Failed to allocate index array\n"); return 0; } res = read_fs_bytes(fd, sBlk->xattr_id_table_start + sizeof(id_table), index_bytes, index); if(res ==0) goto failed1; SQUASHFS_INSWAP_LONG_LONGS(index, indexes); /* * Allocate enough space for the uncompressed xattr id table, and * read and decompress it */ bytes = SQUASHFS_XATTR_BYTES(ids); xattr_ids = malloc(bytes); if(xattr_ids == NULL) { ERROR("Failed to allocate xattr id table\n"); goto failed1; } for(i = 0; i < indexes; i++) { int length = read_block(fd, index[i], NULL, ((unsigned char *) xattr_ids) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read xattr id table block %d, from 0x%llx, length " "%d\n", i, index[i], length); if(length == 0) { ERROR("Failed to read xattr id table block %d, " "from 0x%llx, length %d\n", i, index[i], length); goto failed2; } } /* * Read and decompress the xattr metadata * * Note the first xattr id table metadata block is immediately after * the last xattr metadata block, so we can use index[0] to work out * the end of the xattr metadata */ start = xattr_table_start; end = index[0]; for(i = 0; start < end; i++) { int length; void *x = realloc(xattrs, (i + 1) * SQUASHFS_METADATA_SIZE); if(x == NULL) { ERROR("Failed to realloc xattr data\n"); goto failed3; } xattrs = x; /* store mapping from location of compressed block in fs -> * location of uncompressed block in memory */ res = save_xattr_block(start, i * SQUASHFS_METADATA_SIZE); if(res == -1) goto failed3; length = read_block(fd, start, &start, ((unsigned char *) xattrs) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read xattr block %d, length %d\n", i, length); if(length == 0) { ERROR("Failed to read xattr block %d\n", i); goto failed3; } } /* swap if necessary the xattr id entries */ for(i = 0; i < ids; i++) SQUASHFS_INSWAP_XATTR_ID(&xattr_ids[i]); free(index); return ids; failed3: free(xattrs); failed2: free(xattr_ids); failed1: free(index); return 0; }