brintos

brintos / linux-shallow public Read only

0
0
Text · 12.0 KiB · d5918eb Raw
426 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Squashfs - a compressed read only filesystem for Linux4 *5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 20086 * Phillip Lougher <phillip@squashfs.org.uk>7 *8 * inode.c9 */10 11/*12 * This file implements code to create and read inodes from disk.13 *14 * Inodes in Squashfs are identified by a 48-bit inode which encodes the15 * location of the compressed metadata block containing the inode, and the byte16 * offset into that block where the inode is placed (<block, offset>).17 *18 * To maximise compression there are different inodes for each file type19 * (regular file, directory, device, etc.), the inode contents and length20 * varying with the type.21 *22 * To further maximise compression, two types of regular file inode and23 * directory inode are defined: inodes optimised for frequently occurring24 * regular files and directories, and extended types where extra25 * information has to be stored.26 */27 28#include <linux/fs.h>29#include <linux/vfs.h>30#include <linux/xattr.h>31#include <linux/pagemap.h>32 33#include "squashfs_fs.h"34#include "squashfs_fs_sb.h"35#include "squashfs_fs_i.h"36#include "squashfs.h"37#include "xattr.h"38 39/*40 * Initialise VFS inode with the base inode information common to all41 * Squashfs inode types.  Sqsh_ino contains the unswapped base inode42 * off disk.43 */44static int squashfs_new_inode(struct super_block *sb, struct inode *inode,45				struct squashfs_base_inode *sqsh_ino)46{47	uid_t i_uid;48	gid_t i_gid;49	int err;50 51	inode->i_ino = le32_to_cpu(sqsh_ino->inode_number);52	if (inode->i_ino == 0)53		return -EINVAL;54 55	err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->uid), &i_uid);56	if (err)57		return err;58 59	err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->guid), &i_gid);60	if (err)61		return err;62 63	i_uid_write(inode, i_uid);64	i_gid_write(inode, i_gid);65	inode_set_mtime(inode, le32_to_cpu(sqsh_ino->mtime), 0);66	inode_set_atime(inode, inode_get_mtime_sec(inode), 0);67	inode_set_ctime(inode, inode_get_mtime_sec(inode), 0);68	inode->i_mode = le16_to_cpu(sqsh_ino->mode);69	inode->i_size = 0;70 71	return err;72}73 74 75struct inode *squashfs_iget(struct super_block *sb, long long ino,76				unsigned int ino_number)77{78	struct inode *inode = iget_locked(sb, ino_number);79	int err;80 81	TRACE("Entered squashfs_iget\n");82 83	if (!inode)84		return ERR_PTR(-ENOMEM);85	if (!(inode->i_state & I_NEW))86		return inode;87 88	err = squashfs_read_inode(inode, ino);89	if (err) {90		iget_failed(inode);91		return ERR_PTR(err);92	}93 94	unlock_new_inode(inode);95	return inode;96}97 98 99/*100 * Initialise VFS inode by reading inode from inode table (compressed101 * metadata).  The format and amount of data read depends on type.102 */103int squashfs_read_inode(struct inode *inode, long long ino)104{105	struct super_block *sb = inode->i_sb;106	struct squashfs_sb_info *msblk = sb->s_fs_info;107	u64 block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;108	int err, type, offset = SQUASHFS_INODE_OFFSET(ino);109	union squashfs_inode squashfs_ino;110	struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base;111	int xattr_id = SQUASHFS_INVALID_XATTR;112 113	TRACE("Entered squashfs_read_inode\n");114 115	/*116	 * Read inode base common to all inode types.117	 */118	err = squashfs_read_metadata(sb, sqshb_ino, &block,119				&offset, sizeof(*sqshb_ino));120	if (err < 0)121		goto failed_read;122 123	err = squashfs_new_inode(sb, inode, sqshb_ino);124	if (err)125		goto failed_read;126 127	block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;128	offset = SQUASHFS_INODE_OFFSET(ino);129 130	type = le16_to_cpu(sqshb_ino->inode_type);131	switch (type) {132	case SQUASHFS_REG_TYPE: {133		unsigned int frag_offset, frag;134		int frag_size;135		u64 frag_blk;136		struct squashfs_reg_inode *sqsh_ino = &squashfs_ino.reg;137 138		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,139							sizeof(*sqsh_ino));140		if (err < 0)141			goto failed_read;142 143		frag = le32_to_cpu(sqsh_ino->fragment);144		if (frag != SQUASHFS_INVALID_FRAG) {145			frag_offset = le32_to_cpu(sqsh_ino->offset);146			frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);147			if (frag_size < 0) {148				err = frag_size;149				goto failed_read;150			}151		} else {152			frag_blk = SQUASHFS_INVALID_BLK;153			frag_size = 0;154			frag_offset = 0;155		}156 157		set_nlink(inode, 1);158		inode->i_size = le32_to_cpu(sqsh_ino->file_size);159		inode->i_fop = &generic_ro_fops;160		inode->i_mode |= S_IFREG;161		inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;162		squashfs_i(inode)->fragment_block = frag_blk;163		squashfs_i(inode)->fragment_size = frag_size;164		squashfs_i(inode)->fragment_offset = frag_offset;165		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);166		squashfs_i(inode)->block_list_start = block;167		squashfs_i(inode)->offset = offset;168		inode->i_data.a_ops = &squashfs_aops;169 170		TRACE("File inode %x:%x, start_block %llx, block_list_start "171			"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),172			offset, squashfs_i(inode)->start, block, offset);173		break;174	}175	case SQUASHFS_LREG_TYPE: {176		unsigned int frag_offset, frag;177		int frag_size;178		u64 frag_blk;179		struct squashfs_lreg_inode *sqsh_ino = &squashfs_ino.lreg;180 181		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,182							sizeof(*sqsh_ino));183		if (err < 0)184			goto failed_read;185 186		frag = le32_to_cpu(sqsh_ino->fragment);187		if (frag != SQUASHFS_INVALID_FRAG) {188			frag_offset = le32_to_cpu(sqsh_ino->offset);189			frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);190			if (frag_size < 0) {191				err = frag_size;192				goto failed_read;193			}194		} else {195			frag_blk = SQUASHFS_INVALID_BLK;196			frag_size = 0;197			frag_offset = 0;198		}199 200		xattr_id = le32_to_cpu(sqsh_ino->xattr);201		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));202		inode->i_size = le64_to_cpu(sqsh_ino->file_size);203		inode->i_op = &squashfs_inode_ops;204		inode->i_fop = &generic_ro_fops;205		inode->i_mode |= S_IFREG;206		inode->i_blocks = (inode->i_size -207				le64_to_cpu(sqsh_ino->sparse) + 511) >> 9;208 209		squashfs_i(inode)->fragment_block = frag_blk;210		squashfs_i(inode)->fragment_size = frag_size;211		squashfs_i(inode)->fragment_offset = frag_offset;212		squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block);213		squashfs_i(inode)->block_list_start = block;214		squashfs_i(inode)->offset = offset;215		inode->i_data.a_ops = &squashfs_aops;216 217		TRACE("File inode %x:%x, start_block %llx, block_list_start "218			"%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),219			offset, squashfs_i(inode)->start, block, offset);220		break;221	}222	case SQUASHFS_DIR_TYPE: {223		struct squashfs_dir_inode *sqsh_ino = &squashfs_ino.dir;224 225		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,226				sizeof(*sqsh_ino));227		if (err < 0)228			goto failed_read;229 230		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));231		inode->i_size = le16_to_cpu(sqsh_ino->file_size);232		inode->i_op = &squashfs_dir_inode_ops;233		inode->i_fop = &squashfs_dir_ops;234		inode->i_mode |= S_IFDIR;235		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);236		squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);237		squashfs_i(inode)->dir_idx_cnt = 0;238		squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);239 240		TRACE("Directory inode %x:%x, start_block %llx, offset %x\n",241				SQUASHFS_INODE_BLK(ino), offset,242				squashfs_i(inode)->start,243				le16_to_cpu(sqsh_ino->offset));244		break;245	}246	case SQUASHFS_LDIR_TYPE: {247		struct squashfs_ldir_inode *sqsh_ino = &squashfs_ino.ldir;248 249		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,250				sizeof(*sqsh_ino));251		if (err < 0)252			goto failed_read;253 254		xattr_id = le32_to_cpu(sqsh_ino->xattr);255		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));256		inode->i_size = le32_to_cpu(sqsh_ino->file_size);257		inode->i_op = &squashfs_dir_inode_ops;258		inode->i_fop = &squashfs_dir_ops;259		inode->i_mode |= S_IFDIR;260		squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);261		squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);262		squashfs_i(inode)->dir_idx_start = block;263		squashfs_i(inode)->dir_idx_offset = offset;264		squashfs_i(inode)->dir_idx_cnt = le16_to_cpu(sqsh_ino->i_count);265		squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);266 267		TRACE("Long directory inode %x:%x, start_block %llx, offset "268				"%x\n", SQUASHFS_INODE_BLK(ino), offset,269				squashfs_i(inode)->start,270				le16_to_cpu(sqsh_ino->offset));271		break;272	}273	case SQUASHFS_SYMLINK_TYPE:274	case SQUASHFS_LSYMLINK_TYPE: {275		struct squashfs_symlink_inode *sqsh_ino = &squashfs_ino.symlink;276 277		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,278				sizeof(*sqsh_ino));279		if (err < 0)280			goto failed_read;281 282		inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);283		if (inode->i_size > PAGE_SIZE) {284			ERROR("Corrupted symlink\n");285			return -EINVAL;286		}287 288		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));289		inode->i_op = &squashfs_symlink_inode_ops;290		inode_nohighmem(inode);291		inode->i_data.a_ops = &squashfs_symlink_aops;292		inode->i_mode |= S_IFLNK;293		squashfs_i(inode)->start = block;294		squashfs_i(inode)->offset = offset;295 296		if (type == SQUASHFS_LSYMLINK_TYPE) {297			__le32 xattr;298 299			err = squashfs_read_metadata(sb, NULL, &block,300						&offset, inode->i_size);301			if (err < 0)302				goto failed_read;303			err = squashfs_read_metadata(sb, &xattr, &block,304						&offset, sizeof(xattr));305			if (err < 0)306				goto failed_read;307			xattr_id = le32_to_cpu(xattr);308		}309 310		TRACE("Symbolic link inode %x:%x, start_block %llx, offset "311				"%x\n", SQUASHFS_INODE_BLK(ino), offset,312				block, offset);313		break;314	}315	case SQUASHFS_BLKDEV_TYPE:316	case SQUASHFS_CHRDEV_TYPE: {317		struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev;318		unsigned int rdev;319 320		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,321				sizeof(*sqsh_ino));322		if (err < 0)323			goto failed_read;324 325		if (type == SQUASHFS_CHRDEV_TYPE)326			inode->i_mode |= S_IFCHR;327		else328			inode->i_mode |= S_IFBLK;329		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));330		rdev = le32_to_cpu(sqsh_ino->rdev);331		init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));332 333		TRACE("Device inode %x:%x, rdev %x\n",334				SQUASHFS_INODE_BLK(ino), offset, rdev);335		break;336	}337	case SQUASHFS_LBLKDEV_TYPE:338	case SQUASHFS_LCHRDEV_TYPE: {339		struct squashfs_ldev_inode *sqsh_ino = &squashfs_ino.ldev;340		unsigned int rdev;341 342		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,343				sizeof(*sqsh_ino));344		if (err < 0)345			goto failed_read;346 347		if (type == SQUASHFS_LCHRDEV_TYPE)348			inode->i_mode |= S_IFCHR;349		else350			inode->i_mode |= S_IFBLK;351		xattr_id = le32_to_cpu(sqsh_ino->xattr);352		inode->i_op = &squashfs_inode_ops;353		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));354		rdev = le32_to_cpu(sqsh_ino->rdev);355		init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));356 357		TRACE("Device inode %x:%x, rdev %x\n",358				SQUASHFS_INODE_BLK(ino), offset, rdev);359		break;360	}361	case SQUASHFS_FIFO_TYPE:362	case SQUASHFS_SOCKET_TYPE: {363		struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc;364 365		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,366				sizeof(*sqsh_ino));367		if (err < 0)368			goto failed_read;369 370		if (type == SQUASHFS_FIFO_TYPE)371			inode->i_mode |= S_IFIFO;372		else373			inode->i_mode |= S_IFSOCK;374		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));375		init_special_inode(inode, inode->i_mode, 0);376		break;377	}378	case SQUASHFS_LFIFO_TYPE:379	case SQUASHFS_LSOCKET_TYPE: {380		struct squashfs_lipc_inode *sqsh_ino = &squashfs_ino.lipc;381 382		err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,383				sizeof(*sqsh_ino));384		if (err < 0)385			goto failed_read;386 387		if (type == SQUASHFS_LFIFO_TYPE)388			inode->i_mode |= S_IFIFO;389		else390			inode->i_mode |= S_IFSOCK;391		xattr_id = le32_to_cpu(sqsh_ino->xattr);392		inode->i_op = &squashfs_inode_ops;393		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));394		init_special_inode(inode, inode->i_mode, 0);395		break;396	}397	default:398		ERROR("Unknown inode type %d in squashfs_iget!\n", type);399		return -EINVAL;400	}401 402	if (xattr_id != SQUASHFS_INVALID_XATTR && msblk->xattr_id_table) {403		err = squashfs_xattr_lookup(sb, xattr_id,404					&squashfs_i(inode)->xattr_count,405					&squashfs_i(inode)->xattr_size,406					&squashfs_i(inode)->xattr);407		if (err < 0)408			goto failed_read;409		inode->i_blocks += ((squashfs_i(inode)->xattr_size - 1) >> 9)410				+ 1;411	} else412		squashfs_i(inode)->xattr_count = 0;413 414	return 0;415 416failed_read:417	ERROR("Unable to read inode 0x%llx\n", ino);418	return err;419}420 421 422const struct inode_operations squashfs_inode_ops = {423	.listxattr = squashfs_listxattr424};425 426