void read_uids_guids() { if((uid_table = malloc((sBlk.no_uids + sBlk.no_guids) * sizeof(unsigned int))) == NULL) EXIT_UNSQUASH("read_uids_guids: failed to allocate uid/gid table\n"); guid_table = uid_table + sBlk.no_uids; if(swap) { unsigned int suid_table[sBlk.no_uids + sBlk.no_guids]; if(read_bytes(sBlk.uid_start, (sBlk.no_uids + sBlk.no_guids) * sizeof(unsigned int), (char *) suid_table) == FALSE) EXIT_UNSQUASH("read_uids_guids: failed to read uid/gid table\n"); SQUASHFS_SWAP_INTS(uid_table, suid_table, sBlk.no_uids + sBlk.no_guids); } else if(read_bytes(sBlk.uid_start, (sBlk.no_uids + sBlk.no_guids) * sizeof(unsigned int), (char *) uid_table) == FALSE) EXIT_UNSQUASH("read_uids_guids: failed to read uid/gid table\n"); }
int 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) { unsigned char *cur_ptr; int byte, files = 0; unsigned int directory_start_block, bytes = 0, size = 0; struct squashfs_base_inode_header base; TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start " "0x%llx\n", start, end, root_inode_start); *root_inode_block = UINT_MAX; while(start < end) { if(start == root_inode_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); if(*inode_table == NULL) MEM_ERROR(); } TRACE("scan_inode_table: reading block 0x%llx\n", start); byte = read_block(fd, start, &start, 0, *inode_table + bytes); if(byte == 0) goto corrupted; bytes += byte; /* If this is not the last metadata block in the inode table * 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 && byte != SQUASHFS_METADATA_SIZE) goto corrupted; } /* * We expect to have found the metadata block containing the * root inode in the above inode_table metadata block scan. If it * hasn't been found then the filesystem is corrupted */ if(*root_inode_block == UINT_MAX) goto corrupted; /* * The number of bytes available after the root inode medata block * should be at least the root inode offset + the size of a * regular directory inode, if not the filesystem is corrupted * * +-----------------------+-----------------------+ * | | directory | * | | inode | * +-----------------------+-----------------------+ * ^ ^ ^ * *root_inode_block root_inode_offset bytes */ if((bytes - *root_inode_block) < (root_inode_offset + sizeof(struct squashfs_dir_inode_header))) goto corrupted; /* * Read last inode entry which is the root directory inode, and obtain * the last directory start block index. This is used when calculating * the total uncompressed directory size. The directory bytes in the * last * block will be counted as normal. * * Note, the previous check ensures the following calculation won't * underflow, and we won't access beyond the buffer */ *root_inode_size = bytes - (*root_inode_block + root_inode_offset); bytes = *root_inode_block + root_inode_offset; SQUASHFS_SWAP_DIR_INODE_HEADER(*inode_table + bytes, &dir_inode->dir); if(dir_inode->base.inode_type == SQUASHFS_DIR_TYPE) directory_start_block = dir_inode->dir.start_block; else if(dir_inode->base.inode_type == SQUASHFS_LDIR_TYPE) { if(*root_inode_size < sizeof(struct squashfs_ldir_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_LDIR_INODE_HEADER(*inode_table + bytes, &dir_inode->ldir); directory_start_block = dir_inode->ldir.start_block; } else /* bad type, corrupted filesystem */ goto corrupted; get_uid(id_table[dir_inode->base.uid]); get_guid(id_table[dir_inode->base.guid]); /* allocate fragment to file mapping table */ file_mapping = calloc(sBlk->fragments, sizeof(struct append_file *)); if(file_mapping == NULL) MEM_ERROR(); for(cur_ptr = *inode_table; cur_ptr < *inode_table + bytes; files ++) { if(NO_INODE_BYTES(squashfs_base_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_BASE_INODE_HEADER(cur_ptr, &base); TRACE("scan_inode_table: processing inode @ byte position " "0x%x, type 0x%x\n", (unsigned int) (cur_ptr - *inode_table), base.inode_type); get_uid(id_table[base.uid]); get_guid(id_table[base.guid]); switch(base.inode_type) { case SQUASHFS_FILE_TYPE: { struct squashfs_reg_inode_header inode; int frag_bytes, blocks, i; long long start, file_bytes = 0; unsigned int *block_list; if(NO_INODE_BYTES(squashfs_reg_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_REG_INODE_HEADER(cur_ptr, &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; TRACE("scan_inode_table: regular file, file_size %d, " "blocks %d\n", inode.file_size, blocks); if(NO_BYTES(blocks * sizeof(unsigned int))) /* corrupted filesystem */ goto corrupted; block_list = malloc(blocks * sizeof(unsigned int)); if(block_list == NULL) MEM_ERROR(); cur_ptr += sizeof(inode); SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks); *uncompressed_file += inode.file_size; (*file_count) ++; for(i = 0; i < blocks; i++) file_bytes += SQUASHFS_COMPRESSED_SIZE_BLOCK (block_list[i]); if(inode.fragment != SQUASHFS_INVALID_FRAG && inode.fragment >= sBlk->fragments) { free(block_list); goto corrupted; } add_file(start, inode.file_size, file_bytes, block_list, blocks, inode.fragment, inode.offset, frag_bytes); cur_ptr += blocks * sizeof(unsigned int); break; } case SQUASHFS_LREG_TYPE: { struct squashfs_lreg_inode_header inode; int frag_bytes, blocks, i; long long start, file_bytes = 0; unsigned int *block_list; if(NO_INODE_BYTES(squashfs_lreg_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_LREG_INODE_HEADER(cur_ptr, &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; TRACE("scan_inode_table: extended regular " "file, file_size %lld, blocks %d\n", inode.file_size, blocks); if(NO_BYTES(blocks * sizeof(unsigned int))) /* corrupted filesystem */ goto corrupted; block_list = malloc(blocks * sizeof(unsigned int)); if(block_list == NULL) MEM_ERROR(); cur_ptr += sizeof(inode); SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks); *uncompressed_file += inode.file_size; (*file_count) ++; for(i = 0; i < blocks; i++) file_bytes += SQUASHFS_COMPRESSED_SIZE_BLOCK (block_list[i]); if(inode.fragment != SQUASHFS_INVALID_FRAG && inode.fragment >= sBlk->fragments) { free(block_list); goto corrupted; } add_file(start, inode.file_size, file_bytes, block_list, blocks, inode.fragment, inode.offset, frag_bytes); cur_ptr += blocks * sizeof(unsigned int); break; } case SQUASHFS_SYMLINK_TYPE: case SQUASHFS_LSYMLINK_TYPE: { struct squashfs_symlink_inode_header inode; if(NO_INODE_BYTES(squashfs_symlink_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_SYMLINK_INODE_HEADER(cur_ptr, &inode); (*sym_count) ++; if (inode.inode_type == SQUASHFS_LSYMLINK_TYPE) { if(NO_BYTES(inode.symlink_size + sizeof(unsigned int))) /* corrupted filesystem */ goto corrupted; cur_ptr += sizeof(inode) + inode.symlink_size + sizeof(unsigned int); } else { if(NO_BYTES(inode.symlink_size)) /* corrupted filesystem */ goto corrupted; cur_ptr += sizeof(inode) + inode.symlink_size; } break; } case SQUASHFS_DIR_TYPE: { struct squashfs_dir_inode_header dir_inode; if(NO_INODE_BYTES(squashfs_dir_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_DIR_INODE_HEADER(cur_ptr, &dir_inode); if(dir_inode.start_block < directory_start_block) *uncompressed_directory += dir_inode.file_size; (*dir_count) ++; cur_ptr += sizeof(struct squashfs_dir_inode_header); break; } case SQUASHFS_LDIR_TYPE: { struct squashfs_ldir_inode_header dir_inode; int i; if(NO_INODE_BYTES(squashfs_ldir_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_LDIR_INODE_HEADER(cur_ptr, &dir_inode); if(dir_inode.start_block < directory_start_block) *uncompressed_directory += dir_inode.file_size; (*dir_count) ++; cur_ptr += sizeof(struct squashfs_ldir_inode_header); for(i = 0; i < dir_inode.i_count; i++) { struct squashfs_dir_index index; if(NO_BYTES(sizeof(index))) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_DIR_INDEX(cur_ptr, &index); if(NO_BYTES(index.size + 1)) /* corrupted filesystem */ goto corrupted; cur_ptr += sizeof(index) + index.size + 1; } break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: if(NO_INODE_BYTES(squashfs_dev_inode_header)) /* corrupted filesystem */ goto corrupted; (*dev_count) ++; cur_ptr += sizeof(struct squashfs_dev_inode_header); break; case SQUASHFS_LBLKDEV_TYPE: case SQUASHFS_LCHRDEV_TYPE: if(NO_INODE_BYTES(squashfs_ldev_inode_header)) /* corrupted filesystem */ goto corrupted; (*dev_count) ++; cur_ptr += sizeof(struct squashfs_ldev_inode_header); break; case SQUASHFS_FIFO_TYPE: if(NO_INODE_BYTES(squashfs_ipc_inode_header)) /* corrupted filesystem */ goto corrupted; (*fifo_count) ++; cur_ptr += sizeof(struct squashfs_ipc_inode_header); break; case SQUASHFS_LFIFO_TYPE: if(NO_INODE_BYTES(squashfs_lipc_inode_header)) /* corrupted filesystem */ goto corrupted; (*fifo_count) ++; cur_ptr += sizeof(struct squashfs_lipc_inode_header); break; case SQUASHFS_SOCKET_TYPE: if(NO_INODE_BYTES(squashfs_ipc_inode_header)) /* corrupted filesystem */ goto corrupted; (*sock_count) ++; cur_ptr += sizeof(struct squashfs_ipc_inode_header); break; case SQUASHFS_LSOCKET_TYPE: if(NO_INODE_BYTES(squashfs_lipc_inode_header)) /* corrupted filesystem */ goto corrupted; (*sock_count) ++; cur_ptr += sizeof(struct squashfs_lipc_inode_header); break; default: ERROR("Unknown inode type %d in scan_inode_table!\n", base.inode_type); goto corrupted; } } printf("Read existing filesystem, %d inodes scanned\n", files); return TRUE; corrupted: ERROR("scan_inode_table: filesystem corruption detected in " "scanning metadata\n"); free(*inode_table); return FALSE; }
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 byte, bytes = 0, size = 0, files = 0; squashfs_reg_inode_header inode; unsigned int directory_start_block; 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%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%llx\n", start); if((byte = read_block(fd, start, &start, *inode_table + bytes, sBlk)) == 0) { free(*inode_table); return FALSE; } bytes += byte; } /* * Read last inode entry which is the root directory inode, and obtain the last * directory start block index. This is used when calculating the total uncompressed * directory size. The directory bytes in the last block will be counted as normal. * * The root inode is ignored in the inode scan. This ensures there is * always enough bytes left to read a regular file inode entry */ *root_inode_size = bytes - (*root_inode_block + root_inode_offset); bytes = *root_inode_block + root_inode_offset; if(swap) { 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(&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(&sinode, cur_ptr, sizeof(inode)); SQUASHFS_SWAP_REG_INODE_HEADER(&inode, &sinode); } else 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_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; long long file_bytes = 0; int i; long long 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, inode.file_size, 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; long long start; unsigned int *block_list; 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(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, inode.file_size, file_bytes, block_list, blocks, inode.fragment, inode.offset, frag_bytes); cur_ptr += blocks * sizeof(unsigned int); break; } case SQUASHFS_SYMLINK_TYPE: { squashfs_symlink_inode_header inodep; if(swap) { squashfs_symlink_inode_header sinodep; memcpy(&sinodep, cur_ptr, sizeof(sinodep)); SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inodep, &sinodep); } else memcpy(&inodep, cur_ptr, sizeof(inodep)); (*sym_count) ++; cur_ptr += sizeof(inodep) + inodep.symlink_size; break; } case SQUASHFS_DIR_TYPE: { squashfs_dir_inode_header dir_inode; if(swap) { squashfs_dir_inode_header sinode; memcpy(&sinode, cur_ptr, sizeof(dir_inode)); SQUASHFS_SWAP_DIR_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_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) ++; cur_ptr += sizeof(squashfs_dev_inode_header); break; case SQUASHFS_FIFO_TYPE: (*fifo_count) ++; cur_ptr += sizeof(squashfs_ipc_inode_header); break; case SQUASHFS_SOCKET_TYPE: (*sock_count) ++; cur_ptr += sizeof(squashfs_ipc_inode_header); break; default: ERROR("Unknown inode type %d in scan_inode_table!\n", inode.inode_type); goto failed; } } return files; failed: free(*inode_table); return FALSE; }
int write_file(char *pathname, unsigned int fragment, unsigned int frag_bytes, unsigned int offset, unsigned int blocks, long long start, char *block_ptr, unsigned int mode) { unsigned int file_fd, bytes, i; unsigned int *block_list; TRACE("write_file: regular file, blocks %d\n", blocks); if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) { ERROR("write_file: unable to malloc block list\n"); return FALSE; } if(swap) { unsigned int sblock_list[blocks]; memcpy(sblock_list, block_ptr, blocks * sizeof(unsigned int)); SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks); } else memcpy(block_list, block_ptr, blocks * sizeof(unsigned int)); if((file_fd = open(pathname, O_CREAT | O_WRONLY, (mode_t) mode)) == -1) { ERROR("write_file: failed to create file %s, because %s\n", pathname, strerror(errno)); free(block_list); return FALSE; } for(i = 0; i < blocks; i++) { if((bytes = read_data_block(start, block_list[i], file_data)) == 0) { ERROR("write_file: failed to read data block 0x%llx\n", start); goto failure; } if(write(file_fd, file_data, bytes) < bytes) { ERROR("write_file: failed to write data block 0x%llx\n", start); goto failure; } start += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]); } if(frag_bytes != 0) { char *fragment_data = read_fragment(fragment); if(fragment_data == NULL) goto failure; if(write(file_fd, fragment_data + offset, frag_bytes) < frag_bytes) { ERROR("write_file: failed to write fragment %d\n", fragment); goto failure; } } close(file_fd); return TRUE; failure: close(file_fd); free(block_list); return FALSE; }
struct inode *read_inode_4(unsigned int start_block, unsigned int offset) { static union squashfs_inode_header header; long long start = sBlk.s.inode_table_start + start_block; int bytes = lookup_entry(inode_table_hash, start); char *block_ptr = inode_table + bytes + offset; static struct inode i; TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset); if(bytes == -1) EXIT_UNSQUASH("read_inode: inode table block %lld not found\n", start); SQUASHFS_SWAP_BASE_INODE_HEADER(&header.base, block_ptr); i.uid = (uid_t) id_table[header.base.uid]; i.gid = (uid_t) id_table[header.base.guid]; i.mode = lookup_type[header.base.inode_type] | header.base.mode; i.type = header.base.inode_type; i.time = header.base.mtime; i.inode_number = header.base.inode_number; switch(header.base.inode_type) { case SQUASHFS_DIR_TYPE: { struct squashfs_dir_inode_header *inode = &header.dir; SQUASHFS_SWAP_DIR_INODE_HEADER(inode, block_ptr); i.data = inode->file_size; i.offset = inode->offset; i.start = inode->start_block; i.xattr = SQUASHFS_INVALID_XATTR; break; } case SQUASHFS_LDIR_TYPE: { struct squashfs_ldir_inode_header *inode = &header.ldir; SQUASHFS_SWAP_LDIR_INODE_HEADER(inode, block_ptr); i.data = inode->file_size; i.offset = inode->offset; i.start = inode->start_block; i.xattr = inode->xattr; break; } case SQUASHFS_FILE_TYPE: { struct squashfs_reg_inode_header *inode = &header.reg; SQUASHFS_SWAP_REG_INODE_HEADER(inode, block_ptr); i.data = inode->file_size; i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk.s.block_size; i.fragment = inode->fragment; i.offset = inode->offset; i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (i.data + sBlk.s.block_size - 1) >> sBlk.s.block_log : i.data >> sBlk.s.block_log; i.start = inode->start_block; i.sparse = 0; i.block_ptr = block_ptr + sizeof(*inode); i.xattr = SQUASHFS_INVALID_XATTR; break; } case SQUASHFS_LREG_TYPE: { struct squashfs_lreg_inode_header *inode = &header.lreg; SQUASHFS_SWAP_LREG_INODE_HEADER(inode, block_ptr); i.data = inode->file_size; i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk.s.block_size; i.fragment = inode->fragment; i.offset = inode->offset; i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size + sBlk.s.block_size - 1) >> sBlk.s.block_log : inode->file_size >> sBlk.s.block_log; i.start = inode->start_block; i.sparse = inode->sparse != 0; i.block_ptr = block_ptr + sizeof(*inode); i.xattr = inode->xattr; break; } case SQUASHFS_SYMLINK_TYPE: case SQUASHFS_LSYMLINK_TYPE: { struct squashfs_symlink_inode_header *inode = &header.symlink; SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inode, block_ptr); i.symlink = malloc(inode->symlink_size + 1); if(i.symlink == NULL) EXIT_UNSQUASH("read_inode: failed to malloc " "symlink data\n"); strncpy(i.symlink, block_ptr + sizeof(struct squashfs_symlink_inode_header), inode->symlink_size); i.symlink[inode->symlink_size] = '\0'; i.data = inode->symlink_size; if(header.base.inode_type == SQUASHFS_LSYMLINK_TYPE) SQUASHFS_SWAP_INTS(&i.xattr, block_ptr + sizeof(struct squashfs_symlink_inode_header) + inode->symlink_size, 1); else i.xattr = SQUASHFS_INVALID_XATTR; break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: { struct squashfs_dev_inode_header *inode = &header.dev; SQUASHFS_SWAP_DEV_INODE_HEADER(inode, block_ptr); i.data = inode->rdev; i.xattr = SQUASHFS_INVALID_XATTR; break; } case SQUASHFS_LBLKDEV_TYPE: case SQUASHFS_LCHRDEV_TYPE: { struct squashfs_ldev_inode_header *inode = &header.ldev; SQUASHFS_SWAP_LDEV_INODE_HEADER(inode, block_ptr); i.data = inode->rdev; i.xattr = inode->xattr; break; } case SQUASHFS_FIFO_TYPE: case SQUASHFS_SOCKET_TYPE: i.data = 0; i.xattr = SQUASHFS_INVALID_XATTR; break; case SQUASHFS_LFIFO_TYPE: case SQUASHFS_LSOCKET_TYPE: { struct squashfs_lipc_inode_header *inode = &header.lipc; SQUASHFS_SWAP_LIPC_INODE_HEADER(inode, block_ptr); i.data = 0; i.xattr = inode->xattr; break; } default: EXIT_UNSQUASH("Unknown inode type %d in read_inode!\n", header.base.inode_type); } return &i; }