Пример #1
0
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;
}
Пример #2
0
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,
		squashfs_inode **inode_lookup_table)
{
	unsigned char *inode_table = NULL, *directory_table;
	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)
		goto error;

	if(read_inode_lookup_table(fd, sBlk, inode_lookup_table) == 0)
		goto error;

	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;
	}

	*uncompressed_inode = root_inode_block;

	printf("Read existing filesystem, %d inodes scanned\n", files);

	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;
		}

		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);

		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);

		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);

		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);
		else {
			squashfs_uid uids_copy[sBlk->no_uids];

			read_bytes(fd, sBlk->uid_start, sBlk->no_uids * sizeof(squashfs_uid), (char *) uids_copy);
			SQUASHFS_SWAP_DATA(uids, uids_copy, sBlk->no_uids, sizeof(squashfs_uid) * 8);
		}

		if(!swap)
			read_bytes(fd, sBlk->guid_start, sBlk->no_guids * sizeof(squashfs_uid), (char *) guids);
		else {
			squashfs_uid guids_copy[sBlk->no_guids];

			read_bytes(fd, sBlk->guid_start, sBlk->no_guids * sizeof(squashfs_uid), (char *) guids_copy);
			SQUASHFS_SWAP_DATA(guids, guids_copy, sBlk->no_guids, sizeof(squashfs_uid) * 8);
		}
		*uid_count = sBlk->no_uids;
		*guid_count = sBlk->no_guids;

		free(inode_table);
		free(directory_table);
		return sBlk->inode_table_start;
	}

error:
	return 0;
}
/*
 * Initialise VFS inode by reading inode from inode table (compressed
 * metadata).  The format and amount of data read depends on type.
 */
