xref: /kernel/linux/linux-5.10/fs/squashfs/inode.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Squashfs - a compressed read only filesystem for Linux
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
68c2ecf20Sopenharmony_ci * Phillip Lougher <phillip@squashfs.org.uk>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * inode.c
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci * This file implements code to create and read inodes from disk.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Inodes in Squashfs are identified by a 48-bit inode which encodes the
158c2ecf20Sopenharmony_ci * location of the compressed metadata block containing the inode, and the byte
168c2ecf20Sopenharmony_ci * offset into that block where the inode is placed (<block, offset>).
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * To maximise compression there are different inodes for each file type
198c2ecf20Sopenharmony_ci * (regular file, directory, device, etc.), the inode contents and length
208c2ecf20Sopenharmony_ci * varying with the type.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * To further maximise compression, two types of regular file inode and
238c2ecf20Sopenharmony_ci * directory inode are defined: inodes optimised for frequently occurring
248c2ecf20Sopenharmony_ci * regular files and directories, and extended types where extra
258c2ecf20Sopenharmony_ci * information has to be stored.
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <linux/fs.h>
298c2ecf20Sopenharmony_ci#include <linux/vfs.h>
308c2ecf20Sopenharmony_ci#include <linux/xattr.h>
318c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include "squashfs_fs.h"
348c2ecf20Sopenharmony_ci#include "squashfs_fs_sb.h"
358c2ecf20Sopenharmony_ci#include "squashfs_fs_i.h"
368c2ecf20Sopenharmony_ci#include "squashfs.h"
378c2ecf20Sopenharmony_ci#include "xattr.h"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/*
408c2ecf20Sopenharmony_ci * Initialise VFS inode with the base inode information common to all
418c2ecf20Sopenharmony_ci * Squashfs inode types.  Sqsh_ino contains the unswapped base inode
428c2ecf20Sopenharmony_ci * off disk.
438c2ecf20Sopenharmony_ci */
448c2ecf20Sopenharmony_cistatic int squashfs_new_inode(struct super_block *sb, struct inode *inode,
458c2ecf20Sopenharmony_ci				struct squashfs_base_inode *sqsh_ino)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	uid_t i_uid;
488c2ecf20Sopenharmony_ci	gid_t i_gid;
498c2ecf20Sopenharmony_ci	int err;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	inode->i_ino = le32_to_cpu(sqsh_ino->inode_number);
528c2ecf20Sopenharmony_ci	if (inode->i_ino == 0)
538c2ecf20Sopenharmony_ci		return -EINVAL;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->uid), &i_uid);
568c2ecf20Sopenharmony_ci	if (err)
578c2ecf20Sopenharmony_ci		return err;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->guid), &i_gid);
608c2ecf20Sopenharmony_ci	if (err)
618c2ecf20Sopenharmony_ci		return err;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	i_uid_write(inode, i_uid);
648c2ecf20Sopenharmony_ci	i_gid_write(inode, i_gid);
658c2ecf20Sopenharmony_ci	inode->i_mtime.tv_sec = le32_to_cpu(sqsh_ino->mtime);
668c2ecf20Sopenharmony_ci	inode->i_atime.tv_sec = inode->i_mtime.tv_sec;
678c2ecf20Sopenharmony_ci	inode->i_ctime.tv_sec = inode->i_mtime.tv_sec;
688c2ecf20Sopenharmony_ci	inode->i_mode = le16_to_cpu(sqsh_ino->mode);
698c2ecf20Sopenharmony_ci	inode->i_size = 0;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	return err;
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistruct inode *squashfs_iget(struct super_block *sb, long long ino,
768c2ecf20Sopenharmony_ci				unsigned int ino_number)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct inode *inode = iget_locked(sb, ino_number);
798c2ecf20Sopenharmony_ci	int err;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	TRACE("Entered squashfs_iget\n");
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (!inode)
848c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
858c2ecf20Sopenharmony_ci	if (!(inode->i_state & I_NEW))
868c2ecf20Sopenharmony_ci		return inode;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	err = squashfs_read_inode(inode, ino);
898c2ecf20Sopenharmony_ci	if (err) {
908c2ecf20Sopenharmony_ci		iget_failed(inode);
918c2ecf20Sopenharmony_ci		return ERR_PTR(err);
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	unlock_new_inode(inode);
958c2ecf20Sopenharmony_ci	return inode;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/*
1008c2ecf20Sopenharmony_ci * Initialise VFS inode by reading inode from inode table (compressed
1018c2ecf20Sopenharmony_ci * metadata).  The format and amount of data read depends on type.
1028c2ecf20Sopenharmony_ci */
1038c2ecf20Sopenharmony_ciint squashfs_read_inode(struct inode *inode, long long ino)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
1068c2ecf20Sopenharmony_ci	struct squashfs_sb_info *msblk = sb->s_fs_info;
1078c2ecf20Sopenharmony_ci	u64 block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
1088c2ecf20Sopenharmony_ci	int err, type, offset = SQUASHFS_INODE_OFFSET(ino);
1098c2ecf20Sopenharmony_ci	union squashfs_inode squashfs_ino;
1108c2ecf20Sopenharmony_ci	struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base;
1118c2ecf20Sopenharmony_ci	int xattr_id = SQUASHFS_INVALID_XATTR;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	TRACE("Entered squashfs_read_inode\n");
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/*
1168c2ecf20Sopenharmony_ci	 * Read inode base common to all inode types.
1178c2ecf20Sopenharmony_ci	 */
1188c2ecf20Sopenharmony_ci	err = squashfs_read_metadata(sb, sqshb_ino, &block,
1198c2ecf20Sopenharmony_ci				&offset, sizeof(*sqshb_ino));
1208c2ecf20Sopenharmony_ci	if (err < 0)
1218c2ecf20Sopenharmony_ci		goto failed_read;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	err = squashfs_new_inode(sb, inode, sqshb_ino);
1248c2ecf20Sopenharmony_ci	if (err)
1258c2ecf20Sopenharmony_ci		goto failed_read;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
1288c2ecf20Sopenharmony_ci	offset = SQUASHFS_INODE_OFFSET(ino);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	type = le16_to_cpu(sqshb_ino->inode_type);
1318c2ecf20Sopenharmony_ci	switch (type) {
1328c2ecf20Sopenharmony_ci	case SQUASHFS_REG_TYPE: {
1338c2ecf20Sopenharmony_ci		unsigned int frag_offset, frag;
1348c2ecf20Sopenharmony_ci		int frag_size;
1358c2ecf20Sopenharmony_ci		u64 frag_blk;
1368c2ecf20Sopenharmony_ci		struct squashfs_reg_inode *sqsh_ino = &squashfs_ino.reg;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
1398c2ecf20Sopenharmony_ci							sizeof(*sqsh_ino));
1408c2ecf20Sopenharmony_ci		if (err < 0)
1418c2ecf20Sopenharmony_ci			goto failed_read;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci		frag = le32_to_cpu(sqsh_ino->fragment);
1448c2ecf20Sopenharmony_ci		if (frag != SQUASHFS_INVALID_FRAG) {
1458c2ecf20Sopenharmony_ci			frag_offset = le32_to_cpu(sqsh_ino->offset);
1468c2ecf20Sopenharmony_ci			frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
1478c2ecf20Sopenharmony_ci			if (frag_size < 0) {
1488c2ecf20Sopenharmony_ci				err = frag_size;
1498c2ecf20Sopenharmony_ci				goto failed_read;
1508c2ecf20Sopenharmony_ci			}
1518c2ecf20Sopenharmony_ci		} else {
1528c2ecf20Sopenharmony_ci			frag_blk = SQUASHFS_INVALID_BLK;
1538c2ecf20Sopenharmony_ci			frag_size = 0;
1548c2ecf20Sopenharmony_ci			frag_offset = 0;
1558c2ecf20Sopenharmony_ci		}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci		set_nlink(inode, 1);
1588c2ecf20Sopenharmony_ci		inode->i_size = le32_to_cpu(sqsh_ino->file_size);
1598c2ecf20Sopenharmony_ci		inode->i_fop = &generic_ro_fops;
1608c2ecf20Sopenharmony_ci		inode->i_mode |= S_IFREG;
1618c2ecf20Sopenharmony_ci		inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
1628c2ecf20Sopenharmony_ci		squashfs_i(inode)->fragment_block = frag_blk;
1638c2ecf20Sopenharmony_ci		squashfs_i(inode)->fragment_size = frag_size;
1648c2ecf20Sopenharmony_ci		squashfs_i(inode)->fragment_offset = frag_offset;
1658c2ecf20Sopenharmony_ci		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
1668c2ecf20Sopenharmony_ci		squashfs_i(inode)->block_list_start = block;
1678c2ecf20Sopenharmony_ci		squashfs_i(inode)->offset = offset;
1688c2ecf20Sopenharmony_ci		inode->i_data.a_ops = &squashfs_aops;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci		TRACE("File inode %x:%x, start_block %llx, block_list_start "
1718c2ecf20Sopenharmony_ci			"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
1728c2ecf20Sopenharmony_ci			offset, squashfs_i(inode)->start, block, offset);
1738c2ecf20Sopenharmony_ci		break;
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci	case SQUASHFS_LREG_TYPE: {
1768c2ecf20Sopenharmony_ci		unsigned int frag_offset, frag;
1778c2ecf20Sopenharmony_ci		int frag_size;
1788c2ecf20Sopenharmony_ci		u64 frag_blk;
1798c2ecf20Sopenharmony_ci		struct squashfs_lreg_inode *sqsh_ino = &squashfs_ino.lreg;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
1828c2ecf20Sopenharmony_ci							sizeof(*sqsh_ino));
1838c2ecf20Sopenharmony_ci		if (err < 0)
1848c2ecf20Sopenharmony_ci			goto failed_read;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		frag = le32_to_cpu(sqsh_ino->fragment);
1878c2ecf20Sopenharmony_ci		if (frag != SQUASHFS_INVALID_FRAG) {
1888c2ecf20Sopenharmony_ci			frag_offset = le32_to_cpu(sqsh_ino->offset);
1898c2ecf20Sopenharmony_ci			frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
1908c2ecf20Sopenharmony_ci			if (frag_size < 0) {
1918c2ecf20Sopenharmony_ci				err = frag_size;
1928c2ecf20Sopenharmony_ci				goto failed_read;
1938c2ecf20Sopenharmony_ci			}
1948c2ecf20Sopenharmony_ci		} else {
1958c2ecf20Sopenharmony_ci			frag_blk = SQUASHFS_INVALID_BLK;
1968c2ecf20Sopenharmony_ci			frag_size = 0;
1978c2ecf20Sopenharmony_ci			frag_offset = 0;
1988c2ecf20Sopenharmony_ci		}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		xattr_id = le32_to_cpu(sqsh_ino->xattr);
2018c2ecf20Sopenharmony_ci		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
2028c2ecf20Sopenharmony_ci		inode->i_size = le64_to_cpu(sqsh_ino->file_size);
2038c2ecf20Sopenharmony_ci		inode->i_op = &squashfs_inode_ops;
2048c2ecf20Sopenharmony_ci		inode->i_fop = &generic_ro_fops;
2058c2ecf20Sopenharmony_ci		inode->i_mode |= S_IFREG;
2068c2ecf20Sopenharmony_ci		inode->i_blocks = (inode->i_size -
2078c2ecf20Sopenharmony_ci				le64_to_cpu(sqsh_ino->sparse) + 511) >> 9;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		squashfs_i(inode)->fragment_block = frag_blk;
2108c2ecf20Sopenharmony_ci		squashfs_i(inode)->fragment_size = frag_size;
2118c2ecf20Sopenharmony_ci		squashfs_i(inode)->fragment_offset = frag_offset;
2128c2ecf20Sopenharmony_ci		squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block);
2138c2ecf20Sopenharmony_ci		squashfs_i(inode)->block_list_start = block;
2148c2ecf20Sopenharmony_ci		squashfs_i(inode)->offset = offset;
2158c2ecf20Sopenharmony_ci		inode->i_data.a_ops = &squashfs_aops;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		TRACE("File inode %x:%x, start_block %llx, block_list_start "
2188c2ecf20Sopenharmony_ci			"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
2198c2ecf20Sopenharmony_ci			offset, squashfs_i(inode)->start, block, offset);
2208c2ecf20Sopenharmony_ci		break;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci	case SQUASHFS_DIR_TYPE: {
2238c2ecf20Sopenharmony_ci		struct squashfs_dir_inode *sqsh_ino = &squashfs_ino.dir;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
2268c2ecf20Sopenharmony_ci				sizeof(*sqsh_ino));
2278c2ecf20Sopenharmony_ci		if (err < 0)
2288c2ecf20Sopenharmony_ci			goto failed_read;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
2318c2ecf20Sopenharmony_ci		inode->i_size = le16_to_cpu(sqsh_ino->file_size);
2328c2ecf20Sopenharmony_ci		inode->i_op = &squashfs_dir_inode_ops;
2338c2ecf20Sopenharmony_ci		inode->i_fop = &squashfs_dir_ops;
2348c2ecf20Sopenharmony_ci		inode->i_mode |= S_IFDIR;
2358c2ecf20Sopenharmony_ci		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
2368c2ecf20Sopenharmony_ci		squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
2378c2ecf20Sopenharmony_ci		squashfs_i(inode)->dir_idx_cnt = 0;
2388c2ecf20Sopenharmony_ci		squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci		TRACE("Directory inode %x:%x, start_block %llx, offset %x\n",
2418c2ecf20Sopenharmony_ci				SQUASHFS_INODE_BLK(ino), offset,
2428c2ecf20Sopenharmony_ci				squashfs_i(inode)->start,
2438c2ecf20Sopenharmony_ci				le16_to_cpu(sqsh_ino->offset));
2448c2ecf20Sopenharmony_ci		break;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci	case SQUASHFS_LDIR_TYPE: {
2478c2ecf20Sopenharmony_ci		struct squashfs_ldir_inode *sqsh_ino = &squashfs_ino.ldir;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
2508c2ecf20Sopenharmony_ci				sizeof(*sqsh_ino));
2518c2ecf20Sopenharmony_ci		if (err < 0)
2528c2ecf20Sopenharmony_ci			goto failed_read;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci		xattr_id = le32_to_cpu(sqsh_ino->xattr);
2558c2ecf20Sopenharmony_ci		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
2568c2ecf20Sopenharmony_ci		inode->i_size = le32_to_cpu(sqsh_ino->file_size);
2578c2ecf20Sopenharmony_ci		inode->i_op = &squashfs_dir_inode_ops;
2588c2ecf20Sopenharmony_ci		inode->i_fop = &squashfs_dir_ops;
2598c2ecf20Sopenharmony_ci		inode->i_mode |= S_IFDIR;
2608c2ecf20Sopenharmony_ci		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
2618c2ecf20Sopenharmony_ci		squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
2628c2ecf20Sopenharmony_ci		squashfs_i(inode)->dir_idx_start = block;
2638c2ecf20Sopenharmony_ci		squashfs_i(inode)->dir_idx_offset = offset;
2648c2ecf20Sopenharmony_ci		squashfs_i(inode)->dir_idx_cnt = le16_to_cpu(sqsh_ino->i_count);
2658c2ecf20Sopenharmony_ci		squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		TRACE("Long directory inode %x:%x, start_block %llx, offset "
2688c2ecf20Sopenharmony_ci				"%x\n", SQUASHFS_INODE_BLK(ino), offset,
2698c2ecf20Sopenharmony_ci				squashfs_i(inode)->start,
2708c2ecf20Sopenharmony_ci				le16_to_cpu(sqsh_ino->offset));
2718c2ecf20Sopenharmony_ci		break;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci	case SQUASHFS_SYMLINK_TYPE:
2748c2ecf20Sopenharmony_ci	case SQUASHFS_LSYMLINK_TYPE: {
2758c2ecf20Sopenharmony_ci		struct squashfs_symlink_inode *sqsh_ino = &squashfs_ino.symlink;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
2788c2ecf20Sopenharmony_ci				sizeof(*sqsh_ino));
2798c2ecf20Sopenharmony_ci		if (err < 0)
2808c2ecf20Sopenharmony_ci			goto failed_read;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
2838c2ecf20Sopenharmony_ci		if (inode->i_size > PAGE_SIZE) {
2848c2ecf20Sopenharmony_ci			ERROR("Corrupted symlink\n");
2858c2ecf20Sopenharmony_ci			return -EINVAL;
2868c2ecf20Sopenharmony_ci		}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
2898c2ecf20Sopenharmony_ci		inode->i_op = &squashfs_symlink_inode_ops;
2908c2ecf20Sopenharmony_ci		inode_nohighmem(inode);
2918c2ecf20Sopenharmony_ci		inode->i_data.a_ops = &squashfs_symlink_aops;
2928c2ecf20Sopenharmony_ci		inode->i_mode |= S_IFLNK;
2938c2ecf20Sopenharmony_ci		squashfs_i(inode)->start = block;
2948c2ecf20Sopenharmony_ci		squashfs_i(inode)->offset = offset;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci		if (type == SQUASHFS_LSYMLINK_TYPE) {
2978c2ecf20Sopenharmony_ci			__le32 xattr;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci			err = squashfs_read_metadata(sb, NULL, &block,
3008c2ecf20Sopenharmony_ci						&offset, inode->i_size);
3018c2ecf20Sopenharmony_ci			if (err < 0)
3028c2ecf20Sopenharmony_ci				goto failed_read;
3038c2ecf20Sopenharmony_ci			err = squashfs_read_metadata(sb, &xattr, &block,
3048c2ecf20Sopenharmony_ci						&offset, sizeof(xattr));
3058c2ecf20Sopenharmony_ci			if (err < 0)
3068c2ecf20Sopenharmony_ci				goto failed_read;
3078c2ecf20Sopenharmony_ci			xattr_id = le32_to_cpu(xattr);
3088c2ecf20Sopenharmony_ci		}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci		TRACE("Symbolic link inode %x:%x, start_block %llx, offset "
3118c2ecf20Sopenharmony_ci				"%x\n", SQUASHFS_INODE_BLK(ino), offset,
3128c2ecf20Sopenharmony_ci				block, offset);
3138c2ecf20Sopenharmony_ci		break;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci	case SQUASHFS_BLKDEV_TYPE:
3168c2ecf20Sopenharmony_ci	case SQUASHFS_CHRDEV_TYPE: {
3178c2ecf20Sopenharmony_ci		struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev;
3188c2ecf20Sopenharmony_ci		unsigned int rdev;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
3218c2ecf20Sopenharmony_ci				sizeof(*sqsh_ino));
3228c2ecf20Sopenharmony_ci		if (err < 0)
3238c2ecf20Sopenharmony_ci			goto failed_read;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		if (type == SQUASHFS_CHRDEV_TYPE)
3268c2ecf20Sopenharmony_ci			inode->i_mode |= S_IFCHR;
3278c2ecf20Sopenharmony_ci		else
3288c2ecf20Sopenharmony_ci			inode->i_mode |= S_IFBLK;
3298c2ecf20Sopenharmony_ci		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
3308c2ecf20Sopenharmony_ci		rdev = le32_to_cpu(sqsh_ino->rdev);
3318c2ecf20Sopenharmony_ci		init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		TRACE("Device inode %x:%x, rdev %x\n",
3348c2ecf20Sopenharmony_ci				SQUASHFS_INODE_BLK(ino), offset, rdev);
3358c2ecf20Sopenharmony_ci		break;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci	case SQUASHFS_LBLKDEV_TYPE:
3388c2ecf20Sopenharmony_ci	case SQUASHFS_LCHRDEV_TYPE: {
3398c2ecf20Sopenharmony_ci		struct squashfs_ldev_inode *sqsh_ino = &squashfs_ino.ldev;
3408c2ecf20Sopenharmony_ci		unsigned int rdev;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
3438c2ecf20Sopenharmony_ci				sizeof(*sqsh_ino));
3448c2ecf20Sopenharmony_ci		if (err < 0)
3458c2ecf20Sopenharmony_ci			goto failed_read;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		if (type == SQUASHFS_LCHRDEV_TYPE)
3488c2ecf20Sopenharmony_ci			inode->i_mode |= S_IFCHR;
3498c2ecf20Sopenharmony_ci		else
3508c2ecf20Sopenharmony_ci			inode->i_mode |= S_IFBLK;
3518c2ecf20Sopenharmony_ci		xattr_id = le32_to_cpu(sqsh_ino->xattr);
3528c2ecf20Sopenharmony_ci		inode->i_op = &squashfs_inode_ops;
3538c2ecf20Sopenharmony_ci		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
3548c2ecf20Sopenharmony_ci		rdev = le32_to_cpu(sqsh_ino->rdev);
3558c2ecf20Sopenharmony_ci		init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		TRACE("Device inode %x:%x, rdev %x\n",
3588c2ecf20Sopenharmony_ci				SQUASHFS_INODE_BLK(ino), offset, rdev);
3598c2ecf20Sopenharmony_ci		break;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci	case SQUASHFS_FIFO_TYPE:
3628c2ecf20Sopenharmony_ci	case SQUASHFS_SOCKET_TYPE: {
3638c2ecf20Sopenharmony_ci		struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
3668c2ecf20Sopenharmony_ci				sizeof(*sqsh_ino));
3678c2ecf20Sopenharmony_ci		if (err < 0)
3688c2ecf20Sopenharmony_ci			goto failed_read;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci		if (type == SQUASHFS_FIFO_TYPE)
3718c2ecf20Sopenharmony_ci			inode->i_mode |= S_IFIFO;
3728c2ecf20Sopenharmony_ci		else
3738c2ecf20Sopenharmony_ci			inode->i_mode |= S_IFSOCK;
3748c2ecf20Sopenharmony_ci		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
3758c2ecf20Sopenharmony_ci		init_special_inode(inode, inode->i_mode, 0);
3768c2ecf20Sopenharmony_ci		break;
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci	case SQUASHFS_LFIFO_TYPE:
3798c2ecf20Sopenharmony_ci	case SQUASHFS_LSOCKET_TYPE: {
3808c2ecf20Sopenharmony_ci		struct squashfs_lipc_inode *sqsh_ino = &squashfs_ino.lipc;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
3838c2ecf20Sopenharmony_ci				sizeof(*sqsh_ino));
3848c2ecf20Sopenharmony_ci		if (err < 0)
3858c2ecf20Sopenharmony_ci			goto failed_read;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci		if (type == SQUASHFS_LFIFO_TYPE)
3888c2ecf20Sopenharmony_ci			inode->i_mode |= S_IFIFO;
3898c2ecf20Sopenharmony_ci		else
3908c2ecf20Sopenharmony_ci			inode->i_mode |= S_IFSOCK;
3918c2ecf20Sopenharmony_ci		xattr_id = le32_to_cpu(sqsh_ino->xattr);
3928c2ecf20Sopenharmony_ci		inode->i_op = &squashfs_inode_ops;
3938c2ecf20Sopenharmony_ci		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
3948c2ecf20Sopenharmony_ci		init_special_inode(inode, inode->i_mode, 0);
3958c2ecf20Sopenharmony_ci		break;
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci	default:
3988c2ecf20Sopenharmony_ci		ERROR("Unknown inode type %d in squashfs_iget!\n", type);
3998c2ecf20Sopenharmony_ci		return -EINVAL;
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (xattr_id != SQUASHFS_INVALID_XATTR && msblk->xattr_id_table) {
4038c2ecf20Sopenharmony_ci		err = squashfs_xattr_lookup(sb, xattr_id,
4048c2ecf20Sopenharmony_ci					&squashfs_i(inode)->xattr_count,
4058c2ecf20Sopenharmony_ci					&squashfs_i(inode)->xattr_size,
4068c2ecf20Sopenharmony_ci					&squashfs_i(inode)->xattr);
4078c2ecf20Sopenharmony_ci		if (err < 0)
4088c2ecf20Sopenharmony_ci			goto failed_read;
4098c2ecf20Sopenharmony_ci		inode->i_blocks += ((squashfs_i(inode)->xattr_size - 1) >> 9)
4108c2ecf20Sopenharmony_ci				+ 1;
4118c2ecf20Sopenharmony_ci	} else
4128c2ecf20Sopenharmony_ci		squashfs_i(inode)->xattr_count = 0;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	return 0;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cifailed_read:
4178c2ecf20Sopenharmony_ci	ERROR("Unable to read inode 0x%llx\n", ino);
4188c2ecf20Sopenharmony_ci	return err;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ciconst struct inode_operations squashfs_inode_ops = {
4238c2ecf20Sopenharmony_ci	.listxattr = squashfs_listxattr
4248c2ecf20Sopenharmony_ci};
4258c2ecf20Sopenharmony_ci
426