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