int squashfs_read_inode(struct inode *inode, long long ino)
{
	struct super_block *sb = inode->i_sb;
	struct squashfs_sb_info *msblk = sb->s_fs_info;
	u64 block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
	int err, type, offset = SQUASHFS_INODE_OFFSET(ino);
	union squashfs_inode squashfs_ino;
	struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base;
	int xattr_id = SQUASHFS_INVALID_XATTR;

	TRACE("Entered squashfs_read_inode\n");

	/*
	 * Read inode base common to all inode types.
	 */
	err = squashfs_read_metadata(sb, sqshb_ino, &block,
				&offset, sizeof(*sqshb_ino));
	if (err < 0)
		goto failed_read;

	err = squashfs_new_inode(sb, inode, sqshb_ino);
	if (err)
		goto failed_read;

	block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
	offset = SQUASHFS_INODE_OFFSET(ino);

	type = le16_to_cpu(sqshb_ino->inode_type);
	switch (type) {
	case SQUASHFS_REG_TYPE: {
		unsigned int frag_offset, frag;
		int frag_size;
		u64 frag_blk;
		struct squashfs_reg_inode *sqsh_ino = &squashfs_ino.reg;

		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
							sizeof(*sqsh_ino));
		if (err < 0)
			goto failed_read;

		frag = le32_to_cpu(sqsh_ino->fragment);
		if (frag != SQUASHFS_INVALID_FRAG) {
			frag_offset = le32_to_cpu(sqsh_ino->offset);
			frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
			if (frag_size < 0) {
				err = frag_size;
				goto failed_read;
			}
		} else {
			frag_blk = SQUASHFS_INVALID_BLK;
			frag_size = 0;
			frag_offset = 0;
		}

		set_nlink(inode, 1);
		inode->i_size = le32_to_cpu(sqsh_ino->file_size);
		inode->i_fop = &generic_ro_fops;
		inode->i_mode |= S_IFREG;
		inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
		squashfs_i(inode)->fragment_block = frag_blk;
		squashfs_i(inode)->fragment_size = frag_size;
		squashfs_i(inode)->fragment_offset = frag_offset;
		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
		squashfs_i(inode)->block_list_start = block;
		squashfs_i(inode)->offset = offset;
		inode->i_data.a_ops = &squashfs_aops;

		TRACE("File inode %x:%x, start_block %llx, block_list_start "
			"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
			offset, squashfs_i(inode)->start, block, offset);
		break;
	}
	case SQUASHFS_LREG_TYPE: {
		unsigned int frag_offset, frag;
		int frag_size;
		u64 frag_blk;
		struct squashfs_lreg_inode *sqsh_ino = &squashfs_ino.lreg;

		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
							sizeof(*sqsh_ino));
		if (err < 0)
			goto failed_read;

		frag = le32_to_cpu(sqsh_ino->fragment);
		if (frag != SQUASHFS_INVALID_FRAG) {
			frag_offset = le32_to_cpu(sqsh_ino->offset);
			frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
			if (frag_size < 0) {
				err = frag_size;
				goto failed_read;
			}
		} else {
			frag_blk = SQUASHFS_INVALID_BLK;
			frag_size = 0;
			frag_offset = 0;
		}

		xattr_id = le32_to_cpu(sqsh_ino->xattr);
		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
		inode->i_size = le64_to_cpu(sqsh_ino->file_size);
		inode->i_op = &squashfs_inode_ops;
		inode->i_fop = &generic_ro_fops;
		inode->i_mode |= S_IFREG;
		inode->i_blocks = (inode->i_size -
				le64_to_cpu(sqsh_ino->sparse) + 511) >> 9;

		squashfs_i(inode)->fragment_block = frag_blk;
		squashfs_i(inode)->fragment_size = frag_size;
		squashfs_i(inode)->fragment_offset = frag_offset;
		squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block);
		squashfs_i(inode)->block_list_start = block;
		squashfs_i(inode)->offset = offset;
		inode->i_data.a_ops = &squashfs_aops;

		TRACE("File inode %x:%x, start_block %llx, block_list_start "
			"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
			offset, squashfs_i(inode)->start, block, offset);
		break;
	}
	case SQUASHFS_DIR_TYPE: {
		struct squashfs_dir_inode *sqsh_ino = &squashfs_ino.dir;

		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
				sizeof(*sqsh_ino));
		if (err < 0)
			goto failed_read;

		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
		inode->i_size = le16_to_cpu(sqsh_ino->file_size);
		inode->i_op = &squashfs_dir_inode_ops;
		inode->i_fop = &squashfs_dir_ops;
		inode->i_mode |= S_IFDIR;
		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
		squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
		squashfs_i(inode)->dir_idx_cnt = 0;
		squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);

		TRACE("Directory inode %x:%x, start_block %llx, offset %x\n",
				SQUASHFS_INODE_BLK(ino), offset,
				squashfs_i(inode)->start,
				le16_to_cpu(sqsh_ino->offset));
		break;
	}
	case SQUASHFS_LDIR_TYPE: {
		struct squashfs_ldir_inode *sqsh_ino = &squashfs_ino.ldir;

		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
				sizeof(*sqsh_ino));
		if (err < 0)
			goto failed_read;

		xattr_id = le32_to_cpu(sqsh_ino->xattr);
		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
		inode->i_size = le32_to_cpu(sqsh_ino->file_size);
		inode->i_op = &squashfs_dir_inode_ops;
		inode->i_fop = &squashfs_dir_ops;
		inode->i_mode |= S_IFDIR;
		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
		squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
		squashfs_i(inode)->dir_idx_start = block;
		squashfs_i(inode)->dir_idx_offset = offset;
		squashfs_i(inode)->dir_idx_cnt = le16_to_cpu(sqsh_ino->i_count);
		squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);

		TRACE("Long directory inode %x:%x, start_block %llx, offset "
				"%x\n", SQUASHFS_INODE_BLK(ino), offset,
				squashfs_i(inode)->start,
				le16_to_cpu(sqsh_ino->offset));
		break;
	}
	case SQUASHFS_SYMLINK_TYPE:
	case SQUASHFS_LSYMLINK_TYPE: {
		struct squashfs_symlink_inode *sqsh_ino = &squashfs_ino.symlink;

		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
				sizeof(*sqsh_ino));
		if (err < 0)
			goto failed_read;

		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
		inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
		inode->i_op = &squashfs_symlink_inode_ops;
		inode->i_data.a_ops = &squashfs_symlink_aops;
		inode->i_mode |= S_IFLNK;
		squashfs_i(inode)->start = block;
		squashfs_i(inode)->offset = offset;

		if (type == SQUASHFS_LSYMLINK_TYPE) {
			__le32 xattr;

			err = squashfs_read_metadata(sb, NULL, &block,
						&offset, inode->i_size);
			if (err < 0)
				goto failed_read;
			err = squashfs_read_metadata(sb, &xattr, &block,
						&offset, sizeof(xattr));
			if (err < 0)
				goto failed_read;
			xattr_id = le32_to_cpu(xattr);
		}

		TRACE("Symbolic link inode %x:%x, start_block %llx, offset "
				"%x\n", SQUASHFS_INODE_BLK(ino), offset,
				block, offset);
		break;
	}
	case SQUASHFS_BLKDEV_TYPE:
	case SQUASHFS_CHRDEV_TYPE: {
		struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev;
		unsigned int rdev;

		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
				sizeof(*sqsh_ino));
		if (err < 0)
			goto failed_read;

		if (type == SQUASHFS_CHRDEV_TYPE)
			inode->i_mode |= S_IFCHR;
		else
			inode->i_mode |= S_IFBLK;
		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
		rdev = le32_to_cpu(sqsh_ino->rdev);
		init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));

		TRACE("Device inode %x:%x, rdev %x\n",
				SQUASHFS_INODE_BLK(ino), offset, rdev);
		break;
	}
	case SQUASHFS_LBLKDEV_TYPE:
	case SQUASHFS_LCHRDEV_TYPE: {
		struct squashfs_ldev_inode *sqsh_ino = &squashfs_ino.ldev;
		unsigned int rdev;

		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
				sizeof(*sqsh_ino));
		if (err < 0)
			goto failed_read;

		if (type == SQUASHFS_LCHRDEV_TYPE)
			inode->i_mode |= S_IFCHR;
		else
			inode->i_mode |= S_IFBLK;
		xattr_id = le32_to_cpu(sqsh_ino->xattr);
		inode->i_op = &squashfs_inode_ops;
		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
		rdev = le32_to_cpu(sqsh_ino->rdev);
		init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));

		TRACE("Device inode %x:%x, rdev %x\n",
				SQUASHFS_INODE_BLK(ino), offset, rdev);
		break;
	}
	case SQUASHFS_FIFO_TYPE:
	case SQUASHFS_SOCKET_TYPE: {
		struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc;

		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
				sizeof(*sqsh_ino));
		if (err < 0)
			goto failed_read;

		if (type == SQUASHFS_FIFO_TYPE)
			inode->i_mode |= S_IFIFO;
		else
			inode->i_mode |= S_IFSOCK;
		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
		init_special_inode(inode, inode->i_mode, 0);
		break;
	}
	case SQUASHFS_LFIFO_TYPE:
	case SQUASHFS_LSOCKET_TYPE: {
		struct squashfs_lipc_inode *sqsh_ino = &squashfs_ino.lipc;

		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
				sizeof(*sqsh_ino));
		if (err < 0)
			goto failed_read;

		if (type == SQUASHFS_LFIFO_TYPE)
			inode->i_mode |= S_IFIFO;
		else
			inode->i_mode |= S_IFSOCK;
		xattr_id = le32_to_cpu(sqsh_ino->xattr);
		inode->i_op = &squashfs_inode_ops;
		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
		init_special_inode(inode, inode->i_mode, 0);
		break;
	}
	default:
		ERROR("Unknown inode type %d in squashfs_iget!\n", type);
		return -EINVAL;
	}

	if (xattr_id != SQUASHFS_INVALID_XATTR && msblk->xattr_id_table) {
		err = squashfs_xattr_lookup(sb, xattr_id,
					&squashfs_i(inode)->xattr_count,
					&squashfs_i(inode)->xattr_size,
					&squashfs_i(inode)->xattr);
		if (err < 0)
			goto failed_read;
		inode->i_blocks += ((squashfs_i(inode)->xattr_size - 1) >> 9)
				+ 1;
	} else
Пример #4
0
static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode)
{
    struct super_block *s = i->i_sb;
    struct squashfs_sb_info *msblk = s->s_fs_info;
    struct squashfs_super_block *sblk = &msblk->sblk;
    unsigned int block = SQUASHFS_INODE_BLK(inode) +
                         sblk->inode_table_start;
    unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
    unsigned int ino = i->i_ino;
    long long next_block;
    unsigned int next_offset;
    union squashfs_inode_header_2 id, sid;
    struct squashfs_base_inode_header_2 *inodeb = &id.base,
                                             *sinodeb = &sid.base;

    TRACE("Entered squashfs_iget\n");

    if (msblk->swap) {
        if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
                                       offset, sizeof(*sinodeb), &next_block,
                                       &next_offset))
            goto failed_read;
        SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
                                          sizeof(*sinodeb));
    } else if (!squashfs_get_cached_block(s, (char *) inodeb, block,
                                          offset, sizeof(*inodeb), &next_block,
                                          &next_offset))
        goto failed_read;

    squashfs_new_inode(msblk, i, inodeb, ino);

    switch(inodeb->inode_type) {
    case SQUASHFS_FILE_TYPE: {
        struct squashfs_reg_inode_header_2 *inodep = &id.reg;
        struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
        long long frag_blk;
        unsigned int frag_size = 0;

        if (msblk->swap) {
            if (!squashfs_get_cached_block(s, (char *)
                                           sinodep, block, offset,
                                           sizeof(*sinodep), &next_block,
                                           &next_offset))
                goto failed_read;
            SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
        } else if (!squashfs_get_cached_block(s, (char *)
                                              inodep, block, offset,
                                              sizeof(*inodep), &next_block,
                                              &next_offset))
            goto failed_read;

        frag_blk = SQUASHFS_INVALID_BLK;
        if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
                !get_fragment_location_2(s,
                                         inodep->fragment, &frag_blk, &frag_size))
            goto failed_read;

        i->i_size = inodep->file_size;
        i->i_fop = &generic_ro_fops;
        i->i_mode |= S_IFREG;
        i->i_mtime.tv_sec = inodep->mtime;
        i->i_atime.tv_sec = inodep->mtime;
        i->i_ctime.tv_sec = inodep->mtime;
        i->i_blocks = ((i->i_size - 1) >> 9) + 1;
        SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
        SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
        SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
        SQUASHFS_I(i)->start_block = inodep->start_block;
        SQUASHFS_I(i)->u.s1.block_list_start = next_block;
        SQUASHFS_I(i)->offset = next_offset;
        if (sblk->block_size > 4096)
            i->i_data.a_ops = &squashfs_aops;
        else
            i->i_data.a_ops = &squashfs_aops_4K;

        TRACE("File inode %x:%x, start_block %x, "
              "block_list_start %llx, offset %x\n",
              SQUASHFS_INODE_BLK(inode), offset,
              inodep->start_block, next_block,
              next_offset);
        break;
    }
    case SQUASHFS_DIR_TYPE: {
        struct squashfs_dir_inode_header_2 *inodep = &id.dir;
        struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;

        if (msblk->swap) {
            if (!squashfs_get_cached_block(s, (char *)
                                           sinodep, block, offset,
                                           sizeof(*sinodep), &next_block,
                                           &next_offset))
                goto failed_read;
            SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
        } else if (!squashfs_get_cached_block(s, (char *)
                                              inodep, block, offset,
                                              sizeof(*inodep), &next_block,
                                              &next_offset))
            goto failed_read;

        i->i_size = inodep->file_size;
        i->i_op = &squashfs_dir_inode_ops_2;
        i->i_fop = &squashfs_dir_ops_2;
        i->i_mode |= S_IFDIR;
        i->i_mtime.tv_sec = inodep->mtime;
        i->i_atime.tv_sec = inodep->mtime;
        i->i_ctime.tv_sec = inodep->mtime;
        SQUASHFS_I(i)->start_block = inodep->start_block;
        SQUASHFS_I(i)->offset = inodep->offset;
        SQUASHFS_I(i)->u.s2.directory_index_count = 0;
        SQUASHFS_I(i)->u.s2.parent_inode = 0;

        TRACE("Directory inode %x:%x, start_block %x, offset "
              "%x\n", SQUASHFS_INODE_BLK(inode),
              offset, inodep->start_block,
              inodep->offset);
        break;
    }
    case SQUASHFS_LDIR_TYPE: {
        struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
        struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;

        if (msblk->swap) {
            if (!squashfs_get_cached_block(s, (char *)
                                           sinodep, block, offset,
                                           sizeof(*sinodep), &next_block,
                                           &next_offset))
                goto failed_read;
            SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
                                              sinodep);
        } else if (!squashfs_get_cached_block(s, (char *)
                                              inodep, block, offset,
                                              sizeof(*inodep), &next_block,
                                              &next_offset))
            goto failed_read;

        i->i_size = inodep->file_size;
        i->i_op = &squashfs_dir_inode_ops_2;
        i->i_fop = &squashfs_dir_ops_2;
        i->i_mode |= S_IFDIR;
        i->i_mtime.tv_sec = inodep->mtime;
        i->i_atime.tv_sec = inodep->mtime;
        i->i_ctime.tv_sec = inodep->mtime;
        SQUASHFS_I(i)->start_block = inodep->start_block;
        SQUASHFS_I(i)->offset = inodep->offset;
        SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
        SQUASHFS_I(i)->u.s2.directory_index_offset =
            next_offset;
        SQUASHFS_I(i)->u.s2.directory_index_count =
            inodep->i_count;
        SQUASHFS_I(i)->u.s2.parent_inode = 0;

        TRACE("Long directory inode %x:%x, start_block %x, "
              "offset %x\n",
              SQUASHFS_INODE_BLK(inode), offset,
              inodep->start_block, inodep->offset);
        break;
    }
    case SQUASHFS_SYMLINK_TYPE: {
        struct squashfs_symlink_inode_header_2 *inodep =
                &id.symlink;
        struct squashfs_symlink_inode_header_2 *sinodep =
                &sid.symlink;

        if (msblk->swap) {
            if (!squashfs_get_cached_block(s, (char *)
                                           sinodep, block, offset,
                                           sizeof(*sinodep), &next_block,
                                           &next_offset))
                goto failed_read;
            SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
                                                 sinodep);
        } else if (!squashfs_get_cached_block(s, (char *)
                                              inodep, block, offset,
                                              sizeof(*inodep), &next_block,
                                              &next_offset))
            goto failed_read;

        i->i_size = inodep->symlink_size;
        i->i_op = &page_symlink_inode_operations;
        i->i_data.a_ops = &squashfs_symlink_aops;
        i->i_mode |= S_IFLNK;
        SQUASHFS_I(i)->start_block = next_block;
        SQUASHFS_I(i)->offset = next_offset;

        TRACE("Symbolic link inode %x:%x, start_block %llx, "
              "offset %x\n",
              SQUASHFS_INODE_BLK(inode), offset,
              next_block, next_offset);
        break;
    }
    case SQUASHFS_BLKDEV_TYPE:
    case SQUASHFS_CHRDEV_TYPE: {
        struct squashfs_dev_inode_header_2 *inodep = &id.dev;
        struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;

        if (msblk->swap) {
            if (!squashfs_get_cached_block(s, (char *)
                                           sinodep, block, offset,
                                           sizeof(*sinodep), &next_block,
                                           &next_offset))
                goto failed_read;
            SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
        } else if (!squashfs_get_cached_block(s, (char *)
                                              inodep, block, offset,
                                              sizeof(*inodep), &next_block,
                                              &next_offset))
            goto failed_read;

        i->i_mode |= (inodeb->inode_type ==
                      SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
                     S_IFBLK;
        init_special_inode(i, i->i_mode,
                           old_decode_dev(inodep->rdev));

        TRACE("Device inode %x:%x, rdev %x\n",
              SQUASHFS_INODE_BLK(inode), offset,
              inodep->rdev);
        break;
    }
    case SQUASHFS_FIFO_TYPE:
    case SQUASHFS_SOCKET_TYPE: {

        i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
                     ? S_IFIFO : S_IFSOCK;
        init_special_inode(i, i->i_mode, 0);
        break;
    }
    default:
        ERROR("Unknown inode type %d in squashfs_iget!\n",
              inodeb->inode_type);
        goto failed_read1;
    }

    return 1;

failed_read:
    ERROR("Unable to read inode [%x:%x]\n", block, offset);

failed_read1:
    return 0;
}